== Action Editor ==
authorJoshua Leung <aligorith@gmail.com>
Wed, 15 Nov 2006 10:41:28 +0000 (10:41 +0000)
committerJoshua Leung <aligorith@gmail.com>
Wed, 15 Nov 2006 10:41:28 +0000 (10:41 +0000)
A Plumiferos wishlist item: Markers working in the Action Editor too.

* The user can choose between displaying the scene markers (i.e. the
markers shown in the timeline) or the markers specific to each action,
by using the next list box on the action editor header. This is specific
to each instance of the action editor.

* The display of the markers currently still needs improvement. At the
moment, the triangle icons + text are drawn below all the last row of
keyframes. As such, I've made it draw yellow vertical lines which
span the height of the action editor, to also indicate markers.
Comments on this and also help getting the triangle thingies to 'float'
above the bottom scroll bar are warmly appreciated.

* There are a few minor update issues with editing a marker in the
timeline and the markers in the action editor which will be fixed soon.

* There are also a few hotkeys to still add.

Enjoy!

source/blender/blenkernel/intern/action.c
source/blender/blenloader/intern/writefile.c
source/blender/include/BIF_editaction.h
source/blender/makesdna/DNA_action_types.h
source/blender/src/drawaction.c
source/blender/src/editaction.c
source/blender/src/edittime.c
source/blender/src/header_action.c

index 9f42e682e82bab77e34643715df6ea723bd15eea..3ee6b89804c097702e84760452dd7a3939143976 100644 (file)
@@ -176,6 +176,10 @@ void free_action(bAction *act)
                free_constraint_channels(&chan->constraintChannels);
        }
        
+       /* Free markers */
+       if (act->markers.first)
+               BLI_freelistN (&act->markers);
+       
        if (act->chanbase.first)
                BLI_freelistN (&act->chanbase);
 }
@@ -189,6 +193,7 @@ bAction* copy_action(bAction *src)
        
        dst= copy_libblock(src);
        duplicatelist(&(dst->chanbase), &(src->chanbase));
+       duplicatelist(&(dst->markers), &(src->markers));
        
        for (dchan=dst->chanbase.first, schan=src->chanbase.first; dchan; dchan=dchan->next, schan=schan->next){
                dchan->ipo = copy_ipo(dchan->ipo);
index 2ee553824ef3669fa85e58ef056d190ffa81358f..2b2ba9f77bdfe5c8212e2c93bb7de968f9a715cf 100644 (file)
@@ -1551,6 +1551,7 @@ static void write_actions(WriteData *wd, ListBase *idbase)
 {
        bAction                 *act;
        bActionChannel  *chan;
+       TimeMarker              *marker;
        
        for(act=idbase->first; act; act= act->id.next) {
                if (act->id.us>0 || wd->current) {
@@ -1560,6 +1561,10 @@ static void write_actions(WriteData *wd, ListBase *idbase)
                                writestruct(wd, DATA, "bActionChannel", 1, chan);
                                write_constraint_channels(wd, &chan->constraintChannels);
                        }
+                       
+                       /* writing dynamic list of TimeMarkers to the blend file */
+                       for(marker= act->markers.first; marker; marker= marker->next)
+                               writestruct(wd, DATA, "TimeMarker", 1, marker);
                }
        }
 }
index 4645cb415e83a5caa9c3934dc453d898b1668d9c..6ccec20181dc048e0ca1bd3a47ac822dc285e36d 100644 (file)
@@ -67,6 +67,7 @@ struct Object;
 struct Ipo;
 struct BWinEvent;
 struct Key;
+struct ListBase;
 
 /* Key operations */
 void delete_meshchannel_keys(struct Key *key);
@@ -81,6 +82,18 @@ void snap_keys_to_frame(void);
 void clean_shapekeys(struct Key *key);
 void clean_actionchannels(struct bAction *act);
 
+/* Marker Operations */
+struct ListBase *get_saction_markers(struct SpaceAction *saction);
+void add_saction_marker(struct ListBase *markers, int frame);
+void duplicate_saction_markers(struct ListBase *markers);
+void remove_saction_markers(struct ListBase *markers);
+void rename_saction_markers(struct ListBase *markers);
+void transform_saction_markers(int mode, int smode);
+void deselect_saction_markers(struct ListBase *markers, int test);
+void borderselect_saction_markers(struct ListBase *markers, float xmin, float xmax, int selectmode);
+struct TimeMarker *find_nearest_saction_marker(struct ListBase *markers);
+
+
 /* channel/strip operations */
 void up_sel_action(void);
 void down_sel_action(void);
@@ -99,12 +112,14 @@ void set_extendtype_actionchannels(int extendtype);
 /* Select */
 void borderselect_mesh(struct Key *key);
 void borderselect_action(void);
+void borderselect_markers(struct ListBase *markers);
 void deselect_actionchannel_keys(struct bAction *act, int test);
 void deselect_actionchannels (struct bAction *act, int test);
 void deselect_meshchannel_keys (struct Key *key, int test);
 int select_channel(struct bAction *act, struct bActionChannel *chan, int selectmode);
 void select_actionchannel_by_name (struct bAction *act, char *name, int select);
 
