== Action/Bone Groups - Ctrl-G Hotkey + Bugfixes ==
New Stuff: * When in PoseMode, the Ctrl-G hotkey now presents a menu with options for manipulating Bone Groups. There are options to add/remove all selected bones from a certain group. TODO - add appropriate entries to menus Bugfixes: * Renaming Bone-Groups in the buttons panel could cause segfaults or memory corruption. Wrong maximum-length for button used here (it's far too easy to miss). * In the Action Editor, (re)grouping channels didn't take into account whether a group was expanded or not. This meant that selected channels from inside a collapsed group got added to the new group too.
This commit is contained in:
@@ -35,6 +35,7 @@
|
|||||||
|
|
||||||
|
|
||||||
struct Object;
|
struct Object;
|
||||||
|
struct bPose;
|
||||||
struct bPoseChannel;
|
struct bPoseChannel;
|
||||||
|
|
||||||
void enter_posemode(void);
|
void enter_posemode(void);
|
||||||
@@ -60,6 +61,13 @@ void paste_posebuf (int flip);
|
|||||||
|
|
||||||
void pose_adds_vgroups(struct Object *meshobj, int heatweights);
|
void pose_adds_vgroups(struct Object *meshobj, int heatweights);
|
||||||
|
|
||||||
|
void pose_add_posegroup(void);
|
||||||
|
void pose_remove_posegroup(void);
|
||||||
|
char *build_posegroups_menustr(struct bPose *pose, short for_pupmenu);
|
||||||
|
void pose_assign_to_posegroup(void);
|
||||||
|
void pose_remove_from_posegroup(void);
|
||||||
|
void pgroup_operation_with_menu(void);
|
||||||
|
|
||||||
void pose_calculate_path(struct Object *ob);
|
void pose_calculate_path(struct Object *ob);
|
||||||
void pose_recalculate_paths(struct Object *ob);
|
void pose_recalculate_paths(struct Object *ob);
|
||||||
void pose_clear_paths(struct Object *ob);
|
void pose_clear_paths(struct Object *ob);
|
||||||
|
|||||||
@@ -3854,44 +3854,17 @@ void do_armbuts(unsigned short event)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// TODO: make these pose-group options proper tools in poseobject.c
|
|
||||||
case B_POSEGRP_RECALC:
|
case B_POSEGRP_RECALC:
|
||||||
allqueue(REDRAWVIEW3D, 0);
|
allqueue(REDRAWVIEW3D, 0);
|
||||||
allqueue(REDRAWBUTSEDIT, 0);
|
allqueue(REDRAWBUTSEDIT, 0);
|
||||||
break;
|
break;
|
||||||
case B_POSEGRP_ADD:
|
case B_POSEGRP_ADD:
|
||||||
if (ob && ob->pose) {
|
if (ob && ob->pose)
|
||||||
bPose *pose= ob->pose;
|
pose_add_posegroup();
|
||||||
bActionGroup *grp;
|
|
||||||
|
|
||||||
grp= MEM_callocN(sizeof(bActionGroup), "PoseGroup");
|
|
||||||
strcpy(grp->name, "Group");
|
|
||||||
BLI_addtail(&pose->agroups, grp);
|
|
||||||
BLI_uniquename(&pose->agroups, grp, "Group", offsetof(bActionGroup, name), 32);
|
|
||||||
|
|
||||||
pose->active_group= BLI_countlist(&pose->agroups);
|
|
||||||
|
|
||||||
BIF_undo_push("Add Pose Group");
|
|
||||||
allqueue(REDRAWBUTSEDIT, 0);
|
|
||||||
allqueue(REDRAWVIEW3D, 0);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case B_POSEGRP_REMOVE:
|
case B_POSEGRP_REMOVE:
|
||||||
if (ob && ob->pose && ob->pose->active_group) {
|
if (ob && ob->pose)
|
||||||
bPose *pose= ob->pose;
|
pose_remove_posegroup();
|
||||||
bActionGroup *grp= NULL;
|
|
||||||
|
|
||||||
// FIXME: make sure all that referenced it get reset
|
|
||||||
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4323,37 +4296,6 @@ static int ob_arm_bone_pchan_lock(Object *ob, bArmature *arm, Bone *bone, bPoseC
|
|||||||
return 0;
|
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)
|
static void editing_panel_pose_bones(Object *ob, bArmature *arm)
|
||||||
{
|
{
|
||||||
uiBlock *block;
|
uiBlock *block;
|
||||||
@@ -4388,7 +4330,7 @@ static void editing_panel_pose_bones(Object *ob, bArmature *arm)
|
|||||||
uiButSetCompleteFunc(but, autocomplete_bone, (void *)ob);
|
uiButSetCompleteFunc(but, autocomplete_bone, (void *)ob);
|
||||||
|
|
||||||
/* Bone custom drawing */
|
/* Bone custom drawing */
|
||||||
menustr= build_posegroups_menustr(ob->pose);
|
menustr= build_posegroups_menustr(ob->pose, 0);
|
||||||
uiDefButS(block, MENU,REDRAWVIEW3D, menustr, 107,by,105,19, &pchan->agrp_index, 0, 0.0, 0.0, 0.0, "Change the Pose Group this Bone belongs to");
|
uiDefButS(block, MENU,REDRAWVIEW3D, menustr, 107,by,105,19, &pchan->agrp_index, 0, 0.0, 0.0, 0.0, "Change the Pose Group this Bone belongs to");
|
||||||
MEM_freeN(menustr);
|
MEM_freeN(menustr);
|
||||||
|
|
||||||
@@ -5211,7 +5153,7 @@ static void editing_panel_links(Object *ob)
|
|||||||
uiBlockBeginAlign(block);
|
uiBlockBeginAlign(block);
|
||||||
/* currently 'active' group - browse groups */
|
/* currently 'active' group - browse groups */
|
||||||
count= BLI_countlist(&pose->agroups);
|
count= BLI_countlist(&pose->agroups);
|
||||||
menustr= build_posegroups_menustr(pose);
|
menustr= build_posegroups_menustr(pose, 0);
|
||||||
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.");
|
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);
|
MEM_freeN(menustr);
|
||||||
|
|
||||||
@@ -5220,7 +5162,7 @@ static void editing_panel_links(Object *ob)
|
|||||||
bActionGroup *grp= (bActionGroup *)BLI_findlink(&pose->agroups, pose->active_group-1);
|
bActionGroup *grp= (bActionGroup *)BLI_findlink(&pose->agroups, pose->active_group-1);
|
||||||
|
|
||||||
/* active group */
|
/* active group */
|
||||||
but= 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.");
|
but= uiDefBut(block, TEX, REDRAWBUTSEDIT,"", xco+18,85,140-18-20,20, grp->name, 0, 31, 0, 0, "Displays current Pose Group name. Click to change.");
|
||||||
uiButSetFunc(but, verify_posegroup_groupname, pose, grp);
|
uiButSetFunc(but, verify_posegroup_groupname, pose, grp);
|
||||||
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");
|
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");
|
||||||
|
|
||||||
|
|||||||
@@ -981,12 +981,14 @@ void action_groups_group (short add_group)
|
|||||||
|
|
||||||
/* make sure not already in new-group */
|
/* make sure not already in new-group */
|
||||||
if (achan->grp != agrp) {
|
if (achan->grp != agrp) {
|
||||||
if (VISIBLE_ACHAN(achan) && SEL_ACHAN(achan)) {
|
if ((achan->grp) && (EXPANDED_AGRP(achan->grp))) {
|
||||||
/* unlink from everything else */
|
if (VISIBLE_ACHAN(achan) && SEL_ACHAN(achan)) {
|
||||||
action_groups_removeachan(act, achan);
|
/* unlink from everything else */
|
||||||
|
action_groups_removeachan(act, achan);
|
||||||
/* add to end of group's channels */
|
|
||||||
action_groups_addachan(act, agrp, achan);
|
/* add to end of group's channels */
|
||||||
|
action_groups_addachan(act, agrp, achan);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
|
|
||||||
#include "BLI_arithb.h"
|
#include "BLI_arithb.h"
|
||||||
#include "BLI_blenlib.h"
|
#include "BLI_blenlib.h"
|
||||||
|
#include "BLI_dynstr.h"
|
||||||
|
|
||||||
#include "DNA_action_types.h"
|
#include "DNA_action_types.h"
|
||||||
#include "DNA_armature_types.h"
|
#include "DNA_armature_types.h"
|
||||||
@@ -910,10 +911,213 @@ void pose_adds_vgroups(Object *meshobj, int heatweights)
|
|||||||
/* ********************************************** */
|
/* ********************************************** */
|
||||||
|
|
||||||
/* adds a new pose-group */
|
/* adds a new pose-group */
|
||||||
// TODO...
|
|
||||||
void pose_add_posegroup ()
|
void pose_add_posegroup ()
|
||||||
{
|
{
|
||||||
|
Object *ob= OBACT;
|
||||||
|
bPose *pose= (ob) ? ob->pose : NULL;
|
||||||
|
bActionGroup *grp;
|
||||||
|
|
||||||
|
if (ELEM(NULL, ob, ob->pose))
|
||||||
|
return;
|
||||||
|
|
||||||
|
grp= MEM_callocN(sizeof(bActionGroup), "PoseGroup");
|
||||||
|
strcpy(grp->name, "Group");
|
||||||
|
BLI_addtail(&pose->agroups, grp);
|
||||||
|
BLI_uniquename(&pose->agroups, grp, "Group", offsetof(bActionGroup, name), 32);
|
||||||
|
|
||||||
|
pose->active_group= BLI_countlist(&pose->agroups);
|
||||||
|
|
||||||
|
BIF_undo_push("Add Bone Group");
|
||||||
|
|
||||||
|
allqueue(REDRAWBUTSEDIT, 0);
|
||||||
|
allqueue(REDRAWVIEW3D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove the active bone-group */
|
||||||
|
void pose_remove_posegroup ()
|
||||||
|
{
|
||||||
|
Object *ob= OBACT;
|
||||||
|
bPose *pose= (ob) ? ob->pose : NULL;
|
||||||
|
bActionGroup *grp = NULL;
|
||||||
|
bPoseChannel *pchan;
|
||||||
|
|
||||||
|
/* sanity checks */
|
||||||
|
if (ELEM(NULL, ob, pose))
|
||||||
|
return;
|
||||||
|
if (pose->active_group <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* get group to remove */
|
||||||
|
grp= BLI_findlink(&pose->agroups, pose->active_group-1);
|
||||||
|
if (grp) {
|
||||||
|
/* firstly, make sure nothing references it */
|
||||||
|
for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) {
|
||||||
|
if (pchan->agrp_index == pose->active_group)
|
||||||
|
pchan->agrp_index= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now, remove it from the pose */
|
||||||
|
BLI_freelinkN(&pose->agroups, grp);
|
||||||
|
pose->active_group= 0;
|
||||||
|
|
||||||
|
BIF_undo_push("Remove Bone Group");
|
||||||
|
}
|
||||||
|
|
||||||
|
allqueue(REDRAWBUTSEDIT, 0);
|
||||||
|
allqueue(REDRAWVIEW3D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *build_posegroups_menustr (bPose *pose, short for_pupmenu)
|
||||||
|
{
|
||||||
|
DynStr *pupds= BLI_dynstr_new();
|
||||||
|
bActionGroup *grp;
|
||||||
|
char *str;
|
||||||
|
char buf[16];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* add title first (and the "none" entry) */
|
||||||
|
BLI_dynstr_append(pupds, "Bone Group%t|");
|
||||||
|
if (for_pupmenu)
|
||||||
|
BLI_dynstr_append(pupds, "Add New%x0|");
|
||||||
|
else
|
||||||
|
BLI_dynstr_append(pupds, "BG: [None]%x0|");
|
||||||
|
|
||||||
|
/* loop through markers, adding them */
|
||||||
|
for (grp= pose->agroups.first, i=1; grp; grp=grp->next, i++) {
|
||||||
|
if (for_pupmenu == 0)
|
||||||
|
BLI_dynstr_append(pupds, "BG: ");
|
||||||
|
BLI_dynstr_append(pupds, grp->name);
|
||||||
|
|
||||||
|
sprintf(buf, "%%x%d", i);
|
||||||
|
BLI_dynstr_append(pupds, buf);
|
||||||
|
|
||||||
|
if (grp->next)
|
||||||
|
BLI_dynstr_append(pupds, "|");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* convert to normal MEM_malloc'd string */
|
||||||
|
str= BLI_dynstr_get_cstring(pupds);
|
||||||
|
BLI_dynstr_free(pupds);
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assign selected pchans to the bone group that the user selects */
|
||||||
|
void pose_assign_to_posegroup ()
|
||||||
|
{
|
||||||
|
Object *ob= OBACT;
|
||||||
|
bArmature *arm= (ob) ? ob->data : NULL;
|
||||||
|
bPose *pose= (ob) ? ob->pose : NULL;
|
||||||
|
bPoseChannel *pchan;
|
||||||
|
char *menustr;
|
||||||
|
int nr;
|
||||||
|
short done= 0;
|
||||||
|
|
||||||
|
/* sanity checks */
|
||||||
|
if (ELEM3(NULL, ob, pose, arm))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* get group to affect */
|
||||||
|
menustr= build_posegroups_menustr(pose, 1);
|
||||||
|
nr= pupmenu(menustr);
|
||||||
|
MEM_freeN(menustr);
|
||||||
|
|
||||||
|
if (nr < 0)
|
||||||
|
return;
|
||||||
|
else if (nr == 0) {
|
||||||
|
/* add new - note: this does an undo push and sets active group */
|
||||||
|
pose_add_posegroup();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pose->active_group= nr;
|
||||||
|
|
||||||
|
/* add selected bones to group then */
|
||||||
|
for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) {
|
||||||
|
if ((pchan->bone->flag & BONE_SELECTED) && (pchan->bone->layer & arm->layer)) {
|
||||||
|
pchan->agrp_index= pose->active_group;
|
||||||
|
done= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (done)
|
||||||
|
BIF_undo_push("Add Bones To Group");
|
||||||
|
|
||||||
|
allqueue(REDRAWBUTSEDIT, 0);
|
||||||
|
allqueue(REDRAWVIEW3D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove selected pchans from their bone groups */
|
||||||
|
void pose_remove_from_posegroups ()
|
||||||
|
{
|
||||||
|
Object *ob= OBACT;
|
||||||
|
bArmature *arm= (ob) ? ob->data : NULL;
|
||||||
|
bPose *pose= (ob) ? ob->pose : NULL;
|
||||||
|
bPoseChannel *pchan;
|
||||||
|
short done= 0;
|
||||||
|
|
||||||
|
/* sanity checks */
|
||||||
|
if (ELEM3(NULL, ob, pose, arm))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* remove selected bones from their groups */
|
||||||
|
for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) {
|
||||||
|
if ((pchan->bone->flag & BONE_SELECTED) && (pchan->bone->layer & arm->layer)) {
|
||||||
|
if (pchan->agrp_index) {
|
||||||
|
pchan->agrp_index= 0;
|
||||||
|
done= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (done)
|
||||||
|
BIF_undo_push("Remove Bones From Groups");
|
||||||
|
|
||||||
|
allqueue(REDRAWBUTSEDIT, 0);
|
||||||
|
allqueue(REDRAWVIEW3D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ctrl-G in 3D-View while in PoseMode */
|
||||||
|
void pgroup_operation_with_menu (void)
|
||||||
|
{
|
||||||
|
Object *ob= OBACT;
|
||||||
|
bArmature *arm= (ob) ? ob->data : NULL;
|
||||||
|
bPose *pose= (ob) ? ob->pose : NULL;
|
||||||
|
bPoseChannel *pchan= NULL;
|
||||||
|
int mode;
|
||||||
|
|
||||||
|
/* sanity checks */
|
||||||
|
if (ELEM3(NULL, ob, pose, arm))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* check that something is selected */
|
||||||
|
for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) {
|
||||||
|
if ((pchan->bone->flag & BONE_SELECTED) && (pchan->bone->layer & arm->layer))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (pchan == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* get mode of action */
|
||||||
|
if (pchan)
|
||||||
|
mode= pupmenu("Bone Groups%t|Add Selected to Group%x1|Add New Group%x2|Remove Selected From Groups%x3|Remove Active Group%x4");
|
||||||
|
else
|
||||||
|
mode= pupmenu("Bone Groups%t|Add New Group%x2|Remove Active Group%x4");
|
||||||
|
|
||||||
|
/* handle mode */
|
||||||
|
switch (mode) {
|
||||||
|
case 1:
|
||||||
|
pose_assign_to_posegroup();
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
pose_add_posegroup();
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
pose_remove_from_posegroups();
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
pose_remove_posegroup();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ********************************************** */
|
/* ********************************************** */
|
||||||
|
|||||||
@@ -1940,6 +1940,8 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
|
|||||||
if(ELEM(G.obedit->type, OB_MESH, OB_LATTICE))
|
if(ELEM(G.obedit->type, OB_MESH, OB_LATTICE))
|
||||||
vgroup_assign_with_menu();
|
vgroup_assign_with_menu();
|
||||||
}
|
}
|
||||||
|
else if(ob && (ob->flag & OB_POSEMODE))
|
||||||
|
pgroup_operation_with_menu();
|
||||||
else
|
else
|
||||||
group_operation_with_menu();
|
group_operation_with_menu();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user