2.5 - Context API access for Bones (EditMode and PoseMode)
authorJoshua Leung <aligorith@gmail.com>
Thu, 5 Feb 2009 03:28:07 +0000 (03:28 +0000)
committerJoshua Leung <aligorith@gmail.com>
Thu, 5 Feb 2009 03:28:07 +0000 (03:28 +0000)
* Added selected, selected+editable, and active to access EditBones for Armature Operators to use. These take into account X-Axis Mirror too, so there is really no need to check that sort of thing anymore in tools.

* Added a quick testing operator for verifying that these loops filter the data correctly. I've dumped this in armature_ops.c for now. It can be activated using the TKEY hotkey in Armature EditMode only. This should be removed once we have a few more functional tools.

* Ported over cleaned up roll-calculation tools from AnimSys2
* Removed a few ugly stubs from posemode code

source/blender/blenkernel/BKE_context.h
source/blender/blenkernel/intern/context.c
source/blender/editors/armature/armature_ops.c
source/blender/editors/armature/editarmature.c
source/blender/editors/armature/poseobject.c
source/blender/editors/space_view3d/space_view3d.c
source/blender/editors/transform/transform_conversions.c

index c489aba33266a3c68e6d091534bc65da58e650db..5af97a7d8d5e9aff4f984951c3f95ee3a7097498 100644 (file)
@@ -51,6 +51,8 @@ struct StructRNA;
 struct ToolSettings;
 struct Image;
 struct ImBuf;
+struct EditBone;
+struct bPoseChannel;
 struct wmWindow;
 struct wmWindowManager;
 
@@ -81,7 +83,14 @@ enum {
        CTX_DATA_EDIT_IMAGE,
        CTX_DATA_EDIT_IMAGE_BUFFER,
 
-       CTX_DATA_SELECTED_NODES
+       CTX_DATA_SELECTED_NODES,
+       
+       CTX_DATA_SELECTED_BONES,
+       CTX_DATA_SELECTED_EDITABLE_BONES,
+       CTX_DATA_SELECTED_PCHANS,
+       
+       CTX_DATA_ACTIVE_BONE,
+       CTX_DATA_ACTIVE_PCHAN,
 };
 
 typedef int bContextDataMember;
@@ -185,6 +194,13 @@ struct ImBuf *CTX_data_edit_image_buffer(const bContext *C);
 
 int CTX_data_selected_nodes(const bContext *C, ListBase *list);
 
+struct EditBone *CTX_data_active_bone(const bContext *C);
+int CTX_data_selected_bones(const bContext *C, ListBase *list);
+int CTX_data_selected_editable_bones(const bContext *C, ListBase *list);
+
+struct bPoseChannel *CTX_data_active_pchan(const bContext *C);
+int CTX_data_selected_pchans(const bContext *C, ListBase *list);
+
 /* Data Evaluation Context */
 
 float CTX_eval_frame(const bContext *C);
index ccdbea87d877d5d30138a0c8b0923337c069b446..15e552617a8f58d6a606f6af36abf342c00aaff8 100644 (file)
@@ -441,6 +441,31 @@ struct ImBuf *CTX_data_edit_image_buffer(const bContext *C)
        return ctx_data_pointer_get(C, CTX_DATA_EDIT_IMAGE_BUFFER);
 }
 
+struct EditBone *CTX_data_active_bone(const bContext *C)
+{
+       return ctx_data_pointer_get(C, CTX_DATA_ACTIVE_BONE);
+}
+
+int CTX_data_selected_bones(const bContext *C, ListBase *list)
+{
+       return ctx_data_collection_get(C, CTX_DATA_SELECTED_BONES, list);
+}
+
+int CTX_data_selected_editable_bones(const bContext *C, ListBase *list)
+{
+       return ctx_data_collection_get(C, CTX_DATA_SELECTED_EDITABLE_BONES, list);
+}
+
+struct bPoseChannel *CTX_data_active_pchan(const bContext *C)
+{
+       return ctx_data_pointer_get(C, CTX_DATA_ACTIVE_PCHAN);
+}
+
+int CTX_data_selected_pchans(const bContext *C, ListBase *list)
+{
+       return ctx_data_collection_get(C, CTX_DATA_SELECTED_PCHANS, list);
+}
+
 /* data evaluation */
 
 float CTX_eval_frame(const bContext *C)
