diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index cbec4cf04fb..1e1c3c110e8 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -60,6 +60,11 @@ extern "C" { */ void free_pose_channels(struct bPose *pose); +/** + * Removes and deallocates all data from a pose, and also frees the pose. + */ +void free_pose(struct bPose *pose); + /** * Allocate a new pose on the heap, and copy the src pose and it's channels * into the new pose. *dst is set to the newly allocated structure, and assumed to be NULL. diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index d85b61675a6..b8c05f3bb7b 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -312,7 +312,7 @@ void free_pose_channels(bPose *pose) { bPoseChannel *pchan; - if (pose->chanbase.first){ + if (pose->chanbase.first) { for (pchan = pose->chanbase.first; pchan; pchan=pchan->next){ if(pchan->path) MEM_freeN(pchan->path); @@ -322,6 +322,21 @@ void free_pose_channels(bPose *pose) } } +void free_pose(bPose *pose) +{ + if (pose) { + /* free pose-channels */ + free_pose_channels(pose); + + /* free pose-groups */ + if (pose->agroups.first) + BLI_freelistN(&pose->agroups); + + /* free pose */ + MEM_freeN(pose); + } +} + static void copy_pose_channel_data(bPoseChannel *pchan, const bPoseChannel *chan) { bConstraint *pcon, *con; @@ -415,7 +430,7 @@ bActionChannel *get_action_channel(bAction *act, const char *name) if (!act || !name) return NULL; - for (chan = act->chanbase.first; chan; chan=chan->next){ + for (chan = act->chanbase.first; chan; chan=chan->next) { if (!strcmp (chan->name, name)) return chan; } @@ -423,18 +438,16 @@ bActionChannel *get_action_channel(bAction *act, const char *name) return NULL; } -/* returns existing channel, or adds new one. In latter case it doesnt activate it, context is required for that*/ +/* returns existing channel, or adds new one. In latter case it doesnt activate it, context is required for that */ bActionChannel *verify_action_channel(bAction *act, const char *name) { bActionChannel *chan; chan= get_action_channel(act, name); - if(chan==NULL) { - if (!chan) { - chan = MEM_callocN (sizeof(bActionChannel), "actionChannel"); - strncpy (chan->name, name, 31); - BLI_addtail (&act->chanbase, chan); - } + if (chan == NULL) { + chan = MEM_callocN (sizeof(bActionChannel), "actionChannel"); + strncpy(chan->name, name, 31); + BLI_addtail(&act->chanbase, chan); } return chan; } @@ -1340,10 +1353,8 @@ static void do_nla(Object *ob, int blocktype) } /* free */ - if (tpose){ - free_pose_channels(tpose); - MEM_freeN(tpose); - } + if (tpose) + free_pose(tpose); if(chanbase.first) BLI_freelistN(&chanbase); } diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 295c52f1415..5e53f10db37 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -2036,8 +2036,7 @@ static void actcon_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraint Mat4CpyMat4(ct->matrix, tchan->chan_mat); /* Clean up */ - free_pose_channels(pose); - MEM_freeN(pose); + free_pose(pose); } else if (cob->type == CONSTRAINT_OBTYPE_OBJECT) { /* evaluate using workob */ diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 70be6d2c79b..94190f9753b 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -229,10 +229,8 @@ void free_object(Object *ob) if(ob->dup_group) ob->dup_group->id.us--; if(ob->defbase.first) BLI_freelistN(&ob->defbase); - if(ob->pose) { - free_pose_channels(ob->pose); - MEM_freeN(ob->pose); - } + if(ob->pose) + free_pose(ob->pose); free_effects(&ob->effect); free_properties(&ob->prop); object_free_modifiers(ob); @@ -1438,7 +1436,7 @@ static void ob_parcurve(Object *ob, Object *par, float mat[][4]) { Curve *cu; float q[4], vec[4], dir[3], *quat, x1, ctime; - float timeoffs, sf_orig = 0.0; + float timeoffs = 0.0, sf_orig = 0.0; Mat4One(mat); @@ -2255,4 +2253,4 @@ float give_timeoffset(Object *ob) { } else { return ob->sf; } -} \ No newline at end of file +} diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 88bbcca3a94..8481e7c0a3a 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2830,8 +2830,7 @@ static void lib_link_object(FileData *fd, Main *main) else printf("Object %s lost data.", ob->id.name+2); if(ob->pose) { - free_pose_channels(ob->pose); - MEM_freeN(ob->pose); + free_pose(ob->pose); ob->pose= NULL; ob->flag &= ~OB_POSEMODE; } @@ -2968,6 +2967,7 @@ static void direct_link_pose(FileData *fd, bPose *pose) { return; link_list(fd, &pose->chanbase); + link_list(fd, &pose->agroups); for (pchan = pose->chanbase.first; pchan; pchan=pchan->next) { pchan->bone= NULL; diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index b5c48716036..f7238e96d8f 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -777,6 +777,7 @@ static void write_constraints(WriteData *wd, ListBase *conlist) static void write_pose(WriteData *wd, bPose *pose) { bPoseChannel *chan; + bActionGroup *grp; /* Write each channel */ if (!pose) @@ -792,6 +793,10 @@ static void write_pose(WriteData *wd, bPose *pose) writestruct(wd, DATA, "bPoseChannel", 1, chan); } + + /* Write groups */ + for (grp=pose->agroups.first; grp; grp=grp->next) + writestruct(wd, DATA, "bActionGroup", 1, grp); /* Write this pose */ writestruct(wd, DATA, "bPose", 1, pose); diff --git a/source/blender/include/BIF_editaction.h b/source/blender/include/BIF_editaction.h index bea1edcc2ee..b3e402daa30 100644 --- a/source/blender/include/BIF_editaction.h +++ b/source/blender/include/BIF_editaction.h @@ -142,6 +142,8 @@ void paste_actdata(void); /* Group/Channel Operations */ struct bActionGroup *get_active_actiongroup(struct bAction *act); void set_active_actiongroup(struct bAction *act, struct bActionGroup *agrp, short select); +void unique_name_actiongroup(struct ListBase *lb, struct bActionGroup *agrp); +// <--- add some func to add group for action-channel based on corresponding pchan's grouping void action_groups_group(short add_group); void action_groups_ungroup(void); diff --git a/source/blender/include/butspace.h b/source/blender/include/butspace.h index a20dc36ab50..058b811aeba 100644 --- a/source/blender/include/butspace.h +++ b/source/blender/include/butspace.h @@ -524,6 +524,11 @@ void curvemap_buttons(struct uiBlock *block, struct CurveMapping *cumap, char la #define B_POSELIB_ALONE 2321 #define B_POSELIB_DELETE 2322 + +#define B_POSEGRP_RECALC 2330 +#define B_POSEGRP_ADD 2331 +#define B_POSEGRP_REMOVE 2332 + /* *********************** */ #define B_CAMBUTS 2500 diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index ea145e7ef79..977abaffeb4 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -51,7 +51,7 @@ typedef struct bPoseChannel { short ikflag; /* settings for IK bones */ short selectflag; /* copy of bone flag, so you can work with library armatures */ short protectflag; /* protect channels from being transformed */ - short customCol; /* index of custom color set to use (0=default - used for all old files) */ + short agrp_index; /* index of action-group this bone belongs to (0 = default/no group) */ int pathlen; /* for drawing paths, the amount of frames */ int pathsf; /* for drawing paths, the start frame number */ @@ -98,6 +98,12 @@ typedef struct bPose { float ctime; /* local action time of this pose */ float stride_offset[3]; /* applied to object */ float cyclic_offset[3]; /* result of match and cycles, applied in where_is_pose() */ + + + ListBase agroups; /* list of bActionGroups */ + + int active_group; /* index of active group (starts from 1) */ + int pad; } bPose; @@ -114,7 +120,7 @@ typedef struct bActionGroup { struct bActionGroup *next, *prev; int flag; /* settings for this action-group */ - int pad; + int customCol; /* index of custom color set to use when used for bones (0=default - used for all old files) */ char name[32]; /* name of the group */ ListBase channels; /* Note: this must not be touched by standard listbase functions */ @@ -197,6 +203,7 @@ typedef enum AGRP_FLAG { AGRP_ACTIVE = (1<<1), AGRP_PROTECTED = (1<<2), AGRP_EXPANDED = (1<<3), + AGRP_TEMP = (1<<30), AGRP_MOVED = (1<<31) } AGRP_FLAG; diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c index 8db7f36d504..732d690ae7d 100644 --- a/source/blender/src/buttons_editing.c +++ b/source/blender/src/buttons_editing.c @@ -3852,6 +3852,42 @@ void do_armbuts(unsigned short event) } } break; + case B_POSEGRP_RECALC: + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWBUTSEDIT, 0); + break; + case B_POSEGRP_ADD: + if (ob && ob->pose) { + bPose *pose= ob->pose; + bActionGroup *grp; + + grp= MEM_callocN(sizeof(bActionGroup), "PoseGroup"); + strcpy(grp->name, "Group"); + BLI_addtail(&pose->agroups, grp); + + pose->active_group= BLI_countlist(&pose->agroups); + + BIF_undo_push("Add Pose Group"); + allqueue(REDRAWBUTSEDIT, 0); + allqueue(REDRAWVIEW3D, 0); + } + break; + case B_POSEGRP_REMOVE: + if (ob && ob->pose && ob->pose->active_group) { + bPose *pose= ob->pose; + bActionGroup *grp= NULL; + + grp= BLI_findlink(&pose->agroups, pose->active_group-1); + if (grp) { + BLI_freelinkN(&pose->agroups, grp); + pose->active_group= 0; + } + + BIF_undo_push("Remove Pose Group"); + allqueue(REDRAWBUTSEDIT, 0); + allqueue(REDRAWVIEW3D, 0); + } + break; } } @@ -4282,6 +4318,37 @@ static int ob_arm_bone_pchan_lock(Object *ob, bArmature *arm, Bone *bone, bPoseC return 0; } +static char *build_posegroups_menustr(bPose *pose) +{ + DynStr *pupds= BLI_dynstr_new(); + bActionGroup *agrp; + char *str; + char buf[16]; + int i; + + /* add title first (and the "none" entry) */ + BLI_dynstr_append(pupds, "Pose Group%t|"); + BLI_dynstr_append(pupds, "BG: [None]%x0"); + + /* loop through markers, adding them */ + for (agrp= pose->agroups.first, i=1; agrp; agrp=agrp->next, i++) { + BLI_dynstr_append(pupds, "BG: "); + BLI_dynstr_append(pupds, agrp->name); + + sprintf(buf, "%%x%d", i); + BLI_dynstr_append(pupds, buf); + + if (agrp->next) + BLI_dynstr_append(pupds, "|"); + } + + /* convert to normal MEM_malloc'd string */ + str= BLI_dynstr_get_cstring(pupds); + BLI_dynstr_free(pupds); + + return str; +} + static void editing_panel_pose_bones(Object *ob, bArmature *arm) { uiBlock *block; @@ -4290,6 +4357,7 @@ static void editing_panel_pose_bones(Object *ob, bArmature *arm) Bone *curBone; int by, a; int index, zerodof, zerolimit; + char *menustr; /* Draw the bone name block */ block= uiNewBlock(&curarea->uiblocks, "editing_panel_pose_bones", UI_EMBOSS, UI_HELV, curarea->win); @@ -4305,19 +4373,23 @@ static void editing_panel_pose_bones(Object *ob, bArmature *arm) for (pchan=ob->pose->chanbase.first, index=0; pchan; pchan=pchan->next, index++){ curBone= pchan->bone; if ((curBone->flag & BONE_SELECTED) && (curBone->layer & arm->layer)) { - if(ob_arm_bone_pchan_lock(ob, arm, curBone, pchan)) uiDefBut(block, LABEL, 0, "Proxy Locked", 160, 180,150,18, NULL, 1, 0, 0, 0, ""); - /* Bone naming button */ + /* Bone naming button */ uiBlockBeginAlign(block); but=uiDefBut(block, TEX, REDRAWVIEW3D, "BO:", -10,by,117,19, curBone->name, 0, 24, 0, 0, "Change the bone name"); uiButSetFunc(but, validate_posebonebutton_cb, curBone, NULL); uiButSetCompleteFunc(but, autocomplete_bone, (void *)ob); - /* Dist and weight buttons */ - uiDefButF(block, NUM,B_ARM_RECALCDATA, "Dist:", 107, by, 105, 19, &curBone->dist, 0.0, 1000.0, 10.0, 0.0, "Bone deformation distance"); - uiDefButF(block, NUM,B_ARM_RECALCDATA, "Weight:", 220, by, 110, 19, &curBone->weight, 0.0F, 1000.0F, 10.0F, 0.0F, "Bone deformation weight"); + /* Bone custom drawing */ + menustr= build_posegroups_menustr(ob->pose); + uiDefButS(block, MENU,REDRAWVIEW3D, menustr, 107,by,105,19, &pchan->agrp_index, 0.0, 0.0, 0.0, 0.0, "Change the Pose Group this Bone belongs to"); + MEM_freeN(menustr); + + ob_arm_bone_pchan_lock(ob, arm, curBone, pchan); + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, REDRAWVIEW3D, "OB:", 220,by,110,19, &pchan->custom, "Object that defines custom draw type for this Bone"); + ob_arm_bone_pchan_lock(ob, arm, curBone, NULL); /* Segment, ease in/out buttons */ uiBlockBeginAlign(block); @@ -4330,9 +4402,7 @@ static void editing_panel_pose_bones(Object *ob, bArmature *arm) uiDefButBitI(block, TOG, BONE_NO_SCALE, B_ARM_RECALCDATA, "S", 70,by-38,20,19, &curBone->flag, 1.0, 32.0, 0.0, 0.0, "Don't inherit scale from parent Bone"); uiDefButBitI(block, TOGN, BONE_NO_DEFORM, B_ARM_RECALCDATA, "Deform", 90, by-38, 80, 19, &curBone->flag, 0.0, 0.0, 0.0, 0.0, "Indicate if Bone deforms geometry"); uiDefButBitI(block, TOG, BONE_MULT_VG_ENV, B_ARM_RECALCDATA, "Mult", 170,by-38,80,19, &curBone->flag, 1.0, 32.0, 0.0, 0.0, "Multiply Bone Envelope with VertexGroup"); - ob_arm_bone_pchan_lock(ob, arm, curBone, pchan); - uiDefIDPoinBut(block, test_obpoin_but, ID_OB, REDRAWVIEW3D, "OB:", 250,by-38,80,19, &pchan->custom, "Object that defines custom draw type for this Bone"); - ob_arm_bone_pchan_lock(ob, arm, curBone, NULL); + uiDefButBitI(block, TOG, BONE_MULT_VG_ENV, B_ARM_RECALCDATA, "Hide", 250,by-38,80,19, &curBone->flag, 1.0, 32.0, 0.0, 0.0, "Toggles display of this bone in Edit Mode"); /* layers */ uiBlockBeginAlign(block); @@ -5066,10 +5136,14 @@ static void editing_panel_links(Object *ob) if (ob->type==OB_ARMATURE) { if ((ob->pose) && (ob->flag & OB_POSEMODE) && (G.obedit != ob)) { bAction *act= ob->poselib; + bPose *pose= ob->pose; + int count; + char *menustr; + /* PoseLib settings for armature reside on the left */ xco= 143; - uiDefBut(block, LABEL,0, "Pose Library (Action):", xco, 154, 200, 20, 0, 0, 0, 0, 0, ""); + uiDefBut(block, LABEL,0, "Pose Library:", xco, 154, 200, 20, 0, 0, 0, 0, 0, ""); /* PoseLib Action */ uiBlockSetCol(block, TH_BUT_SETTING2); @@ -5078,20 +5152,22 @@ static void editing_panel_links(Object *ob) uiDefBut(block, BUT, B_POSELIB_VALIDATE, "Auto-Sync PoseLib", xco,110,160,20, 0, 0, 0, 0, 0, "Syncs the current PoseLib with the poses available"); - /* poselib pose editing controls */ - if ((act) && (act->markers.first)) { - TimeMarker *marker= poselib_get_active_pose(act); - int count= BLI_countlist(&act->markers); - char *menustr= poselib_build_poses_menu(act, "PoseLib Poses"); - + /* PoseLib - Pose editing controls */ + if (act) { uiBlockBeginAlign(block); /* currently 'active' pose */ - uiDefButI(block, MENU, B_POSELIB_APPLYP, menustr, xco, 85,18,20, &act->active_marker, 1, count, 0, 0, "Browses Poses in Pose Library. Applies chosen pose."); - MEM_freeN(menustr); - - if (act->active_marker) { - uiDefBut(block, TEX, REDRAWBUTSEDIT,"", xco+18,85,160-18-20,20, marker->name, 0, 63, 0, 0, "Displays current Pose Library Pose name. Click to change."); - uiDefIconBut(block, BUT, B_POSELIB_REMOVEP, VICON_X, xco+160-20, 85, 20, 20, NULL, 0.0, 0.0, 0.0, 0.0, "Remove this Pose Library Pose from Pose Library."); + if (act->markers.first) { + count= BLI_countlist(&act->markers); + menustr= poselib_build_poses_menu(act, "PoseLib Poses"); + uiDefButI(block, MENU, B_POSELIB_APPLYP, menustr, xco, 85,18,20, &act->active_marker, 1, count, 0, 0, "Browses Poses in Pose Library. Applies chosen pose."); + MEM_freeN(menustr); + + if (act->active_marker) { + TimeMarker *marker= poselib_get_active_pose(act); + + uiDefBut(block, TEX, REDRAWBUTSEDIT,"", xco+18,85,160-18-20,20, marker->name, 0, 63, 0, 0, "Displays current Pose Library Pose name. Click to change."); + uiDefIconBut(block, BUT, B_POSELIB_REMOVEP, VICON_X, xco+160-20, 85, 20, 20, NULL, 0.0, 0.0, 0.0, 0.0, "Remove this Pose Library Pose from Pose Library."); + } } /* add new poses */ @@ -5099,6 +5175,37 @@ static void editing_panel_links(Object *ob) uiDefBut(block, BUT, B_POSELIB_REPLACEP, "Replace Pose", xco+80,65,80,20, 0, 0, 0, 0, 0, "Replace existing PoseLib Pose with current pose"); uiBlockEndAlign(block); } + + + /* Action Groups settings for armature reside on the right */ + xco= 315; + + uiDefBut(block, LABEL,0, "Bone Groups:", xco, 154, 140, 20, 0, 0, 0, 0, 0, ""); + + /* add new group */ + uiDefBut(block, BUT, B_POSEGRP_ADD, "Add Group", xco,130,140,20, 0, 0, 0, 0, 0, "Add a new Pose Group for the Pose"); + + if (pose->agroups.first) { + uiBlockBeginAlign(block); + /* currently 'active' group - browse groups */ + count= BLI_countlist(&pose->agroups); + menustr= build_posegroups_menustr(pose); + uiDefButI(block, MENU, B_POSEGRP_RECALC, menustr, xco, 85,18,20, &pose->active_group, 1, count, 0, 0, "Browses Pose Groups available for Armature. Click to change."); + MEM_freeN(menustr); + + + if (pose->active_group) { + bActionGroup *grp= (bActionGroup *)BLI_findlink(&pose->agroups, pose->active_group-1); + + /* active group */ + uiDefBut(block, TEX, REDRAWBUTSEDIT,"", xco+18,85,140-18-20,20, grp->name, 0, 63, 0, 0, "Displays current Pose Group name. Click to change."); + uiDefIconBut(block, BUT, B_POSEGRP_REMOVE, VICON_X, xco+140-20, 85, 20, 20, NULL, 0.0, 0.0, 0.0, 0.0, "Remove this Pose Group"); + + /* set custom color set */ + uiDefButI(block, MENU,B_POSEGRP_RECALC, "Custom Color Set%t|GrpCol: [None]%x0", xco,65,140,19, &grp->customCol, 0.0, 0.0, 0.0, 0.0, "Set of Custom Colors to shade Group's bones with. (NOT YET FUNCTIONAL)"); + } + uiBlockEndAlign(block); + } } return; } diff --git a/source/blender/src/drawaction.c b/source/blender/src/drawaction.c index 42b0b0bda3b..a169af6cf93 100644 --- a/source/blender/src/drawaction.c +++ b/source/blender/src/drawaction.c @@ -64,6 +64,7 @@ #include "BKE_depsgraph.h" #include "BKE_ipo.h" #include "BKE_key.h" +#include "BKE_object.h" #include "BKE_global.h" #include "BKE_utildefines.h" diff --git a/source/blender/src/drawarmature.c b/source/blender/src/drawarmature.c index 9ec688b5d8d..3e08910abfe 100644 --- a/source/blender/src/drawarmature.c +++ b/source/blender/src/drawarmature.c @@ -2015,8 +2015,7 @@ static void draw_ghost_poses_range(Base *base) if (G.vd->zbuf) glEnable(GL_DEPTH_TEST); ghost_poses_tag_unselected(ob, 1); /* unhide unselected bones if need be */ - free_pose_channels(posen); - MEM_freeN(posen); + free_pose(posen); /* restore */ CFRA= cfrao; @@ -2092,9 +2091,8 @@ static void draw_ghost_poses_keys(Base *base) if (G.vd->zbuf) glEnable(GL_DEPTH_TEST); ghost_poses_tag_unselected(ob, 1); /* unhide unselected bones if need be */ - free_pose_channels(posen); BLI_freelistN(&keys); - MEM_freeN(posen); + free_pose(posen); /* restore */ CFRA= cfrao; @@ -2193,8 +2191,7 @@ static void draw_ghost_poses(Base *base) if (G.vd->zbuf) glEnable(GL_DEPTH_TEST); ghost_poses_tag_unselected(ob, 1); /* unhide unselected bones if need be */ - free_pose_channels(posen); - MEM_freeN(posen); + free_pose(posen); /* restore */ CFRA= cfrao; diff --git a/source/blender/src/drawipo.c b/source/blender/src/drawipo.c index d5040bf0a51..6a1744dccac 100644 --- a/source/blender/src/drawipo.c +++ b/source/blender/src/drawipo.c @@ -65,6 +65,7 @@ #include "BKE_global.h" #include "BKE_ipo.h" #include "BKE_key.h" +#include "BKE_object.h" #include "BKE_utildefines.h" #include "BIF_cursors.h"