+
 /* Action */
 struct bActionChannel* get_hilighted_action_channel(struct bAction* action);
 struct bAction *add_empty_action(int blocktype);
index d27dc391f24582353306398446eb677227592710..d9db6e0c8894063023e678d06e50a55a76434098 100644 (file)
@@ -100,7 +100,8 @@ typedef struct bActionChannel {
 
 typedef struct bAction {
        ID                              id;
-       ListBase                chanbase;       /* Channels in this action */
+       ListBase                chanbase;       /* Action Channels in this action */
+       ListBase                markers;        /* Markers specific to this action */
 } bAction;
 
 typedef struct SpaceAction {
@@ -114,7 +115,7 @@ typedef struct SpaceAction {
        View2D v2d;     
        bAction         *action;
        int     flag;
-       short pin, actnr, lock, pad;
+       short pin, actnr, lock, markert;
        float timeslide;
 } SpaceAction;
 
@@ -125,7 +126,13 @@ typedef struct SpaceAction {
 #define ACHAN_MOVED     0x80000000
 
 /* SpaceAction flag */
-#define SACTION_MOVING 1
+#define SACTION_MOVING         1       /* during transform */
+#define SACTION_SLIDERS                2       /* show sliders (if relevant) - limited to shape keys for now */
+
+/* SpaceAction Marker Type */
+#define SACTION_NOMARKERS      0       /* no markers */
+#define SACTION_SCMARKERS      1       /* markers for current scene */
+#define SACTION_ACMARKERS      2       /* markers from current action */
 
 /* Pose->flag */
 #define POSE_RECALC            1
index e628b9ca672c933f99986569be1668a66adefc6d..de36b02ec988d1fce14677fbaeeb6875ad6ae4c0 100644 (file)
@@ -215,6 +215,92 @@ void draw_cfra_action(void)
        glLineWidth(1.0);
 }
 
+/* Aligorith: for now, just draw them as lines (for debugging) */
+static void draw_marker(TimeMarker *marker)
+{
+       float xpos, xspace, yspace, xpixels, ypixels;
+       float vec[2];
+       
+       
+       xpos = marker->frame;
+       /* no time correction for framelen! space is drawn with old values */
+       
+       xspace= G.v2d->cur.xmax - G.v2d->cur.xmin;
+       yspace= G.v2d->cur.ymax - G.v2d->cur.ymin;
+       xpixels= G.v2d->mask.xmax-G.v2d->mask.xmin;
+       ypixels= G.v2d->mask.ymax-G.v2d->mask.ymin;
+
+       glEnable(GL_BLEND);
+       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);      
+
+       /* draw line through this point */
+       vec[0]= G.scene->r.framelen * xpos;
+       
+       vec[1]= G.v2d->cur.ymin;
+       if (marker->flag & SELECT)
+               glColor3ub(0xFF, 0xFF, 0x99);
+       else
+               glColor3ub(0xAA, 0xAA, 0x55);
+       glLineWidth(2.0);
+       
+       glBegin(GL_LINE_STRIP);
+       glVertex2fv(vec);
+       vec[1]= G.v2d->cur.ymax;
+       glVertex2fv(vec);
+       glEnd();
+       
+       
+       /* 5 px to offset icon to align properly, space / pixels corrects for zoom */
+       if(marker->flag & SELECT)
+               BIF_icon_draw(xpos-(5.0*(xspace/xpixels)), (12.0*yspace/ypixels)-CHANNELHEIGHT, ICON_MARKER_HLT);
+       else
+               BIF_icon_draw(xpos-(5.0*(xspace/xpixels)), (12.0*yspace/ypixels)-CHANNELHEIGHT, ICON_MARKER);
+       
+       glBlendFunc(GL_ONE, GL_ZERO);
+       glDisable(GL_BLEND);            
+
+       /* and the marker name too, shifted slightly to the top-right */
+       if(marker->name && marker->name[0]) {
+               if(marker->flag & SELECT) {
+                       BIF_ThemeColor(TH_TEXT_HI);
+                       glRasterPos2f(xpos+(4.0*(xspace/xpixels)),
+                                       ((ypixels<=39.0)?(ypixels-10.0):29.0)*yspace/ypixels);
+               }
+               else {
+                       BIF_ThemeColor(TH_TEXT);
+                       if((marker->frame <= G.scene->r.cfra) && (marker->frame+5 > G.scene->r.cfra))
+                               glRasterPos2f(xpos+(4.0*(xspace/xpixels)),
+                                               ((ypixels<=39.0)?(ypixels-10.0):29.0)*yspace/ypixels);
+                       else
+                               glRasterPos2f(xpos+(4.0*(xspace/xpixels)), 17.0*yspace/ypixels);
+               }
+               BMF_DrawString(G.font, marker->name);
+       }
+}
+
+static void draw_markers_action(SpaceAction *saction)
+{
+       ListBase *markers;
+       TimeMarker *marker;
+       
+       /* try to get markers */
+       markers = get_saction_markers(saction);
+       if (markers == NULL)
+               return;
+               
+       /* unselected markers are drawn at the first time */
+       for(marker= markers->first; marker; marker= marker->next) {
+               if(!(marker->flag & SELECT)) draw_marker(marker);
+       }
+
+       /* selected markers are drawn later ... selected markers have to cover unselected
+        * markers laying at the same position as selected markers
+        * (jiri: it is hack, it could be solved better) */
+       for(marker= markers->first; marker; marker= marker->next) {
+               if(marker->flag & SELECT) draw_marker(marker);
+       }
+}
+
 /* left hand */
 static void draw_action_channel_names(bAction  *act) 
 {
@@ -682,7 +768,7 @@ void drawactionspace(ScrArea *sa, void *spacedata)
                 */
                draw_mesh_strips(G.saction, key);
        }
-
+       
        /* Draw current frame */
        glViewport(ofsx+G.v2d->mask.xmin,  
              ofsy+G.v2d->mask.ymin, 
@@ -694,6 +780,9 @@ void drawactionspace(ScrArea *sa, void *spacedata)
             ( ofsy+G.v2d->mask.ymax-1)-( ofsy+G.v2d->mask.ymin)+1);
        myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax,  G.v2d->cur.ymin, G.v2d->cur.ymax);
        draw_cfra_action();