index eaa8207bc116f060c3073dba4a04a56785edd520..e8f75bd4440448b5488c0a437af497ad12ec7786 100644 (file)
 
 #include "armature_intern.h"
 
+/* ************************** quick tests **********************************/
+
+/*  XXX This is a quick test operator to print names of all EditBones in context
+ *             that should be removed once tool coding starts...
+ */
+
+static int armature_test_exec (bContext *C, wmOperator *op)
+{
+       printf("EditMode Armature Test: \n");
+       
+       printf("\tSelected Bones \n");
+       CTX_DATA_BEGIN(C, EditBone*, ebone, selected_bones)
+       {
+               printf("\t\tEditBone '%s' \n", ebone->name);
+       }
+       CTX_DATA_END;
+       
+       printf("\tEditable Bones \n");
+       CTX_DATA_BEGIN(C, EditBone*, ebone, selected_editable_bones) 
+       {
+               printf("\t\tEditBone '%s' \n", ebone->name);
+       }
+       CTX_DATA_END;
+       
+       printf("\tActive Bone \n");
+       {
+               EditBone *ebone= CTX_data_active_bone(C);
+               if (ebone) printf("\t\tEditBone '%s' \n");
+               else printf("\t\t<None> \n");
+       }
+       
+       return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_test(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Test Context";
+       ot->idname= "ARMATURE_OT_test";
+       
+       /* api callbacks */
+       ot->exec= armature_test_exec;
+}
 
 /* ************************** registration **********************************/
 
@@ -66,16 +109,23 @@ void ED_operatortypes_armature(void)
 {
        WM_operatortype_append(POSE_OT_hide);
        WM_operatortype_append(POSE_OT_reveil);
+       
+       WM_operatortype_append(ARMATURE_OT_test); // XXX temp test for context iterators... to be removed
 }
 
 void ED_keymap_armature(wmWindowManager *wm)
 {
-       ListBase *keymap= WM_keymap_listbase(wm, "Armature", 0, 0);
+       ListBase *keymap;
        wmKeymapItem *kmi;
        
+       /* Armature ------------------------ */
+       keymap= WM_keymap_listbase(wm, "Armature", 0, 0);
+       
        /* only set in editmode armature, by space_view3d listener */
 //     WM_keymap_add_item(keymap, "ARMATURE_OT_hide", HKEY, KM_PRESS, 0, 0);
-
+       WM_keymap_add_item(keymap, "ARMATURE_OT_test", TKEY, KM_PRESS, 0, 0);  // XXX temp test for context iterators... to be removed
+       
+       /* Pose ------------------------ */
        /* only set in posemode, by space_view3d listener */
        keymap= WM_keymap_listbase(wm, "Pose", 0, 0);
        
index 631f6ce39dfc4ec142b6098b881a1a1fdb7129d3..d083dbec103887c06962754d1d7033062a105a99 100644 (file)
@@ -1844,20 +1844,97 @@ float ED_rollBoneToVector(EditBone *bone, float new_up_axis[3])
        return roll;
 }
 
+
+/* Set roll value for given bone -> Z-Axis Point up (original method) */
+void auto_align_ebone_zaxisup(Scene *scene, View3D *v3d, EditBone *ebone)
+{
+       float   delta[3], curmat[3][3];
+       float   xaxis[3]={1.0f, 0.0f, 0.0f}, yaxis[3], zaxis[3]={0.0f, 0.0f, 1.0f};
+       float   targetmat[3][3], imat[3][3], diffmat[3][3];
+       
+       /* Find the current bone matrix */
+       VecSubf(delta, ebone->tail, ebone->head);
+       vec_roll_to_mat3(delta, 0.0f, curmat);
+       
+       /* Make new matrix based on y axis & z-up */
+       VECCOPY(yaxis, curmat[1]);
+       
+       Mat3One(targetmat);
+       VECCOPY(targetmat[0], xaxis);
+       VECCOPY(targetmat[1], yaxis);
+       VECCOPY(targetmat[2], zaxis);
+       Mat3Ortho(targetmat);
+       
+       /* Find the difference between the two matrices */
+       Mat3Inv(imat, targetmat);
+       Mat3MulMat3(diffmat, imat, curmat);
+       
+       // old-method... let's see if using mat3_to_vec_roll is more accurate
+       //ebone->roll = atan2(diffmat[2][0], diffmat[2][2]);  
+       mat3_to_vec_roll(diffmat, delta, &ebone->roll);
+}
+
+/* Set roll value for given bone -> Z-Axis point towards cursor */
+void auto_align_ebone_tocursor(Scene *scene, View3D *v3d, EditBone *ebone)
+{
+       Object *obedit= scene->obedit; // XXX get from context
+       float   *cursor= give_cursor(scene, v3d);
+       float   delta[3], curmat[3][3];
+       float   mat[4][4], tmat[4][4], imat[4][4];
+       float   rmat[4][4], rot[3];
+       float   vec[3];
+       
+       /* find the current bone matrix as a 4x4 matrix (in Armature Space) */
+       VecSubf(delta, ebone->tail, ebone->head);
+       vec_roll_to_mat3(delta, ebone->roll, curmat);
+       Mat4CpyMat3(mat, curmat);
+       VECCOPY(mat[3], ebone->head);
+       
+       /* multiply bone-matrix by object matrix (so that bone-matrix is in WorldSpace) */
+       Mat4MulMat4(tmat, mat, obedit->obmat);
+       Mat4Invert(imat, tmat);
+       
+       /* find position of cursor relative to bone */
+       VecMat4MulVecfl(vec, imat, cursor);
+       
+       /* check that cursor is in usable position */
+       if ((IS_EQ(vec[0], 0)==0) && (IS_EQ(vec[2], 0)==0)) {
+               /* Compute a rotation matrix around y */
+               rot[1] = atan2(vec[0], vec[2]);
+               rot[0] = rot[2] = 0.0f;
+               EulToMat4(rot, rmat);
+               
+               /* Multiply the bone matrix by rotation matrix. This should be new bone-matrix */
+               Mat4MulMat4(tmat, rmat, mat);
+               Mat3CpyMat4(curmat, tmat);
+               
+               /* Now convert from new bone-matrix, back to a roll value (in radians) */
+               mat3_to_vec_roll(curmat, delta, &ebone->roll);
+       }
+}
+
 /* Sets the roll value of selected bones, depending on the mode
  *     mode == 0: their z-axes point upwards 
  *     mode == 1: their z-axes point towards 3d-cursor
  */
 void auto_align_armature(Scene *scene, View3D *v3d, short mode)
 {
-       Object *obedit= scene->obedit; // XXX get from context
+       Object *obedit= scene->obedit;
        bArmature *arm= obedit->data;
        EditBone *ebone;
        EditBone *flipbone = NULL;
-       float   delta[3];
-       float   curmat[3][3];
-       float   *cursor= give_cursor(scene, v3d);
-               
+       void (*roll_func)(Scene *, View3D *, EditBone *) = NULL;
+       
+       /* specific method used to calculate roll depends on mode */
+       switch (mode) {
+               case 1:  /* Z-Axis point towards cursor */
+                       roll_func= auto_align_ebone_tocursor;
+                       break;
+               default: /* Z-Axis Point Up */
+                       roll_func= auto_align_ebone_zaxisup;
+                       break;
+       }
+       
        for (ebone = arm->edbo->first; ebone; ebone=ebone->next) {
                if (EBONE_VISIBLE(arm, ebone)) {
                        if (arm->flag & ARM_MIRROR_EDIT)
@@ -1866,65 +1943,8 @@ void auto_align_armature(Scene *scene, View3D *v3d, short mode)
                        if ((ebone->flag & BONE_SELECTED) || 
                                (flipbone && (flipbone->flag & BONE_SELECTED))) 
                        {
-                               /* specific method used to calculate roll depends on mode */
-                               if (mode == 1) {
-                                       /* Z-Axis point towards cursor */
-                                       float   mat[4][4], tmat[4][4], imat[4][4];
-                                       float   rmat[4][4], rot[3];
-                                       float   vec[3];
-                                       
-                                       /* find the current bone matrix as a 4x4 matrix (in Armature Space) */
-                                       VecSubf(delta, ebone->tail, ebone->head);
-                                       vec_roll_to_mat3(delta, ebone->roll, curmat);
-                                       Mat4CpyMat3(mat, curmat);
-                                       VECCOPY(mat[3], ebone->head);
-                                       
-                                       /* multiply bone-matrix by object matrix (so that bone-matrix is in WorldSpace) */
-                                       Mat4MulMat4(tmat, mat, obedit->obmat);
-                                       Mat4Invert(imat, tmat);
-                                       
-                                       /* find position of cursor relative to bone */
-                                       VecMat4MulVecfl(vec, imat, cursor);
-                                       
-                                       /* check that cursor is in usable position */
-                                       if ((IS_EQ(vec[0], 0)==0) && (IS_EQ(vec[2], 0)==0)) {
-                                               /* Compute a rotation matrix around y */
-                                               rot[1] = atan2(vec[0], vec[2]);
-                                               rot[0] = rot[2] = 0.0f;
-                                               EulToMat4(rot, rmat);
-                                               
-                                               /* Multiply the bone matrix by rotation matrix. This should be new bone-matrix */
-                                               Mat4MulMat4(tmat, rmat, mat);
-                                               Mat3CpyMat4(curmat, tmat);
-                                               
-                                               /* Now convert from new bone-matrix, back to a roll value (in radians) */
-                                               mat3_to_vec_roll(curmat, delta, &ebone->roll);
-                                       }
-                               }
-                               else { 
-                                       /* Z-Axis Point Up */
-                                       float   xaxis[3]={1.0, 0.0, 0.0}, yaxis[3], zaxis[3]={0.0, 0.0, 1.0};
-                                       float   targetmat[3][3], imat[3][3], diffmat[3][3];
-                                       
-                                       /* Find the current bone matrix */
-                                       VecSubf(delta, ebone->tail, ebone->head);
-                                       vec_roll_to_mat3(delta, 0.0, curmat);
-                                       
-                                       /* Make new matrix based on y axis & z-up */
-                                       VECCOPY (yaxis, curmat[1]);
-                                       
-                                       Mat3One(targetmat);
-                                       VECCOPY (targetmat[0], xaxis);
-                                       VECCOPY (targetmat[1], yaxis);
-                                       VECCOPY (targetmat[2], zaxis);
-                                       Mat3Ortho(targetmat);
-                                       
-                                       /* Find the difference between the two matrices */
-                                       Mat3Inv(imat, targetmat);
-                                       Mat3MulMat3(diffmat, imat, curmat);
-                                       
-                                       ebone->roll = atan2(diffmat[2][0], diffmat[2][2]);
-                               }                               
+                               /* roll func is a callback which assumes that all is well */
+                               roll_func(scene, v3d, ebone);                   
                        }
                }
        }
@@ -3539,6 +3559,7 @@ static int clear_active_flag(Object *ob, Bone *bone, void *data)
 }
 
 
+// XXX bone_looper is only to be used when we want to access settings (i.e. editability/visibility/selected) that context doesn't offer 
 static int bone_looper(Object *ob, Bone *bone, void *data,
                                int (*bone_func)(Object *, Bone *, void *)) 
 {
index bb883c5a98d3273f02ce1d32adb057b9aaa06926..0771806a4a2ccdaa652f3689695ba102b84de4ec 100644 (file)
@@ -91,11 +91,10 @@ static void error() {};
 static void BIF_undo_push() {}
 static void countall() {}
 static void add_constraint() {}
-static void select_actionchannel_by_name() {}
 static void autokeyframe_pose_cb_func() {}
 /* ************* XXX *************** */
 
-
+/* This function is used to indicate that a bone is selected and needs keyframes inserted */
 void set_pose_keys (Object *ob)
 {
        bArmature *arm= ob->data;
@@ -104,16 +103,15 @@ void set_pose_keys (Object *ob)
        if (ob->pose){
                for (chan=ob->pose->chanbase.first; chan; chan=chan->next){
                        Bone *bone= chan->bone;
-                       if(bone && (bone->flag & BONE_SELECTED) && (arm->layer & bone->layer)) {
-                               chan->flag |= POSE_KEY;         
-                       }
-                       else {
+                       if ((bone) && (bone->flag & BONE_SELECTED) && (arm->layer & bone->layer))
+                               chan->flag |= POSE_KEY; 
+                       else
                                chan->flag &= ~POSE_KEY;
-                       }
                }
        }
 }
 
+/* This function is used to process the necessary updates for */
 void ED_armature_enter_posemode(bContext *C, Base *base)
 {
        Object *ob= base->object;
@@ -472,9 +470,7 @@ void pose_select_hierarchy(Scene *scene, short direction, short add_to_sel)
                                                curbone->flag &= ~BONE_ACTIVE;
                                                pabone->flag |= (BONE_ACTIVE|BONE_SELECTED);
                                                
-                                               // XXX this is evil... this sort of stuff is to be handled in one go as a result of a notifier
-                                               select_actionchannel_by_name (ob->action, pchan->name, 0);
-                                               select_actionchannel_by_name (ob->action, pchan->parent->name, 1);
+                                               // XXX notifiers need to be sent to other editors to update
                                                break;
                                        }
                                } else { // BONE_SELECT_CHILD
@@ -488,9 +484,7 @@ void pose_select_hierarchy(Scene *scene, short direction, short add_to_sel)
                                                curbone->flag &= ~BONE_ACTIVE;
                                                chbone->flag |= (BONE_ACTIVE|BONE_SELECTED);
                                                
-                                               // XXX this is evil... this sort of stuff is to be handled in one go as a result of a notifier
-                                               select_actionchannel_by_name (ob->action, pchan->name, 0);
-                                               select_actionchannel_by_name (ob->action, pchan->child->name, 1);
+                                               // XXX notifiers need to be sent to other editors to update
                                                break;
                                        }
                                }
