diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index fb527051a0d..2c573faeb87 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -78,7 +78,9 @@ void unlink_armature(struct bArmature *arm); void free_armature(struct bArmature *arm); void make_local_armature(struct bArmature *arm); struct bArmature *copy_armature(struct bArmature *arm); + void bone_flip_name (char *name, int strip_number); +void bone_autoside_name (char *name, int strip_number, short axis, float head, float tail); struct bArmature *get_armature (struct Object *ob); struct Bone *get_named_bone (struct bArmature *arm, const char *name); diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index f4da821e3ea..62315412aba 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -30,6 +30,8 @@ #include #include #include +#include + #include "MEM_guardedalloc.h" #include "nla.h" @@ -354,6 +356,88 @@ void bone_flip_name (char *name, int strip_number) sprintf (name, "%s%s%s%s", prefix, replace, suffix, number); } +/* Finds the best possible extension to the name on a particular axis. (For renaming, check for unique names afterwards) + * This assumes that bone names are at most 32 chars long! + * strip_number: removes number extensions (TODO: not used) + * axis: the axis to name on + * head/tail: the head/tail co-ordinate of the bone on the specified axis + */ +void bone_autoside_name (char *name, int strip_number, short axis, float head, float tail) +{ + int len; + char basename[32]={""}; + char extension[3]={""}; + + len= strlen(name); + if (len == 0) return; + strcpy(basename, name); + + /* Figure out extension to append: + * - The extension to append is based upon the axis that we are working on. + * - If head happens to be on 0, then we must consider the tail position as well to decide + * which side the bone is on + * -> If tail is 0, then it's bone is considered to be on axis, so no extension should be added + * -> Otherwise, extension is added from perspective of object based on which side tail goes to + * - If head is non-zero, extension is added from perspective of object based on side head is on + */ + if (axis == 2) { + /* z-axis - vertical (top/bottom) */ + if (IS_EQ(head, 0)) { + if (tail < 0) + strcpy(extension, ".Bot"); + else if (tail > 0) + strcpy(extension, ".Top"); + } + else { + if (head < 0) + strcpy(extension, ".Bot"); + else + strcpy(extension, ".Top"); + } + } + else if (axis == 1) { + /* y-axis - depth (front/back) */ + if (IS_EQ(head, 0)) { + if (tail < 0) + strcpy(extension, ".Fr"); + else if (tail > 0) + strcpy(extension, ".Bk"); + } + else { + if (head < 0) + strcpy(extension, ".Fr"); + else + strcpy(extension, ".Bk"); + } + } + else { + /* x-axis - horizontal (left/right) */ + if (IS_EQ(head, 0)) { + if (tail < 0) + strcpy(extension, ".R"); + else if (tail > 0) + strcpy(extension, ".L"); + } + else { + if (head < 0) + strcpy(extension, ".R"); + else if (head > 0) + strcpy(extension, ".L"); + } + } + + /* Simple name truncation + * - truncate if there is an extension and it wouldn't be able to fit + * - otherwise, just append to end (TODO: this should really check if there was already a tag there, and remove it) + */ + if (extension[0]) { + if ((32 - len) < strlen(extension)) { + strncpy(name, basename, len-strlen(extension); + } + } + + sprintf(name, "%s%s", basename, extension); +} /* ************* B-Bone support ******************* */ diff --git a/source/blender/include/BIF_editarmature.h b/source/blender/include/BIF_editarmature.h index 8cf63a005cb..cc34cb58ae3 100644 --- a/source/blender/include/BIF_editarmature.h +++ b/source/blender/include/BIF_editarmature.h @@ -128,6 +128,7 @@ int bone_looper(struct Object *ob, struct Bone *bone, void *data, void undo_push_armature(char *name); void armature_bone_rename(struct bArmature *arm, char *oldname, char *newname); void armature_flip_names(void); +void armature_autoside_names(short axis); EditBone *armature_bone_get_mirrored(EditBone *ebo); void transform_armature_mirror_update(void); diff --git a/source/blender/include/BIF_poseobject.h b/source/blender/include/BIF_poseobject.h index f356c9d664c..3aa4413e9f9 100644 --- a/source/blender/include/BIF_poseobject.h +++ b/source/blender/include/BIF_poseobject.h @@ -73,6 +73,7 @@ void pose_recalculate_paths(struct Object *ob); void pose_clear_paths(struct Object *ob); void pose_flip_names(void); +void pose_autoside_names(short axis); void pose_activate_flipped_bone(void); void pose_movetolayer(void); void pose_relax(void); diff --git a/source/blender/src/editarmature.c b/source/blender/src/editarmature.c index 45711bc1cfa..763d9744064 100644 --- a/source/blender/src/editarmature.c +++ b/source/blender/src/editarmature.c @@ -3603,13 +3603,37 @@ void armature_flip_names(void) allqueue(REDRAWVIEW3D, 0); allqueue(REDRAWBUTSEDIT, 0); allqueue(REDRAWBUTSOBJECT, 0); - allqueue (REDRAWACTION, 0); + allqueue(REDRAWACTION, 0); allqueue(REDRAWOOPS, 0); BIF_undo_push("Flip names"); - } -/* context; editmode armature */ +/* context: edtimode armature */ +void armature_autoside_names(short axis) +{ + bArmature *arm= G.obedit->data; + EditBone *ebone; + char newname[32]; + + for (ebone = G.edbo.first; ebone; ebone=ebone->next) { + if (arm->layer & ebone->layer) { + if (ebone->flag & BONE_SELECTED) { + BLI_strncpy(newname, ebone->name, sizeof(newname)); + bone_autoside_name(newname, 1, axis, ebone->head[axis], ebone->tail[axis]); + armature_bone_rename(G.obedit->data, ebone->name, newname); + } + } + } + + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWBUTSEDIT, 0); + allqueue(REDRAWBUTSOBJECT, 0); + allqueue(REDRAWACTION, 0); + allqueue(REDRAWOOPS, 0); + BIF_undo_push("Auto-side name"); +} + +/* context: editmode armature */ EditBone *armature_bone_get_mirrored(EditBone *ebo) { EditBone *eboflip= NULL; diff --git a/source/blender/src/editobject.c b/source/blender/src/editobject.c index 4e90fbac5ac..ac631cf2a5c 100644 --- a/source/blender/src/editobject.c +++ b/source/blender/src/editobject.c @@ -2548,7 +2548,7 @@ void special_editmenu(void) DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); } else if(G.obedit->type==OB_ARMATURE) { - nr= pupmenu("Specials%t|Subdivide %x1|Subdivide Multi%x2|Flip Left-Right Names%x3"); + nr= pupmenu("Specials%t|Subdivide %x1|Subdivide Multi%x2|Flip Left-Right Names%x3|%l|AutoName Left-Right%x4|AutoName Front-Back%x5|AutoName Top-Bottom%x6"); if(nr==1) subdivide_armature(1); if(nr==2) { @@ -2558,6 +2558,9 @@ void special_editmenu(void) } else if(nr==3) armature_flip_names(); + else if(ELEM3(nr, 4, 5, 6)) { + armature_autoside_names(nr-4); + } } else if(G.obedit->type==OB_LATTICE) { static float weight= 1.0f; diff --git a/source/blender/src/poseobject.c b/source/blender/src/poseobject.c index 42640465e12..e187530d25f 100644 --- a/source/blender/src/poseobject.c +++ b/source/blender/src/poseobject.c @@ -490,7 +490,7 @@ void pose_special_editmenu(void) if(!ob && !ob->pose) return; if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return; - nr= pupmenu("Specials%t|Select Constraint Target%x1|Flip Left-Right Names%x2|Calculate Paths%x3|Clear Paths%x4|Clear User Transform %x5|Relax Pose %x6"); + nr= pupmenu("Specials%t|Select Constraint Target%x1|Flip Left-Right Names%x2|Calculate Paths%x3|Clear Paths%x4|Clear User Transform %x5|Relax Pose %x6|%l|AutoName Left-Right%x7|AutoName Front-Back%x8|AutoName Top-Bottom%x9"); if(nr==1) { pose_select_constraint_target(); } @@ -511,6 +511,9 @@ void pose_special_editmenu(void) else if(nr==6) { pose_relax(); } + else if(ELEM3(nr, 7, 8, 9)) { + pose_autoside_names(nr-7); + } } void pose_add_IK(void) @@ -1154,7 +1157,39 @@ void pose_flip_names(void) allqueue (REDRAWACTION, 0); allqueue(REDRAWOOPS, 0); BIF_undo_push("Flip names"); +} + +/* context active object */ +void pose_autoside_names(short axis) +{ + Object *ob= OBACT; + bArmature *arm= ob->data; + bPoseChannel *pchan; + char newname[32]; + /* paranoia checks */ + if (ELEM(NULL, ob, ob->pose)) return; + if (ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return; + + if (pose_has_protected_selected(ob, 0)) + return; + + for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { + if(arm->layer & pchan->bone->layer) { + if(pchan->bone->flag & (BONE_ACTIVE|BONE_SELECTED)) { + BLI_strncpy(newname, pchan->name, sizeof(newname)); + bone_autoside_name(newname, 1, axis, pchan->bone->head[axis], pchan->bone->tail[axis]); + armature_bone_rename(ob->data, pchan->name, newname); + } + } + } + + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWBUTSEDIT, 0); + allqueue(REDRAWBUTSOBJECT, 0); + allqueue (REDRAWACTION, 0); + allqueue(REDRAWOOPS, 0); + BIF_undo_push("Flip names"); } /* context active object, or weightpainted object with armature in posemode */ diff --git a/source/blender/src/space.c b/source/blender/src/space.c index b1d274d670e..e90c2e99d0a 100644 --- a/source/blender/src/space.c +++ b/source/blender/src/space.c @@ -3155,6 +3155,9 @@ static void info_user_theme_colsets_buts(uiBlock *block, short y1, short y2, sho /* Extra 'Options' */ uiDefButBitS(block, TOG, TH_WIRECOLOR_CONSTCOLS, B_UPDATE_THEME, "Use 'Constraint' Colouring", 885,y2,200,20, &col_set->flag, 0, 0, 0, 0, "Allow the use of colors indicating constraints/keyed status"); + + /* 'Debug' Tools */ + // TODO... dump current colours } static void info_user_themebuts(uiBlock *block, short y1, short y2, short y3, short y4)