+       
+       /* Draw markers */
+       draw_markers_action(G.saction);
 
        /* Draw scroll */
        mywinset(curarea->win); // reset scissor too
index 14d65d5bf7d59fda3c82cf0ffc7caea37b58b8e8..4af44f796b7aa4e3e03f97a4bd85461c66aafa15 100644 (file)
@@ -135,101 +135,6 @@ static void select_poseelement_by_name (char *name, int select)
        }
 }
 
-bAction* bake_action_with_client (bAction *act, Object *armob, float tolerance)
-{
-       bArmature               *arm;
-       bAction                 *result=NULL;
-       bActionChannel *achan;
-       bAction                 *temp;
-       bPoseChannel    *pchan;
-       ID                              *id;
-       float                   actstart, actend;
-       int                             oldframe;
-       int                             curframe;
-       char                    newname[64];
-
-       if (!act)
-               return NULL;
-       
-       arm = get_armature(armob);
-
-       if (G.obedit){
-               error ("Actions can't be baked in Edit Mode");
-               return NULL;
-       }
-
-       if (!arm || armob->pose==NULL){
-               error ("Select an armature before baking");
-               return NULL;
-       }
-       
-       /* Get a new action */
-       result = add_empty_action(ID_PO);
-       id= (ID *)armob;
-
-       /* Assign the new action a unique name */
-       sprintf (newname, "%s.BAKED", act->id.name+2);
-       rename_id(&result->id, newname);
-
-       calc_action_range(act, &actstart, &actend, 1);
-
-       oldframe = G.scene->r.cfra;
-
-       temp = armob->action;
-       armob->action = result;
-       
-       for (curframe=1; curframe<ceil(actend+1.0f); curframe++){
-
-               /* Apply the old action */
-               
-               G.scene->r.cfra = curframe;
-
-               /* Apply the object ipo */
-               extract_pose_from_action(armob->pose, act, curframe);
-
-               where_is_pose(armob);
-               
-               /* For each channel: set quats and locs if channel is a bone */
-               for (pchan=armob->pose->chanbase.first; pchan; pchan=pchan->next){
-
-                       /* Apply to keys */
-                       insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_X);
-                       insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Y);
-                       insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Z);
-                       insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_X);
-                       insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Y);
-                       insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Z);
-                       insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_W);
-                       insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_X);
-                       insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_Y);
-                       insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_Z);
-               }
-       }
-
-
-       /* Make another pass to ensure all keyframes are set to linear interpolation mode */
-       for (achan = result->chanbase.first; achan; achan=achan->next){
-               IpoCurve* icu;
-               if(achan->ipo) {
-                       for (icu = achan->ipo->curve.first; icu; icu=icu->next){
-                               icu->ipo= IPO_LIN;
-                       }
-               }
-       }
-
-       notice ("Made a new action named \"%s\"", newname);
-       G.scene->r.cfra = oldframe;
-       armob->action = temp;
-               
-       /* restore */
-       extract_pose_from_action(armob->pose, act, G.scene->r.cfra);
-       where_is_pose(armob);
-       
-       allqueue(REDRAWACTION, 1);
-       
-       return result;
-}
-
 /* apparently within active object context */
 /* called extern, like on bone selection */
 void select_actionchannel_by_name (bAction *act, char *name, int select)
@@ -697,16 +602,20 @@ static void mouse_action(int selectmode)
        float   selx;
        bActionChannel *chan;
        bConstraintChannel *conchan;
+       TimeMarker *marker;
+       ListBase *markers;
        short   mval[2];
 
        act=G.saction->action;
        if (!act)
                return;
+       markers= get_saction_markers(G.saction);
 
        getmouseco_areawin (mval);
 
        chan=get_nearest_actionchannel_key(&selx, &sel, &conchan);