@@ -1339,8 +1333,7 @@ void pose_activate_flipped_bone(Scene *scene)
                                        DAG_object_flush_update(scene, OBACT, OB_RECALC_DATA);
                                }
                                
-                               // XXX this is evil... this sort of stuff is to be handled in one go as a result of a notifier
-                               select_actionchannel_by_name(ob->action, name, 1);
+                               // XXX notifiers need to be sent to other editors to update
                                
                        }                       
                }
index 3f47ec57a5076def8f52e46fb8d12825871d9399..cdc38879d56042f694da63887b072f09d6d67a04 100644 (file)
@@ -29,6 +29,8 @@
 #include <string.h>
 #include <stdio.h>
 
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
 #include "DNA_object_types.h"
 #include "DNA_space_types.h"
 #include "DNA_scene_types.h"
@@ -46,6 +48,7 @@
 #include "BKE_screen.h"
 #include "BKE_utildefines.h"
 
+#include "ED_armature.h"
 #include "ED_space_api.h"
 #include "ED_screen.h"
 
@@ -458,6 +461,89 @@ static int view3d_context(const bContext *C, bContextDataMember member, bContext
 
                return 1;
        }
+       else if(ELEM(member, CTX_DATA_SELECTED_BONES, CTX_DATA_SELECTED_EDITABLE_BONES)) {
+               Object *obedit= scene->obedit; // XXX get from context?
+               bArmature *arm= (obedit) ? obedit->data : NULL;
+               EditBone *ebone, *flipbone=NULL;
+               
+               if (arm && arm->edbo) {
+                       /* Attention: X-Axis Mirroring is also handled here... */
+                       for (ebone= arm->edbo->first; ebone; ebone= ebone->next) {
+                               /* first and foremost, bone must be visible */
+                               if (EBONE_VISIBLE(arm, ebone)) {
+                                       /* get 'x-axis mirror equivalent' bone if the X-Axis Mirroring option is enabled
+                                        * so that users of this data don't need to check for it themselves
+                                        */
+                                       if (arm->flag & ARM_MIRROR_EDIT)
+                                               flipbone = armature_bone_get_mirrored(arm->edbo, ebone);
+                                       
+                                       /* if we're filtering for editable too, use the check for that instead, as it has selection check too */
+                                       if (member == CTX_DATA_SELECTED_EDITABLE_BONES) {
+                                               /* only selected + editable */
+                                               if ( EBONE_EDITABLE(ebone) || 
+                                                        ((flipbone) && EBONE_EDITABLE(flipbone)) ) 
+                                               {
+                                                       CTX_data_list_add(result, ebone);
+                                               }
+                                       }
+                                       else {
+                                               /* only include if bone is selected */
+                                               if ( (ebone->flag & BONE_SELECTED) || 
+                                                        ((flipbone) && (flipbone->flag & BONE_SELECTED)) ) 
+                                               {
+                                                       CTX_data_list_add(result, ebone);
+                                               }
+                                       }
+                               }
+                       }       
+                       
+                       return 1;
+               }
+       }
+       else if(member == CTX_DATA_SELECTED_PCHANS) {
+               Object *obact= OBACT;
+               bArmature *arm= (obact) ? obact->data : NULL;
+               bPoseChannel *pchan;
+               
+               if (obact && arm) {
+                       for (pchan= obact->pose->chanbase.first; pchan; pchan= pchan->next) {
+                               if ((pchan->bone) && (arm->layer & pchan->bone->layer)) {
+                                       CTX_data_list_add(result, pchan);
+                               }
+                       }
+                       
+                       return 1;
+               }
+       }
+       else if(member == CTX_DATA_ACTIVE_BONE) {
+               Object *obedit= scene->obedit; // XXX get from context?
+               bArmature *arm= (obedit) ? obedit->data : NULL;
+               EditBone *ebone;
+               
+               if (arm && arm->edbo) {
+                       for (ebone= arm->edbo->first; ebone; ebone= ebone->next) {
+                               if (EBONE_VISIBLE(arm, ebone)) {
+                                       if (ebone->flag & BONE_ACTIVE) {
+                                               CTX_data_pointer_set(result, ebone);
+                                               
+                                               return 1;
+                                       }
+                               }
+                       }
+               }
+               
+       }
+       else if(member == CTX_DATA_ACTIVE_PCHAN) {
+               Object *obact= OBACT;
+               bArmature *arm= (obact) ? obact->data : NULL;
+               bPoseChannel *pchan;
+               
+               pchan= get_active_posechannel(obact);
+               if (pchan) {
+                       CTX_data_pointer_set(result, pchan);
+                       return 1;
+               }
+       }
 
        return 0;
 }
index d59961465e7b2372525f361aef4eb63894b0b3e9..ebe8341ffc5231839e74159059f605b7fcbdf292 100644 (file)
@@ -3440,12 +3440,12 @@ void remake_graph_transdata (TransInfo *t, ListBase *anim_data)
                        sort_time_beztmaps(bezm, fcu->totvert);
                        beztmap_to_data(t, fcu, bezm, fcu->totvert);
                        
-                       /* re-sort actual beztriples (perhaps this could be done using the beztmaps to save time?) */
-                       sort_time_fcurve(fcu);
-                       
                        /* free mapping stuff */
                        MEM_freeN(bezm);
                        
+                       /* re-sort actual beztriples (perhaps this could be done using the beztmaps to save time?) */
+                       sort_time_fcurve(fcu);
+                       
                        /* make sure handles are all set correctly */
                        testhandles_fcurve(fcu);
                }