== Armature Ghost and Path Drawing ==
authorJoshua Leung <aligorith@gmail.com>
Mon, 1 Jan 2007 08:32:11 +0000 (08:32 +0000)
committerJoshua Leung <aligorith@gmail.com>
Mon, 1 Jan 2007 08:32:11 +0000 (08:32 +0000)
The Plumiferos Team have requested some improvements to the
ghost and path drawing tools for armatures. These changes make
these more useful, with more customisable settings. A new panel in
the editing panels for armatures has been added to house these
settings.

-> Ghosts
In addition to the existing method of showing ghosts either side of the
current frame, it is now possible to show ghosts from a given frame range.
This is useful for visualising how the poses in another part of the animation
changed, while editing another part. The colour of ghosts goes from light
(earlier on) to darker (later on).

-> Paths
Several new options for path drawing have been added.
* It is now possibly specify a frame range in which to calculate paths too.
This offers speedups for longer timelines as a shorter span of time can be
sampled.
* Keyframes from the active action/action strip can be shown in a different
colour (in the default theme, this is yellow) on the path.
* Frame numbers for the highlighted positions on the path can be drawn.

Two notes of caution:
* For ghost range: keep the frame ranges relatively small (20-50 frames),
otherwise you will experience a slowdown.
* For path frame numbers: if you have a graphics card which is picky about
text in the 3d-view (like x,y,z labels on empty), this may cause issues.

source/blender/include/butspace.h
source/blender/makesdna/DNA_action_types.h
source/blender/makesdna/DNA_armature_types.h
source/blender/src/buttons_editing.c
source/blender/src/drawarmature.c
source/blender/src/poseobject.c

index b74cb452e87618c65f02c8b743efba8a78f2eebb..f5ac1d4e22bde9ea758eb2337b3772ef094f3ae8 100644 (file)
@@ -43,6 +43,7 @@ struct rctf;
 struct CurveMap;
 struct ImageUser;
 struct RenderResult;
+struct Image;
 
 /* buts->scaflag */            
 #define BUTS_SENS_SEL          1