-
+       marker=find_nearest_saction_marker(markers);
+       
        if (chan){
                if (selectmode == SELECT_REPLACE) {
                        selectmode = SELECT_ADD;
@@ -734,6 +643,20 @@ static void mouse_action(int selectmode)
                allqueue(REDRAWOOPS, 0);
                allqueue(REDRAWBUTSALL, 0);
        }
+       else if (marker != NULL) {
+               /* not channel, so maybe marker */              
+               if (selectmode == SELECT_REPLACE) {
+                       selectmode = SELECT_ADD;
+                       
+                       deselect_saction_markers(markers, 0);
+                       marker->flag |= SELECT;
+               }
+               
+               std_rmouse_transform(transform_saction_markers);
+               
+               allqueue(REDRAWACTION, 0);
+               allqueue(REDRAWTIME, 0);
+       }
 }
 
 static void mouse_mesh_action(int selectmode, Key *key)
@@ -743,6 +666,8 @@ static void mouse_mesh_action(int selectmode, Key *key)
         */
 
     IpoCurve *icu;
+       TimeMarker *marker;
+       ListBase *markers;
     short  sel;
     float  selx;
     short  mval[2];
@@ -754,6 +679,9 @@ static void mouse_mesh_action(int selectmode, Key *key)
      * data, etc)
      */
 
+       markers= get_saction_markers(G.saction);
+       marker= find_nearest_saction_marker(markers);
+        
        /* get the click location, and the cooresponding
         * ipo curve and selection time value
         */
@@ -803,12 +731,15 @@ void borderselect_action(void)
        bActionChannel *chan;
        bConstraintChannel *conchan;
        bAction *act;
+       ListBase *markers;
        float   ymin, ymax;
 
        act=G.saction->action;
 
        if (!act)
                return;
+               
+       markers = get_saction_markers(G.saction);
 
        if ( (val = get_border(&rect, 3)) ){
                if (val == LEFTMOUSE)
@@ -822,7 +753,7 @@ void borderselect_action(void)
                mval[0]= rect.xmax;
                mval[1]= rect.ymax-2;
                areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
-               
+                       
                /* if action is mapped in NLA, it returns a correction */
                if(G.saction->pin==0 && OBACT) {
                        rectf.xmin= get_action_frame(OBACT, rectf.xmin);
@@ -854,31 +785,46 @@ void borderselect_action(void)
                                }
                        }
                }       
+               
+               /* do markers first */
+               if (markers != NULL)
+                       borderselect_saction_markers(markers, rectf.xmin, rectf.xmax, selectmode);
+               
+               
                BIF_undo_push("Border Select Action");
                allqueue(REDRAWNLA, 0);
                allqueue(REDRAWACTION, 0);
                allqueue(REDRAWIPO, 0);
+               if (markers != NULL) allqueue(REDRAWTIME, 0);
        }
 }
 
 void borderselect_mesh(Key *key)
 { 
+       ListBase *markers;
        rcti     rect;
        int      val, adrcodemax, adrcodemin;
        short    mval[2];
        float    xmin, xmax;
+       int      selectmode;
        int      (*select_function)(BezTriple *);
        IpoCurve *icu;
 
+       markers = get_saction_markers(G.saction);
+               
        if ( (val = get_border(&rect, 3)) ){
                /* set the selection function based on what
                 * mouse button had been used in the border
                 * select
                 */
-               if (val == LEFTMOUSE)
+               if (val == LEFTMOUSE) {
+                       selectmode = SELECT_ADD;
                        select_function = select_bezier_add;
-               else
+               }
+               else {
+                       selectmode = SELECT_SUBTRACT;
                        select_function = select_bezier_subtract;
+               }
 
                /* get the minimum and maximum adrcode numbers
                 * for the IpoCurves (this is the number that
@@ -909,11 +855,17 @@ void borderselect_mesh(Key *key)
                                }
                        }
                }
+               
+               /* do markers too if any */
+               if (markers != NULL) 
+                       borderselect_saction_markers(markers, xmin, xmax, selectmode);
+               
                /* redraw stuff */
                BIF_undo_push("Border select Action Key");
                allqueue(REDRAWNLA, 0);
                allqueue(REDRAWACTION, 0);
                allqueue(REDRAWIPO, 0);
+               if (markers != NULL) allqueue(REDRAWTIME, 0);
        }
 }
 
@@ -2453,6 +2405,7 @@ void winqreadactionspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
        extern void do_actionbuts(unsigned short event); // drawaction.c
        SpaceAction *saction;
        bAction *act;
+       ListBase *markers;
        Key *key;
        float dx,dy;
        int doredraw= 0;
@@ -2467,6 +2420,8 @@ void winqreadactionspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
        saction= curarea->spacedata.first;
        if (!saction)
                return;
