use pose_foreachScreenBone for pose lasso and circle select
authorCampbell Barton <ideasman42@gmail.com>
Fri, 5 Oct 2012 17:51:44 +0000 (17:51 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 5 Oct 2012 17:51:44 +0000 (17:51 +0000)
source/blender/editors/include/ED_view3d.h
source/blender/editors/space_view3d/drawobject.c
source/blender/editors/space_view3d/view3d_select.c

index 8161dd23b8e8cd591d4723c681bdbe2c577f7e67..ebf93baeabc94d3d2a7810ac1fd0b2c8c2467637 100644 (file)
@@ -172,6 +172,7 @@ void mesh_foreachScreenFace(struct ViewContext *vc, void (*func)(void *userData,
 void nurbs_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct Nurb *nu, struct BPoint *bp, struct BezTriple *bezt, int beztindex, int x, int y), void *userData);
 void lattice_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct BPoint *bp, int x, int y), void *userData);
 void armature_foreachScreenBone(struct ViewContext *vc, void (*func)(void *userData, struct EditBone *ebone, int x0, int y0, int x1, int y1), void *userData);
+void pose_foreachScreenBone(struct ViewContext *vc, void (*func)(void *userData, struct bPoseChannel *pchan, int x0, int y0, int x1, int y1), void *userData);
 
 
 void ED_view3d_clipping_calc(struct BoundBox *bb, float planes[4][4], struct bglMats *mats, const struct rcti *rect);
index 5ea0413ef719e4a549be72a0d9f55fe85fcb1b58..40207ce806ce685b282c9357db0661288cd2f0ad 100644 (file)
@@ -2265,6 +2265,53 @@ void armature_foreachScreenBone(
        }
 }
 