@@ -475,6 +476,8 @@ void curvemap_buttons(struct uiBlock *block, struct CurveMapping *cumap, char la
 
 #define B_ARM_RECALCDATA       2301
 #define B_ARM_STRIDE           2302
+#define B_ARM_CALCPATHS                2303
+#define B_ARM_CLEARPATHS       2304
 
 /* *********************** */
 #define B_CAMBUTS              2500
index 67c8a6a72b3e325a301cce0602f0f6528e889ddd..08546dc4984a4f34274db9b4c49a01ce553017e7 100644 (file)
@@ -50,10 +50,13 @@ typedef struct bPoseChannel {
        short                           constflag;  /* for quick detecting which constraints affect this channel */
        short                           ikflag;         /* settings for IK bones */
        short               selectflag; /* copy of bone flag, so you can work with library armatures */
-       int                                 pathlen;    /* for drawing paths, the amount of frames */
-       short                           protectflag;/* protect channels from being transformed */
+       short                           protectflag; /* protect channels from being transformed */
        short                           pad2;
        
+       int                                 pathlen;    /* for drawing paths, the amount of frames */
+       int                             pathsf;         /* for drawing paths, the start frame number */
+       int                                     pathef;         /* for drawing paths, the end frame number */
+       
        struct Bone                     *bone;          /* set on read file or rebuild pose */
        struct bPoseChannel *parent;    /* set on read file or rebuild pose */
        struct bPoseChannel *child;             /* set on read file or rebuild pose, the 'ik' child, for b-bones */
index cfcdd4ec959ceb0ac67071f61251f7e83f926631..6225b018c8b0cc4423be47555bc770158116f55d 100644 (file)
@@ -76,10 +76,13 @@ typedef struct bArmature {
        ListBase        chainbase;
        int                     flag;
        int                     drawtype;                       
-       short           deformflag, pad1;
+       short           deformflag; 
+       short           pathflag;
        short           layer, layer_protected;         /* for buttons to work, both variables in this order together */
-       short           ghostep, ghostsize;
-       int                     pad2;
+       short           ghostep, ghostsize;             /*number of frames to ghosts to show, and step between them  */
+       short           ghosttype, pathsize;            /* ghost drawing options and number of frames between points of path */
+       int                     ghostsf, ghostef;               /* start and end frames of ghost-drawing range */
+       int             pathsf, pathef;                 /* start and end frames of path-calculation range for all bones */      
 }bArmature;
 
 /* armature->flag */
@@ -99,6 +102,7 @@ typedef struct bArmature {
 #define                ARM_AUTO_IK             0x200
                        /* made option negative, for backwards compat */
 #define                ARM_NO_CUSTOM   0x400
+#define                ARM_COL_CUSTOM  0x800
 
 /* armature->drawtype */
 #define                ARM_OCTA                0
@@ -110,6 +114,13 @@ typedef struct bArmature {
 #define                ARM_DEF_VGROUP          1
 #define                ARM_DEF_ENVELOPE        2
 
+/* armature->pathflag */
+#define                ARM_PATH_FNUMS  0x001
+#define                ARM_PATH_KFRAS  0x002
+
+/* armature->ghosttype */
+#define        ARM_GHOST_CUR   0
+#define                ARM_GHOST_RANGE 1
 
 /* bone->flag */
 #define                BONE_SELECTED   1
index 2c236b1401bf04ce2c219c69163b9fd3357aa0e9..bde4a809a5ad302eeae065e70de641fe364aeed2 100644 (file)
 #include "BKE_texture.h"
 #include "BKE_utildefines.h"
 
+#include "BIF_poseobject.h"
+
 #include "BDR_drawobject.h"
 #include "BDR_editcurve.h"
 #include "BDR_editface.h"
@@ -3090,6 +3092,14 @@ void do_armbuts(unsigned short event)
                        allqueue(REDRAWBUTSEDIT, 0);
                }
                break;
+       case B_ARM_CALCPATHS:
+               if (ob && ob->pose) 
+                       pose_calculate_path(ob);
+               break;
+       case B_ARM_CLEARPATHS:
+               if (ob && ob->pose)
+                       pose_clear_paths(ob);
+               break;
        }
 }
 
@@ -3291,8 +3301,6 @@ static void editing_panel_armature_type(Object *ob, bArmature *arm)
        uiDefButBitI(block, TOG, ARM_DRAWNAMES, REDRAWVIEW3D, "Draw Names", 110,80,100,20, &arm->flag, 0, 0, 0, 0, "Draw bone names");
        uiDefButBitI(block, TOGN, ARM_NO_CUSTOM, REDRAWVIEW3D, "Draw Shapes", 210,80,100,20, &arm->flag, 0, 0, 0, 0, "Draw custom bone shapes");
        
-       uiDefButS(block, NUM, REDRAWVIEW3D, "Ghost: ", 10,60,150,20, &arm->ghostep, 0.0f, 30.0f, 0, 0, "Draw Ghosts around current frame, for current Action");
-       uiDefButS(block, NUM, REDRAWVIEW3D, "Step: ", 160,60,150,20, &arm->ghostsize, 1.0f, 20.0f, 0, 0, "How many frames between Ghost instances");
        uiBlockEndAlign(block);
        
        uiDefBut(block, LABEL, 0, "Deform Options", 10,40,150,20, 0, 0, 0, 0, 0, "");
@@ -3301,7 +3309,67 @@ static void editing_panel_armature_type(Object *ob, bArmature *arm)
        uiDefButBitS(block, TOG, ARM_DEF_ENVELOPE, B_ARM_RECALCDATA, "Envelopes",       160,20,150,20, &arm->deformflag, 0, 0, 0, 0, "Enable Bone Envelopes defining deform (not for Modifiers)");
        uiDefButBitI(block, TOG, ARM_RESTPOS, B_ARM_RECALCDATA,"Rest Position",         10,0,150,20, &arm->flag, 0, 0, 0, 0, "Show armature rest position, no posing possible");
        uiDefButBitI(block, TOG, ARM_DELAYDEFORM, REDRAWVIEW3D, "Delay Deform",         160,0,150,20, &arm->flag, 0, 0, 0, 0, "Don't deform children when manipulating bones in pose mode");
+       uiBlockEndAlign(block);
+}
+
+static void editing_panel_armature_visuals(Object *ob, bArmature *arm)
+{
+       uiBlock *block;
+       
+       block= uiNewBlock(&curarea->uiblocks, "editing_panel_armature_visuals", UI_EMBOSS, UI_HELV, curarea->win);
+       uiNewPanelTabbed("Armature Visualisations", "Editing");
+       if(uiNewPanel(curarea, block, "Armature Visualisations", "Editing", 320, 0, 318, 204)==0) return;
+
+       /* version patch for older files here (do_versions patch too complicated) */
+       if ((arm->ghostsf == 0) || (arm->ghostef == 0)) {
+               arm->ghostsf = CFRA - arm->ghostep;
+               arm->ghostef = CFRA + arm->ghostep;
+       }
+       if ((arm->pathsf == 0) || (arm->pathef == 0)) {
+               arm->pathsf = SFRA;
+               arm->pathef = EFRA;
+       }
        
+       /* Ghost Drawing Options */
+       uiDefBut(block, LABEL, 0, "Ghost Options", 10,180,150,20, 0, 0, 0, 0, 0, "");
+
+       uiBlockBeginAlign(block);
+       uiDefButS(block, MENU, REDRAWVIEW3D, "Ghosts %t|Around Current Frame %x0|In Range %x1", 
+                                                                                               10, 160, 150, 20, &arm->ghosttype, 0, 0, 0, 0, "Choose range of Ghosts to draw for current Action");    
+       
+       uiDefButS(block, NUM, REDRAWVIEW3D, "GStep: ", 10,140,150,20, &arm->ghostsize, 1.0f, 20.0f, 0, 0, "How many frames between Ghost instances");
+       uiBlockEndAlign(block);
+       
+       uiBlockBeginAlign(block);
+       if (arm->ghosttype == ARM_GHOST_CUR) {
+               /* range is around current frame */
+               uiDefButS(block, NUM, REDRAWVIEW3D, "Ghost: ", 10,110,150,20, &arm->ghostep, 0.0f, 30.0f, 0, 0, "Draw Ghosts around current frame, for current Action");
+       }
+       else if (arm->ghosttype == ARM_GHOST_RANGE) {
+               /* range is defined by start+end frame below */
+               uiDefButI(block, NUM,REDRAWVIEW3D,"GSta:",10,110,150,20, &arm->ghostsf,1.0,MAXFRAMEF, 0, 0, "The start frame for Ghost display range");
+               uiDefButI(block, NUM,REDRAWVIEW3D,"GEnd:",10,90,150,20, &arm->ghostef,arm->ghostsf,MAXFRAMEF, 0, 0, "The end frame for Ghost display range");   
+       }
+       uiBlockEndAlign(block);
+       
+       /* Bone Path Drawing Options */
+       uiDefBut(block, LABEL, 0, "Bone Paths", 165,180,150,20, 0, 0, 0, 0, 0, "");
+       
+       uiBlockBeginAlign(block);
+       uiDefButBitS(block, TOG, ARM_PATH_FNUMS, REDRAWVIEW3D, "Frame Nums", 170, 160, 80, 20, &arm->pathflag, 0, 0, 0, 0, "Show frame numbers on path");
+       uiDefButBitS(block, TOG, ARM_PATH_KFRAS, REDRAWVIEW3D, "Show Keys", 250, 160, 80, 20, &arm->pathflag, 0, 0, 0, 0, "Show key frames on path");
+       uiDefButS(block, NUM, REDRAWVIEW3D, "PStep:",170,140,160,20, &arm->pathsize,1,100, 10, 50, "Frames between highlighted points on bone path");
+       uiBlockEndAlign(block);
+       
+       uiBlockBeginAlign(block);
+       uiDefButI(block, NUM,REDRAWVIEW3D,"PSta:",170,100,160,20, &arm->pathsf, 1.0, MAXFRAMEF, 0, 0, "The start frame for Bone Path display range");
+       uiDefButI(block, NUM,REDRAWVIEW3D,"PEnd:",170,80,160,20, &arm->pathef, arm->pathsf, MAXFRAMEF, 0, 0, "The end frame for Bone Path display range");      
+       uiBlockEndAlign(block);
+       
+       uiBlockBeginAlign(block);
+       uiDefBut(block, BUT, B_ARM_CALCPATHS, "Calculate Paths", 170,40,160,20, 0, 0, 0, 0, 0, "(Re)calculates the paths of the selected bones");
+       uiDefBut(block, BUT, B_ARM_CLEARPATHS, "Clear All Paths", 170,20,160,20, 0, 0, 0, 0, 0, "Clears all bone paths");
+       uiBlockEndAlign(block);
 }
 
 /* autocomplete callback for editbones */