+               
+       markers = get_saction_markers(saction);
 
        act=saction->action;
        if(val) {
@@ -2635,6 +2590,27 @@ void winqreadactionspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                        allqueue(REDRAWNLA, 0);
                        break;
                        
+               case MKEY:
+                       /* marker operations */
+                       if (G.qual == 0)
+                               add_saction_marker(markers, CFRA);
+                       else if (G.qual == LR_ALTKEY) {
+                               if( okee("Erase selected markers")==0 ) 
+                                       break;
+                               remove_saction_markers(markers);
+                       }
+                       else if (G.qual == LR_CTRLKEY)
+                               rename_saction_markers(markers);
+                       else if (G.qual == LR_SHIFTKEY)
+                               transform_saction_markers('g', 0);
+                       else if (G.qual == (LR_CTRLKEY|LR_SHIFTKEY))
+                               duplicate_saction_markers(markers);
+                       else 
+                               break;
+                       allqueue(REDRAWACTION, 0);
+                       allqueue(REDRAWTIME, 0);
+                       break;
+                       
                case NKEY:
                        if(G.qual==0) {
                                numbuts_action();
@@ -2890,7 +2866,256 @@ int get_nearest_key_num(Key *key, short *mval, float *x) {
     return (num + 1);
 }
 
+/* ************************************* Action Editor Markers ************************************* */
+
+/* returns the current active markers */
+ListBase *get_saction_markers (SpaceAction *saction)
+{
+       ListBase *markers;
+       
+       if (saction->markert == SACTION_SCMARKERS) 
+               markers = &(G.scene->markers);
+       else if ((saction->markert == SACTION_ACMARKERS) && (saction->action != NULL))
+               markers = &(saction->action->markers);
+       else
+               markers = NULL;
+               
+       return markers;
+}
+
+/* add a TimeMarker - code basically taken from edittime.c */
+void add_saction_marker (ListBase *markers, int frame)
+{
+       TimeMarker *marker;
+       
+       /* two markers can't be at the same place */
+       for(marker= markers->first; marker; marker= marker->next)
+               if(marker->frame == frame) return;
+       /* deselect all */
+       for(marker= markers->first; marker; marker= marker->next)
+               marker->flag &= ~SELECT;
+               
+       marker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
+       marker->flag= SELECT;
+       marker->frame= frame;
+       BLI_addtail(markers, marker);
+       
+       BIF_undo_push("Add Marker");
+}
+
+/* remove a TimeMarker - code basically taken from edittime.c */
+void remove_saction_markers(ListBase *markers)
+{
+       TimeMarker *marker;
+       
+       for(marker= markers->first; marker; marker= marker->next) {
+               if(marker->flag & SELECT){
+                       BLI_freelinkN(markers, marker);
+               }
+       }
+       
+       BIF_undo_push("Remove Marker");
+}
+
+/* rename a TimeMarker - code basically taken from edittime.c */
+void rename_saction_markers(ListBase *markers)
+{
+       TimeMarker *marker;
+       char name[64];
+       
+       for(marker= markers->first; marker; marker= marker->next) {
+               if(marker->flag & SELECT) {
+                       sprintf(name, marker->name);
+                       if (sbutton(name, 0, sizeof(name)-1, "Name: "))
+                               BLI_strncpy(marker->name, name, sizeof(marker->name));
+                       break;
+               }
+       }
+       
+       BIF_undo_push("Rename Marker");
+}
+
+/* duplicate selected TimeMarkers - code basically taken from edittime.c */
+void duplicate_saction_markers(ListBase *markers)
+{
+       TimeMarker *marker, *newmarker;
+
+       /* go through the list of markers, duplicate selected markers and add duplicated copies
+        * to the begining of the list (unselect original markers) */
+       for(marker= markers->first; marker; marker= marker->next) {
+               if(marker->flag & SELECT){
+                       /* unselect selected marker */
+                       marker->flag &= ~SELECT;
+                       /* create and set up new marker */
+                       newmarker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
+                       newmarker->flag= SELECT;
+                       newmarker->frame= marker->frame;
+                       BLI_strncpy(newmarker->name, marker->name, sizeof(marker->name));
+                       /* new marker is added to the begining of list */
+                       BLI_addhead(markers, newmarker);
+               }
+       }
+       
+       transform_saction_markers('g', 0);
+}
+
+void transform_saction_markers(int mode, int smode)    // mode and smode unused here, for callback
+{
+       SpaceAction *saction= curarea->spacedata.first;
+       TimeMarker *marker, *selmarker=NULL;
+       ListBase *markers;
+       float dx, fac;
+       int a, ret_val= 0, totmark=0, *oldframe, offs, firsttime=1;
+       unsigned short event;
+       short val, pmval[2], mval[2], mvalo[2];
+       char str[32];
+       
+       markers= get_saction_markers(saction);
+       if (markers == NULL) return;
+       
+       for(marker= markers->first; marker; marker= marker->next) {
+               if(marker->flag & SELECT) totmark++;
+       }
+       if(totmark==0) return;
+       
+       oldframe= MEM_mallocN(totmark*sizeof(int), "marker array");
+       for(a=0, marker= markers->first; marker; marker= marker->next) {
+               if(marker->flag & SELECT) {
+                       oldframe[a]= marker->frame;
+                       selmarker= marker;      // used for hederprint
+                       a++;
+               }
+       }
+       
+       dx= G.v2d->mask.xmax-G.v2d->mask.xmin;
+       dx= (G.v2d->cur.xmax-G.v2d->cur.xmin)/dx;
+       
+       getmouseco_areawin(pmval);
+       mvalo[0]= pmval[0];
+       
+       while(ret_val == 0) {
+               
+               getmouseco_areawin(mval);
+               
+               if (mval[0] != mvalo[0] || firsttime) {
+                       mvalo[0]= mval[0];
+                       firsttime= 0;
+                       
+                       fac= (((float)(mval[0] - pmval[0]))*dx);
+                       
+                       apply_keyb_grid(&fac, 0.0, 1.0, 0.1, U.flag & USER_AUTOGRABGRID);
+                       offs= (int)fac;
+                       
+                       for(a=0, marker= markers->first; marker; marker= marker->next) {
+                               if(marker->flag & SELECT) {
+                                       marker->frame= oldframe[a] + offs;
+                                       a++;
+                               }
+                       }
+                       
+                       if(totmark==1)  // we print current marker value
+                               sprintf(str, "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
+                       else 
+                               sprintf(str, "Marker offset %.2f ", (double)(offs));
+                       
+                       headerprint(str);
+                       
+                       force_draw(0);  // areas identical to this, 0 = no header
+               }
+               else PIL_sleep_ms(10);  // idle
+               
+               /* emptying queue and reading events */
+               while( qtest() ) {
+                       event= extern_qread(&val);
+                       
+                       if(val) {
+                               if(event==ESCKEY || event==RIGHTMOUSE) ret_val= 2;
+                               else if(event==LEFTMOUSE || event==RETKEY || event==SPACEKEY) ret_val= 1;
+                       }
+               }
+       }
+       
+       /* restore? */
+       if(ret_val==2) {
+               for(a=0, marker= markers->first; marker; marker= marker->next) {
+                       if(marker->flag & SELECT) {
+                               marker->frame= oldframe[a];
+                               a++;
+                       }
+               }
+       }
+       else {
+               BIF_undo_push("Move Markers");
+       }
+       MEM_freeN(oldframe);
+       allqueue(REDRAWACTION, 0);
+       allqueue(REDRAWTIME, 0);
+}
+
+TimeMarker *find_nearest_saction_marker(ListBase *markers)
+{
+       TimeMarker *marker;
+       float xmin, xmax;
+       rctf    rectf;
+       short mval[2];
+       
+       getmouseco_areawin (mval);
 
+       mval[0]-=7;
+       areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
+       mval[0]+=14;
+       areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
+       
+       xmin= rectf.xmin;
+       xmax= rectf.xmax;
+       
+       for(marker= markers->first; marker; marker= marker->next) {
+               if ((marker->frame > xmin) && (marker->frame <= xmax)) {
+                       return marker;
+               }
+       }
+       
+       return NULL;
+}
+
+/* select/deselect all TimeMarkers */
+void deselect_saction_markers(ListBase *markers, int test)
+{
+       TimeMarker *marker;
+       
+       for (marker = markers->first; marker; marker= marker->next) {
+                       if (test) {
+                               if ((marker->flag & SELECT)==0)
+                                       marker->flag |= SELECT;
+                       }
+                       else {
+                               if (marker->flag & SELECT)
+                                       marker->flag &= ~SELECT;
+                       }
+       }
+}
+
+void borderselect_saction_markers(ListBase *markers, float xmin, float xmax, int selectmode)
+{
+       TimeMarker *marker;
+       
+       for(marker= markers->first; marker; marker= marker->next) {
+               if ((marker->frame > xmin) && (marker->frame <= xmax)) {
+                       switch (selectmode) {
+                               case SELECT_ADD:
+                                       if ((marker->flag & SELECT) == 0) 
+                                               marker->flag |= SELECT;
+                                       break;
+                               case SELECT_SUBTRACT:
+                                       if (marker->flag & SELECT) 
+                                               marker->flag &= ~SELECT;
+                                       break;
+                       }
+               }
+       }
+}
+
+/* ************************************* Action Channel Ordering *********************************** */
 
 void top_sel_action()
 {
@@ -3051,6 +3276,9 @@ void bottom_sel_action()
        allqueue(REDRAWNLA, 0);
 }
 
+/* ********************************* BAKING STUFF ********************************** */
+/* NOTE: these functions should probably be moved to their own file sometime - Aligorith */
+
 void world2bonespace(float boneSpaceMat[][4], float worldSpace[][4], float restPos[][4], float armPos[][4])
 {
        float imatarm[4][4], imatbone[4][4], tmat[4][4], t2mat[4][4];
@@ -3062,6 +3290,101 @@ void world2bonespace(float boneSpaceMat[][4], float worldSpace[][4], float restP
        Mat4MulMat4(boneSpaceMat, restPos, t2mat);
 }
 
+bAction* bake_action_with_client (bAction *act, Object *armob, float tolerance)
+{
+       bArmature               *arm;
+       bAction                 *result=NULL;
+       bActionChannel *achan;
+       bAction                 *temp;
+       bPoseChannel    *pchan;
+       ID                              *id;
+       float                   actstart, actend;
+       int                             oldframe;
+       int                             curframe;
+       char                    newname[64];
+
+       if (!act)
+               return NULL;
+       
+       arm = get_armature(armob);
+
+       if (G.obedit){
+               error ("Actions can't be baked in Edit Mode");
+               return NULL;
+       }
+
+       if (!arm || armob->pose==NULL){
+               error ("Select an armature before baking");
+               return NULL;
+       }
+       
+       /* Get a new action */
+       result = add_empty_action(ID_PO);
+       id= (ID *)armob;
+
+       /* Assign the new action a unique name */
+       sprintf (newname, "%s.BAKED", act->id.name+2);
+       rename_id(&result->id, newname);
+
+       calc_action_range(act, &actstart, &actend, 1);
+
+       oldframe = G.scene->r.cfra;
+
+       temp = armob->action;
+       armob->action = result;
+       
+       for (curframe=1; curframe<ceil(actend+1.0f); curframe++){
+
+               /* Apply the old action */
+               
+               G.scene->r.cfra = curframe;
+
+               /* Apply the object ipo */
+               extract_pose_from_action(armob->pose, act, curframe);
+
+               where_is_pose(armob);
+               
+               /* For each channel: set quats and locs if channel is a bone */
+               for (pchan=armob->pose->chanbase.first; pchan; pchan=pchan->next){
+
+                       /* Apply to keys */
+                       insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_X);
+                       insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Y);
+                       insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Z);
+                       insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_X);
+                       insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Y);
+                       insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Z);
+                       insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_W);
+                       insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_X);
+                       insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_Y);
+                       insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_Z);
+               }
+       }
+
+
+       /* Make another pass to ensure all keyframes are set to linear interpolation mode */
+       for (achan = result->chanbase.first; achan; achan=achan->next){
+               IpoCurve* icu;
+               if(achan->ipo) {
+                       for (icu = achan->ipo->curve.first; icu; icu=icu->next){
+                               icu->ipo= IPO_LIN;
+                       }
+               }
+       }
+
+       notice ("Made a new action named \"%s\"", newname);
+       G.scene->r.cfra = oldframe;
+       armob->action = temp;
+               
+       /* restore */
+       extract_pose_from_action(armob->pose, act, G.scene->r.cfra);
+       where_is_pose(armob);
+       
+       allqueue(REDRAWACTION, 1);
+       
+       return result;
+}
+
 
 bAction* bake_obIPO_to_action (Object *ob)
 {
index 266d7bda139a3d217f5eea1ab7bd3c2923a4bab7..919508aec0d2ec8a712ebb445d91cb8b7bc0cb08 100644 (file)
@@ -452,6 +452,7 @@ void timeline_grab(int mode, int smode)     // mode and smode unused here, for callb
        }
        MEM_freeN(oldframe);
        allqueue(REDRAWTIME, 0);