+/* ED_view3d_init_mats_rv3d must be called first */
+/* almost _exact_ copy of #armature_foreachScreenBone */
+void pose_foreachScreenBone(
+        struct ViewContext *vc,
+        void (*func)(void *userData, struct bPoseChannel *pchan, int x0, int y0, int x1, int y1),
+        void *userData)
+{
+       bArmature *arm = vc->obact->data;
+       bPose *pose = vc->obact->pose;
+       bPoseChannel *pchan;
+
+       for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+               if (PBONE_VISIBLE(arm, pchan->bone)) {
+                       int screen_co_a[2], screen_co_b[2];
+                       int points_proj_tot = 0;
+
+                       /* project head location to screenspace */
+                       if (ED_view3d_project_int_object(vc->ar, pchan->pose_head, screen_co_a,
+                                                        V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS)
+                       {
+                               points_proj_tot++;
+                       }
+                       else {
+                               screen_co_a[0] = IS_CLIPPED;  /* weak */
+                               /* screen_co_a[1]: intentionally dont set this so we get errors on misuse */
+                       }
+
+                       /* project tail location to screenspace */
+                       if (ED_view3d_project_int_object(vc->ar, pchan->pose_tail, screen_co_b,
+                                                        V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS)
+                       {
+                               points_proj_tot++;
+                       }
+                       else {
+                               screen_co_b[0] = IS_CLIPPED;  /* weak */
+                               /* screen_co_b[1]: intentionally dont set this so we get errors on misuse */
+                       }
+
+                       if (points_proj_tot) {  /* at least one point's projection worked */
+                               func(userData, pchan,
+                                    screen_co_a[0], screen_co_a[1],
+                                    screen_co_b[0], screen_co_b[1]);
+                       }
+               }
+       }
+}
+
 /* ************** DRAW MESH ****************** */
 
 /* First section is all the "simple" draw routines, 
index ab0c6a2edc899b7d3a4235b53034f35657539df2..36a2927cb44b8089303e50ef6fb6a6a96852de38 100644 (file)
@@ -343,62 +343,70 @@ static int edge_inside_rect(const rcti *rect, int x1, int y1, int x2, int y2)
        return 1;
 }
 
-/* warning; lasso select with backbuffer-check draws in backbuf with persp(PERSP_WIN) 
- * and returns with persp(PERSP_VIEW). After lasso select backbuf is not OK
- */
-static void do_lasso_select_pose(ViewContext *vc, Object *ob, const int mcords[][2], short moves, short select)
+static void do_lasso_select_pose__doSelectBone(void *userData, struct bPoseChannel *pchan, int x0, int y0, int x1, int y1)
 {
-       bPoseChannel *pchan;
-       bArmature *arm = ob->data;
-       
-       if ((ob->type != OB_ARMATURE) || (ob->pose == NULL)) {
-               return;
-       }
-
-       ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d);
+       LassoSelectUserData *data = userData;
+       bArmature *arm = data->vc->obact->data;
 
-       for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
-               if (PBONE_SELECTABLE(arm, pchan->bone)) {
-                       int screen_co_a[2], screen_co_b[2];
-                       int is_point_done = FALSE;
-                       int points_proj_tot = 0;
+       if (PBONE_SELECTABLE(arm, pchan->bone)) {
+               int is_point_done = FALSE;
+               int points_proj_tot = 0;
 
-                       /* project head location to screenspace */
-                       if (ED_view3d_project_int_object(vc->ar, pchan->pose_head, screen_co_a,
-                                                        V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS)
+               /* project head location to screenspace */
+               if (x0 != IS_CLIPPED) {
+                       points_proj_tot++;
+                       if (BLI_rcti_isect_pt(data->rect, x0, y0) &&
+                           BLI_lasso_is_point_inside(data->mcords, data->moves, x0, y0, INT_MAX))
                        {
-                               points_proj_tot++;
-                               if (BLI_lasso_is_point_inside(mcords, moves, screen_co_a[0], screen_co_a[1], INT_MAX)) {
-                                       is_point_done = TRUE;
-                               }
+                               is_point_done = TRUE;
                        }
+               }
 
-                       /* project tail location to screenspace */
-                       if (ED_view3d_project_int_object(vc->ar, pchan->pose_tail, screen_co_b,
-                                                        V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS)
+               /* project tail location to screenspace */
+               if (x1 != IS_CLIPPED) {
+                       points_proj_tot++;
+                       if (BLI_rcti_isect_pt(data->rect, x1, y1) &&
+                           BLI_lasso_is_point_inside(data->mcords, data->moves, x1, y1, INT_MAX))
                        {
-                               points_proj_tot++;
-                               if (BLI_lasso_is_point_inside(mcords, moves, screen_co_b[0], screen_co_b[1], INT_MAX)) {
-                                       is_point_done = TRUE;
-                               }
+                               is_point_done = TRUE;
                        }
+               }
 
-                       /* if one of points selected, we skip the bone itself */
-                       if ((is_point_done == TRUE) ||
-                           ((is_point_done == FALSE) && (points_proj_tot == 2) &&
-                            BLI_lasso_is_edge_inside(mcords, moves,
-                                                     screen_co_a[0], screen_co_a[1],
-                                                     screen_co_b[0], screen_co_b[1], INT_MAX)))
-                       {
-                               if (select) pchan->bone->flag |=  BONE_SELECTED;
-                               else        pchan->bone->flag &= ~BONE_SELECTED;
-                       }
+               /* if one of points selected, we skip the bone itself */
+               if ((is_point_done == TRUE) ||
+                   ((is_point_done == FALSE) && (points_proj_tot == 2) &&
+                    BLI_lasso_is_edge_inside(data->mcords, data->moves, x0, y0, x1, y1, INT_MAX)))
+               {
+                       if (data->select) pchan->bone->flag |=  BONE_SELECTED;
+                       else              pchan->bone->flag &= ~BONE_SELECTED;
+                       data->is_change = TRUE;
                }
+               data->is_change |= is_point_done;
        }
+}
+static void do_lasso_select_pose(ViewContext *vc, Object *ob, const int mcords[][2], short moves, short select)
+{
+       LassoSelectUserData data;
+       rcti rect;
        
-       if (arm->flag & ARM_HAS_VIZ_DEPS) {
-               /* mask modifier ('armature' mode), etc. */
-               DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+       if ((ob->type != OB_ARMATURE) || (ob->pose == NULL)) {
+               return;
+       }
+
+       view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select);
+
+       ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d);
+
+       BLI_lasso_boundbox(&rect, mcords, moves);
+
+       pose_foreachScreenBone(vc, do_lasso_select_pose__doSelectBone, &data);
+
+       if (data.is_change) {
+               bArmature *arm = ob->data;
+               if (arm->flag & ARM_HAS_VIZ_DEPS) {
+                       /* mask modifier ('armature' mode), etc. */
+                       DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+               }
        }
 }
 
@@ -2427,66 +2435,68 @@ static short pchan_circle_doSelectJoint(void *userData, bPoseChannel *pchan, int
        }
        return 0;
 }
-static void pose_circle_select(ViewContext *vc, int select, const int mval[2], float rad)
+static void do_circle_select_pose__doSelectBone(void *userData, struct bPoseChannel *pchan, int x0, int y0, int x1, int y1)
 {
-       CircleSelectUserData data;
-       bArmature *arm = vc->obact->data;
-       bPose *pose = vc->obact->pose;
-       bPoseChannel *pchan;
-       
-       view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
+       CircleSelectUserData *data = userData;
+       bArmature *arm = data->vc->obact->data;
 
-       ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); /* for foreach's screen/vert projection */
-       
-       /* check each PoseChannel... */
-       /* TODO: could be optimized at some point */
-       for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
-               if (PBONE_SELECTABLE(arm, pchan->bone)) {
-                       int screen_co_a[2], screen_co_b[2];
-                       int is_point_done = FALSE;
-                       int points_proj_tot = 0;
-
-                       /* project head location to screenspace */
-                       if (ED_view3d_project_int_object(vc->ar, pchan->pose_head, screen_co_a,
-                                                        V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS)
-                       {
-                               points_proj_tot++;
-                               if (pchan_circle_doSelectJoint(&data, pchan, screen_co_a[0], screen_co_a[1])) {
-                                       is_point_done = TRUE;
-                               }
-                       }
+       if (PBONE_SELECTABLE(arm, pchan->bone)) {
+               int is_point_done = FALSE;
+               int points_proj_tot = 0;
 
-                       /* project tail location to screenspace */
-                       if (ED_view3d_project_int_object(vc->ar, pchan->pose_tail, screen_co_b,
-                                                        V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS)
-                       {
-                               points_proj_tot++;
-                               if (pchan_circle_doSelectJoint(&data, pchan, screen_co_b[0], screen_co_b[1])) {
-                                       is_point_done = TRUE;
-                               }
+               /* project head location to screenspace */
+               if (x0 != IS_CLIPPED) {
+                       points_proj_tot++;
+                       if (pchan_circle_doSelectJoint(data, pchan, x0, y0)) {
+                               is_point_done = TRUE;
                        }
+               }
 
-                       /* only if the endpoints didn't get selected, deal with the middle of the bone too
-                        * It works nicer to only do this if the head or tail are not in the circle,
-                        * otherwise there is no way to circle select joints alone */
-                       if ((is_point_done == FALSE) && (points_proj_tot == 2) &&
-                           edge_inside_circle(mval[0], mval[1], rad,
-                                              screen_co_a[0], screen_co_a[1],
-                                              screen_co_b[0], screen_co_b[1]))
-                       {
-                               if (select)
-                                       pchan->bone->flag |= BONE_SELECTED;
-                               else
-                                       pchan->bone->flag &= ~BONE_SELECTED;
-                               data.is_change = TRUE;
+               /* project tail location to screenspace */
+               if (x1 != IS_CLIPPED) {
+                       points_proj_tot++;
+                       if (pchan_circle_doSelectJoint(data, pchan, x1, y1)) {
+                               is_point_done = TRUE;
                        }
+               }
 
-                       data.is_change |= is_point_done;
+               /* check if the head and/or tail is in the circle
+                * - the call to check also does the selection already
+                */
+
+               /* only if the endpoints didn't get selected, deal with the middle of the bone too
+                * It works nicer to only do this if the head or tail are not in the circle,
+                * otherwise there is no way to circle select joints alone */
+               if ((is_point_done == FALSE) && (points_proj_tot == 2) &&
+                   edge_inside_circle(data->mval[0], data->mval[1], data->radius, x0, y0, x1, y1))
+               {
+                       if (data->select) pchan->bone->flag |= BONE_SELECTED;
+                       else              pchan->bone->flag &= ~BONE_SELECTED;
+                       data->is_change = TRUE;
                }
+
+               data->is_change |= is_point_done;
        }
+}
+static void pose_circle_select(ViewContext *vc, int select, const int mval[2], float rad)
+{
+       CircleSelectUserData data;
+       
+       view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
+
+       ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); /* for foreach's screen/vert projection */
+       
+       pose_foreachScreenBone(vc, do_circle_select_pose__doSelectBone, &data);
 
        if (data.is_change) {
+               bArmature *arm = vc->obact->data;
+
                WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, vc->obact);
+
+               if (arm->flag & ARM_HAS_VIZ_DEPS) {
+                       /* mask modifier ('armature' mode), etc. */
+                       DAG_id_tag_update(&vc->obact->id, OB_RECALC_DATA);
+               }
        }
 }