@@ -5112,6 +5180,7 @@ void editing_panels()
                        editing_panel_armature_bones(ob, arm);
                }
                else if(ob->flag & OB_POSEMODE) {
+                       editing_panel_armature_visuals(ob, arm);
                        editing_panel_pose_bones(ob, arm);
                        object_panel_constraint("Editing");
                }               
index cb786c651d6932e01aa75f442a6e3aa2ceb600f1..42ce97f771bde931dbd22fc73aca4bcd25a26686 100644 (file)
 #include "BKE_global.h"
 #include "BKE_main.h"
 #include "BKE_object.h"
+#include "BKE_ipo.h"
 #include "BKE_utildefines.h"
 
+#include "BIF_editaction.h"
 #include "BIF_editarmature.h"
 #include "BIF_gl.h"
 #include "BIF_glutil.h"
@@ -75,6 +77,7 @@
 
 #include "BDR_editobject.h"
 #include "BDR_drawobject.h"
+#include "BDR_drawaction.h"
 
 #include "BSE_edit.h"
 #include "BSE_view.h"
@@ -1731,18 +1734,32 @@ static void draw_pose_paths(Object *ob)
 {
        bArmature *arm= ob->data;
        bPoseChannel *pchan;
+       bAction *act;
+       bActionChannel *achan;
+       CfraElem *ce;
+       ListBase ak;
        float *fp;
        int a;
+       int stepsize, sfra;
        
        if(G.vd->zbuf) glDisable(GL_DEPTH_TEST);
        
        glPushMatrix();
        glLoadMatrixf(G.vd->viewmat);
        
+       stepsize = arm->pathsize;
+       
        for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
                if(pchan->bone->layer & arm->layer) {
                        if(pchan->path) {
+                               /* version patch here - cannot access frame info from file reading */
+                               if ((pchan->pathsf == 0) || (pchan->pathef == 0)) {
+                                       pchan->pathsf= SFRA;
+                                       pchan->pathef= EFRA;
+                               }
+                               sfra= pchan->pathsf;
                                
+                               /* draw curve-line of path */
                                BIF_ThemeColorBlend(TH_WIRE, TH_BACK, 0.7);
                                glBegin(GL_LINE_STRIP);
                                for(a=0, fp= pchan->path; a<pchan->pathlen; a++, fp+=3)
@@ -1750,17 +1767,70 @@ static void draw_pose_paths(Object *ob)
                                glEnd();
                                
                                glPointSize(1.0);
-                               BIF_ThemeColor(TH_WIRE);
+                               
+                               /* draw little black point at each frame */
                                glBegin(GL_POINTS);
-                               for(a=0, fp= pchan->path; a<pchan->pathlen; a++, fp+=3)
+                               for(a=0, fp= pchan->path; a<pchan->pathlen; a++, fp+=3) 
                                        glVertex3fv(fp);
                                glEnd();
                                
+                               /* Draw little white dots at each framestep value */
                                BIF_ThemeColor(TH_TEXT_HI);
                                glBegin(GL_POINTS);
-                               for(a=0, fp= pchan->path; a<pchan->pathlen; a+=10, fp+=30)
+                               for(a=0, fp= pchan->path; a<pchan->pathlen; a+=stepsize, fp+=(stepsize*3)) 
                                        glVertex3fv(fp);
                                glEnd();
+                               
+                               /* Draw frame numbers at each framestep value */
+                               if (arm->pathflag & ARM_PATH_FNUMS) {
+                                       for(a=0, fp= pchan->path; a<pchan->pathlen; a+=stepsize, fp+=(stepsize*3)) {
+                                               char str[32];
+                                               
+                                               glRasterPos3fv(fp);
+                                               sprintf(str, "  %d\n", (a+sfra));
+                                               BMF_DrawString(G.font, str);
+                                       }
+                               }
+                               
+                               /* Keyframes - dots and numbers */
+                               if (arm->pathflag & ARM_PATH_KFRAS) {
+                                       /* build list of all keyframes in active action for pchan */
+                                       ak.first = ak.last = NULL;      
+                                       act= ob_get_action(ob);
+                                       if (act) {
+                                               achan= get_action_channel(act, pchan->name);
+                                               if (achan) 
+                                                       ipo_to_keylist(achan->ipo, &ak, NULL);
+                                       }
+                                       
+                                       /* Draw little yellow dots at each keyframe */
+                                       BIF_ThemeColor(TH_VERTEX_SELECT);
+                                       glBegin(GL_POINTS);
+                                       for(a=0, fp= pchan->path; a<pchan->pathlen; a++, fp+=3) {
+                                               for (ce= ak.first; ce; ce= ce->next) {
+                                                       if (ce->cfra == (a+sfra))
+                                                               glVertex3fv(fp);
+                                               }
+                                       }
+                                       glEnd();
+                                       
+                                       /* Draw frame numbers of keyframes  */
+                                       if (arm->pathflag & ARM_PATH_FNUMS) {
+                                               for(a=0, fp= pchan->path; a<pchan->pathlen; a++, fp+=3) {
+                                                       for (ce= ak.first; ce; ce= ce->next) {
+                                                               if (ce->cfra == (a+sfra)) {
+                                                                       char str[32];
+                                                                       
+                                                                       glRasterPos3fv(fp);
+                                                                       sprintf(str, "  %d\n", (a+sfra));
+                                                                       BMF_DrawString(G.font, str);
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       
+                                       BLI_freelistN(&ak);
+                               }
                        }
                }
        }
@@ -1769,6 +1839,66 @@ static void draw_pose_paths(Object *ob)
        glPopMatrix();
 }
 
+/* draw ghosts that occur within a frame range 
+ *     note: object should be in posemode */
+static void draw_ghost_poses_range(Base *base)
+{
+       Object *ob= base->object;
+       bArmature *arm= ob->data;
+       bPose *posen, *poseo;
+       float start, end, stepsize, range, colfac;
+       int cfrao, flago, ipoflago;
+       
+       start = arm->ghostsf;
+       end = arm->ghostef;
+       if (end<=start)
+               return;
+       
+       stepsize= (float)(arm->ghostsize);
+       range= (float)(end - start);
+       
+       /* store values */
+       ob->flag &= ~OB_POSEMODE;
+       cfrao= CFRA;
+       flago= arm->flag;
+       arm->flag &= ~(ARM_DRAWNAMES|ARM_DRAWAXES);
+       ipoflago= ob->ipoflag; 
+       ob->ipoflag |= OB_DISABLE_PATH;
+       
+       /* copy the pose */
+       poseo= ob->pose;
+       copy_pose(&posen, ob->pose, 1);
+       ob->pose= posen;
+       armature_rebuild_pose(ob, ob->data);    /* child pointers for IK */
+       
+       glEnable(GL_BLEND);
+       if(G.vd->zbuf) glDisable(GL_DEPTH_TEST);
+       
+       /* draw from first frame of range to last */
+       for(CFRA= start; CFRA<end; CFRA+=stepsize) {
+               colfac = (end-CFRA)/range;
+               BIF_ThemeColorShadeAlpha(TH_WIRE, 0, -128-(int)(120.0f*sqrt(colfac)));
+               
+               do_all_pose_actions(ob);
+               where_is_pose(ob);
+               draw_pose_channels(base, OB_WIRE);
+       }
+       glDisable(GL_BLEND);
+       if(G.vd->zbuf) glEnable(GL_DEPTH_TEST);
+
+       free_pose_channels(posen);
+       MEM_freeN(posen);
+       
+       /* restore */
+       CFRA= cfrao;
+       ob->pose= poseo;
+       arm->flag= flago;
+       armature_rebuild_pose(ob, ob->data);
+       ob->flag |= OB_POSEMODE;
+       ob->ipoflag= ipoflago; 
+
+}
+
 /* object is supposed to be armature in posemode */
 static void draw_ghost_poses(Base *base)
 {
@@ -1904,9 +2034,12 @@ int draw_armature(Base *base, int dt)
                                                arm->flag |= ARM_POSEMODE;
                                }
                                else if(ob->flag & OB_POSEMODE) {
-               
-                                       if(arm->ghostep) {
-                                               draw_ghost_poses(base);
+                                       if (arm->ghosttype == ARM_GHOST_RANGE){
+                                               draw_ghost_poses_range(base);
+                                       }
+                                       else {
+                                               if (arm->ghostep)
+                                                       draw_ghost_poses(base);
                                        }
                                        
                                        if(ob==OBACT) 
index f2fe70737a8bb85e951fd09c618fb1c36873a06f..571705968189ae7430b8893982038b7c5a2c2342 100644 (file)
@@ -229,12 +229,17 @@ void pose_calculate_path(Object *ob)
        Base *base;
        float *fp;
        int cfra;
+       int sfra, efra;
        
        if(ob==NULL || ob->pose==NULL)
                return;
        arm= ob->data;
        
-       if(EFRA<=SFRA) return;
+       /* set frame values */
+       cfra= CFRA;
+       sfra = arm->pathsf;
+       efra = arm->pathef;
+       if (efra<=sfra) return;
        
        DAG_object_update_flags(G.scene, ob, screen_view3d_layers());
        
@@ -242,7 +247,9 @@ void pose_calculate_path(Object *ob)
        for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
                if(pchan->bone && (pchan->bone->flag & BONE_SELECTED)) {
                        if(arm->layer & pchan->bone->layer) {
-                               pchan->pathlen= EFRA-SFRA+1;
+                               pchan->pathlen= efra-sfra+1;
+                               pchan->pathsf= sfra;
+                               pchan->pathef= efra+1;
                                if(pchan->path)
                                        MEM_freeN(pchan->path);
                                pchan->path= MEM_callocN(3*pchan->pathlen*sizeof(float), "pchan path");
@@ -250,8 +257,7 @@ void pose_calculate_path(Object *ob)
                }
        }
        
-       cfra= CFRA;
-       for(CFRA=SFRA; CFRA<=EFRA; CFRA++) {
+       for(CFRA=sfra; CFRA<=efra; CFRA++) {
                
                /* do all updates */
                for(base= FIRSTBASE; base; base= base->next) {
@@ -266,7 +272,7 @@ void pose_calculate_path(Object *ob)
                        if(pchan->bone && (pchan->bone->flag & BONE_SELECTED)) {
                                if(arm->layer & pchan->bone->layer) {
                                        if(pchan->path) {
-                                               fp= pchan->path+3*(CFRA-SFRA);
+                                               fp= pchan->path+3*(CFRA-sfra);
                                                VECCOPY(fp, pchan->pose_tail);
                                                Mat4MulVecfl(ob->obmat, fp);
                                        }