+       allqueue(REDRAWACTION, 0);
 }
 
 /* copy of this is actually in editscreen.c, but event based */
@@ -642,6 +643,7 @@ void winqreadtimespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                        else
                                add_timeline_marker(CFRA);
                        allqueue(REDRAWTIME, 0);
+                       allqueue(REDRAWACTION, 0);
                        break;
                case SKEY: /* set start frame */
                        G.scene->r.sfra = CFRA;
@@ -662,6 +664,7 @@ void winqreadtimespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
 
                        remove_timeline_marker();
                        allqueue(REDRAWTIME, 0);
+                       allqueue(REDRAWACTION, 0);
                        break;
                }
        }
index de4cafbe3ec1ed279efeb1cd4c7acf1e34e1d034..0bb18014b4eee7e5dd542674178e29703ccb2b60 100644 (file)
@@ -83,6 +83,7 @@
 #define ACTMENU_VIEW_ALL        4
 #define ACTMENU_VIEW_MAXIMIZE   5
 #define ACTMENU_VIEW_LOCK              6
+#define ACTMENU_VIEW_SLIDERS   7
 
 #define ACTMENU_SEL_BORDER      0
 #define ACTMENU_SEL_ALL_KEYS    1
 #define ACTMENU_KEY_EXTEND_CYCLIC 2
 #define ACTMENU_KEY_EXTEND_CYCLICEXTRAPOLATION 3
 
+#define ACTMENU_MARKERS_ADD 0
+#define ACTMENU_MARKERS_DUPLICATE 1
+#define ACTMENU_MARKERS_DELETE 2
+#define ACTMENU_MARKERS_NAME 3
+#define ACTMENU_MARKERS_MOVE 4
+
 void do_action_buttons(unsigned short event)
 {
        Object *ob= OBACT;
@@ -234,6 +241,9 @@ static void do_action_viewmenu(void *arg, int event)
                        if(G.v2d->flag & V2D_VIEWLOCK)
                                view2d_do_locks(curarea, 0);
                        break;
+               case ACTMENU_VIEW_SLIDERS:       /* Show sliders (when applicable) */
+                       G.saction->flag ^= SACTION_SLIDERS;
+                       break;
                case ACTMENU_VIEW_MAXIMIZE: /* Maximize Window */
                        /* using event B_FULL */
                        break;
@@ -262,6 +272,14 @@ static uiBlock *action_viewmenu(void *arg_unused)
                                         "Update Automatically|", 0, yco-=20, 
                                         menuwidth, 19, NULL, 0.0, 0.0, 1, 
                                         ACTMENU_VIEW_AUTOUPDATE, "");
+               
+       uiDefBut(block, SEPR, 0, "", 0, yco-=6, 
+                        menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+       
+       uiDefIconTextBut(block, BUTM, 1, (G.saction->flag & SACTION_SLIDERS)?ICON_CHECKBOX_HLT:ICON_CHECKBOX_DEHLT, 
+                                        "Show Sliders|", 0, yco-=20, 
+                                        menuwidth, 19, NULL, 0.0, 0.0, 1, 
+                                        ACTMENU_VIEW_SLIDERS, "");
 
        uiDefBut(block, SEPR, 0, "", 0, yco-=6, 
                                        menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
@@ -866,6 +884,80 @@ static uiBlock *action_keymenu(void *arg_unused)
        return block;
 }
 
+static void do_action_markermenu(void *arg, int event)
+{      
+       SpaceAction *saction;
+       ListBase *lb = NULL;
+       
+       saction= curarea->spacedata.first;
+       if (!saction)
+               return;
+
+       /* get set of markers */
+       lb= get_saction_markers(saction);
+       if (lb == NULL) 
+               return;
+       
+       switch(event)
+       {
+               case ACTMENU_MARKERS_ADD:
+                       add_saction_marker(lb, CFRA);
+                       break;
+               case ACTMENU_MARKERS_DUPLICATE:
+                       duplicate_saction_markers(lb);
+                       break;
+               case ACTMENU_MARKERS_DELETE:
+                       remove_saction_markers(lb);
+                       break;
+               case ACTMENU_MARKERS_NAME:
+                       rename_saction_markers(lb);
+                       break;
+               case ACTMENU_MARKERS_MOVE:
+                       transform_saction_markers('g', 0);
+                       break;
+       }
+       
+       allqueue(REDRAWACTION, 0);
+       allqueue(REDRAWTIME, 0);
+}
+
+static uiBlock *action_markermenu(void *arg_unused)
+{
+       uiBlock *block;
+       short yco= 0, menuwidth=120;
+
+       block= uiNewBlock(&curarea->uiblocks, "action_markermenu", 
+                                         UI_EMBOSSP, UI_HELV, curarea->headwin);
+       uiBlockSetButmFunc(block, do_action_markermenu, NULL);
+
+       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Add Marker|M", 0, yco-=20, 
+                                        menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_ADD, "");
+       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Duplicate Marker(s)|Ctrl Shift M", 0, yco-=20, 
+                                        menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_DUPLICATE, "");
+       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Delete Marker(s)|Alt M", 0, yco-=20,
+                                        menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_DELETE, "");
+                                        
+       uiDefBut(block, SEPR, 0, "",        0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "(Re)Name Marker(s)|Ctrl M", 0, yco-=20,
+                                        menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_NAME, "");
+       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grab/Move Marker(s)|Shift M", 0, yco-=20,
+                                        menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_MOVE, "");
+       
+       
+       if(curarea->headertype==HEADERTOP) {
+               uiBlockSetDirection(block, UI_DOWN);
+       }
+       else {
+               uiBlockSetDirection(block, UI_TOP);
+               uiBlockFlipOrder(block);
+       }
+
+       uiTextBoundsBlock(block, 50);
+
+       return block;
+}
+
 void action_buttons(void)
 {
        uiBlock *block;
@@ -942,6 +1034,11 @@ void action_buttons(void)
                uiDefPulldownBut(block, action_keymenu, NULL, 
                                          "Key", xco, -2, xmax-3, 24, "");
                xco+= xmax;
+               
+               xmax= GetButStringLength("Marker");
+               uiDefPulldownBut(block, action_markermenu, NULL, 
+                                         "Marker", xco, -2, xmax-3, 24, "");
+               xco+= xmax;
        }
 
        uiBlockSetEmboss(block, UI_EMBOSS);
@@ -955,6 +1052,29 @@ void action_buttons(void)
                                                from, &(G.saction->actnr), B_ACTALONE, 
                                                B_ACTLOCAL, B_ACTIONDELETE, 0, 0);      
 
+       
+       /* Draw marker set selection box */
+       xco+= 8;
+       
+       if (G.saction->action != NULL) {
+               uiDefButS(block, MENU, B_REDR, 
+                               "Markers%t|None%x0|Scene%x1|Action%x2",  
+                               xco, 0, 80, 20,  &(G.saction->markert), 0, 0, 0, 0, 
+                               "What set of markers to display.");
+       }
+       else {
+               if (G.saction->markert == SACTION_ACMARKERS) 
+                       G.saction->markert = SACTION_NOMARKERS;
+               
+               uiDefButS(block, MENU, B_REDR, 
+                               "Markers%t|None%x0|Scene%x1",    
+                               xco, 0, 80, 20,  &(G.saction->markert), 0, 0, 0, 0, 
+                               "What set of markers to display.");
+       }
+       
+       xco+=80;
+       
+       
        /* Draw action baker */
        xco+= 8;