diff options
Diffstat (limited to 'source/blender/editors/space_view3d/view3d_select.c')
-rw-r--r-- | source/blender/editors/space_view3d/view3d_select.c | 588 |
1 files changed, 346 insertions, 242 deletions
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index e409ad4e81e..8510e39271b 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -110,15 +110,16 @@ int view3d_get_view_aligned_coordinate(ViewContext *vc, float fp[3], const int m { float dvec[3]; int mval_cpy[2]; + eV3DProjStatus ret; mval_cpy[0] = mval[0]; mval_cpy[1] = mval[1]; - ED_view3d_project_int_noclip(vc->ar, fp, mval_cpy); + ret = ED_view3d_project_int_global(vc->ar, fp, mval_cpy, V3D_PROJ_TEST_NOP); initgrabz(vc->rv3d, fp[0], fp[1], fp[2]); - if (mval_cpy[0] != IS_CLIPPED) { + if (ret == V3D_PROJ_RET_SUCCESS) { const float mval_f[2] = {(float)(mval_cpy[0] - mval[0]), (float)(mval_cpy[1] - mval[1])}; ED_view3d_win_to_delta(vc->ar, mval_f, dvec); @@ -255,10 +256,33 @@ static void edbm_backbuf_check_and_select_tfaces(Mesh *me, int select) typedef struct LassoSelectUserData { ViewContext *vc; - rcti *rect; - int (*mcords)[2], moves, select, pass, done; + const rcti *rect; + const int (*mcords)[2]; + int moves; + int select; + + /* runtime */ + int pass; + int is_done; + int is_change; } LassoSelectUserData; +static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data, + ViewContext *vc, const rcti *rect, const int (*mcords)[2], + const int moves, const int select) +{ + r_data->vc = vc; + r_data->rect = rect; + r_data->mcords = mcords; + r_data->moves = moves; + r_data->select = select; + + /* runtime */ + r_data->pass = 0; + r_data->is_done = FALSE; + r_data->is_change = FALSE; +} + static int view3d_selectable_data(bContext *C) { Object *ob = CTX_data_active_object(C); @@ -289,12 +313,12 @@ static int view3d_selectable_data(bContext *C) /* helper also for borderselect */ -static int edge_fully_inside_rect(rcti *rect, short x1, short y1, short x2, short y2) +static int edge_fully_inside_rect(const rcti *rect, int x1, int y1, int x2, int y2) { return BLI_rcti_isect_pt(rect, x1, y1) && BLI_rcti_isect_pt(rect, x2, y2); } -static int edge_inside_rect(rcti *rect, short x1, short y1, short x2, short y2) +static int edge_inside_rect(const rcti *rect, int x1, int y1, int x2, int y2) { int d1, d2, d3, d4; @@ -319,35 +343,70 @@ static int edge_inside_rect(rcti *rect, short x1, short y1, short x2, short 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, 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; - float vec[3]; - int sco1[2], sco2[2]; - bArmature *arm = ob->data; - - if ((ob->type != OB_ARMATURE) || (ob->pose == NULL)) return; + LassoSelectUserData *data = userData; + bArmature *arm = data->vc->obact->data; - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - if (PBONE_VISIBLE(arm, pchan->bone) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0) { - mul_v3_m4v3(vec, ob->obmat, pchan->pose_head); - ED_view3d_project_int(vc->ar, vec, sco1); - mul_v3_m4v3(vec, ob->obmat, pchan->pose_tail); - ED_view3d_project_int(vc->ar, vec, sco2); - - if (BLI_lasso_is_edge_inside(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1], IS_CLIPPED)) { - if (select) pchan->bone->flag |= BONE_SELECTED; - else pchan->bone->flag &= ~BONE_SELECTED; + if (PBONE_SELECTABLE(arm, pchan->bone)) { + int is_point_done = FALSE; + int points_proj_tot = 0; + + /* 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)) + { + is_point_done = TRUE; + } + } + + /* 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)) + { + 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(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); + } } } @@ -362,7 +421,7 @@ static void object_deselect_all_visible(Scene *scene, View3D *v3d) } } -static void do_lasso_select_objects(ViewContext *vc, int mcords[][2], short moves, short extend, short select) +static void do_lasso_select_objects(ViewContext *vc, const int mcords[][2], const short moves, short extend, short select) { Base *base; @@ -371,7 +430,7 @@ static void do_lasso_select_objects(ViewContext *vc, int mcords[][2], short move for (base = vc->scene->base.first; base; base = base->next) { if (BASE_SELECTABLE(vc->v3d, base)) { /* use this to avoid un-needed lasso lookups */ - ED_view3d_project_short(vc->ar, base->object->obmat[3], &base->sx); + ED_view3d_project_base(vc->ar, base); if (BLI_lasso_is_point_inside(mcords, moves, base->sx, base->sy, IS_CLIPPED)) { if (select) ED_base_object_select(base, BA_SELECT); @@ -406,7 +465,7 @@ static void do_lasso_select_mesh__doSelectEdge(void *userData, BMEdge *eed, int BLI_lasso_is_point_inside(data->mcords, data->moves, x1, y1, IS_CLIPPED)) { BM_edge_select_set(data->vc->em->bm, eed, data->select); - data->done = TRUE; + data->is_done = TRUE; } } else { @@ -427,7 +486,7 @@ static void do_lasso_select_mesh__doSelectFace(void *userData, BMFace *efa, int } } -static void do_lasso_select_mesh(ViewContext *vc, int mcords[][2], short moves, short extend, short select) +static void do_lasso_select_mesh(ViewContext *vc, const int mcords[][2], short moves, short extend, short select) { LassoSelectUserData data; ToolSettings *ts = vc->scene->toolsettings; @@ -439,13 +498,7 @@ static void do_lasso_select_mesh(ViewContext *vc, int mcords[][2], short moves, /* set editmesh */ vc->em = BMEdit_FromObject(vc->obedit); - data.vc = vc; - data.rect = ▭ - data.mcords = mcords; - data.moves = moves; - data.select = select; - data.done = FALSE; - data.pass = 0; + view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select); if (extend == 0 && select) EDBM_flag_disable_all(vc->em, BM_ELEM_SELECT); @@ -469,7 +522,7 @@ static void do_lasso_select_mesh(ViewContext *vc, int mcords[][2], short moves, data.pass = 0; mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, V3D_CLIP_TEST_OFF); - if (data.done == 0) { + if (data.is_done == 0) { data.pass = 1; mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, V3D_CLIP_TEST_OFF); } @@ -521,15 +574,11 @@ static void do_lasso_select_curve__doSelect(void *userData, Nurb *UNUSED(nu), BP } } -static void do_lasso_select_curve(ViewContext *vc, int mcords[][2], short moves, short extend, short select) +static void do_lasso_select_curve(ViewContext *vc, const int mcords[][2], short moves, short extend, short select) { LassoSelectUserData data; - /* set vc->editnurb */ - data.vc = vc; - data.mcords = mcords; - data.moves = moves; - data.select = select; + view3d_userdata_lassoselect_init(&data, vc, NULL, mcords, moves, select); if (extend == 0 && select) CU_deselect_all(vc->obedit); @@ -546,14 +595,11 @@ static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, int x, bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT); } } -static void do_lasso_select_lattice(ViewContext *vc, int mcords[][2], short moves, short extend, short select) +static void do_lasso_select_lattice(ViewContext *vc, const int mcords[][2], short moves, short extend, short select) { LassoSelectUserData data; - /* set editdata in vc */ - data.mcords = mcords; - data.moves = moves; - data.select = select; + view3d_userdata_lassoselect_init(&data, vc, NULL, mcords, moves, select); if (extend == 0 && select) ED_setflagsLatt(vc->obedit, 0); @@ -562,51 +608,70 @@ static void do_lasso_select_lattice(ViewContext *vc, int mcords[][2], short move lattice_foreachScreenVert(vc, do_lasso_select_lattice__doSelect, &data); } -static void do_lasso_select_armature(ViewContext *vc, int mcords[][2], short moves, short extend, short select) +static void do_lasso_select_armature__doSelectBone(void *userData, struct EditBone *ebone, int x0, int y0, int x1, int y1) { - bArmature *arm = vc->obedit->data; - EditBone *ebone; - float vec[3]; - short sco1[2], sco2[2], didpoint; - int change = FALSE; + LassoSelectUserData *data = userData; + bArmature *arm = data->vc->obedit->data; - if (extend == 0 && select) - ED_armature_deselect_all_visible(vc->obedit); + if (EBONE_SELECTABLE(arm, ebone)) { + int is_point_done = FALSE; + int points_proj_tot = 0; - /* set editdata in vc */ - - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_VISIBLE(arm, ebone) && (ebone->flag & BONE_UNSELECTABLE) == 0) { - mul_v3_m4v3(vec, vc->obedit->obmat, ebone->head); - ED_view3d_project_short(vc->ar, vec, sco1); - mul_v3_m4v3(vec, vc->obedit->obmat, ebone->tail); - ED_view3d_project_short(vc->ar, vec, sco2); - - didpoint = 0; - if (BLI_lasso_is_point_inside(mcords, moves, sco1[0], sco1[1], IS_CLIPPED)) { - if (select) ebone->flag |= BONE_ROOTSEL; - else ebone->flag &= ~BONE_ROOTSEL; - didpoint = 1; - change = TRUE; - } - if (BLI_lasso_is_point_inside(mcords, moves, sco2[0], sco2[1], IS_CLIPPED)) { - if (select) ebone->flag |= BONE_TIPSEL; - else ebone->flag &= ~BONE_TIPSEL; - didpoint = 1; - change = TRUE; + /* 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)) + { + is_point_done = TRUE; + if (data->select) ebone->flag |= BONE_ROOTSEL; + else ebone->flag &= ~BONE_ROOTSEL; } - /* if one of points selected, we skip the bone itself */ - if (didpoint == 0 && - BLI_lasso_is_edge_inside(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1], IS_CLIPPED)) + } + + /* 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)) { - if (select) ebone->flag |= BONE_TIPSEL | BONE_ROOTSEL | BONE_SELECTED; - else ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - change = TRUE; + is_point_done = TRUE; + if (data->select) ebone->flag |= BONE_TIPSEL; + else ebone->flag &= ~BONE_TIPSEL; } } + + /* if one of points selected, we skip the bone itself */ + if ((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) ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + else ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + data->is_change = TRUE; + } + + data->is_change |= is_point_done; } - - if (change) { +} + +static void do_lasso_select_armature(ViewContext *vc, const int mcords[][2], short moves, short extend, short select) +{ + LassoSelectUserData data; + rcti rect; + + view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select); + + ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); + + BLI_lasso_boundbox(&rect, mcords, moves); + + if (extend == 0 && select) + ED_armature_deselect_all_visible(vc->obedit); + + armature_foreachScreenBone(vc, do_lasso_select_armature__doSelectBone, &data); + + if (data.is_change) { + bArmature *arm = vc->obedit->data; ED_armature_sync_selection(arm->edbo); ED_armature_validate_active(arm); WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, vc->obedit); @@ -614,29 +679,29 @@ static void do_lasso_select_armature(ViewContext *vc, int mcords[][2], short mov } - - -static void do_lasso_select_meta(ViewContext *vc, int mcords[][2], short moves, short extend, short select) +static void do_lasso_select_meta(ViewContext *vc, const int mcords[][2], short moves, short extend, short select) { MetaBall *mb = (MetaBall *)vc->obedit->data; MetaElem *ml; - float vec[3]; - short sco[2]; if (extend == 0 && select) { + /* XXX, make an editor function as is done elsewhere */ for (ml = mb->editelems->first; ml; ml = ml->next) { ml->flag &= ~SELECT; } } - for (ml = mb->editelems->first; ml; ml = ml->next) { - - mul_v3_m4v3(vec, vc->obedit->obmat, &ml->x); - ED_view3d_project_short(vc->ar, vec, sco); + ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); - if (BLI_lasso_is_point_inside(mcords, moves, sco[0], sco[1], IS_CLIPPED)) { - if (select) ml->flag |= SELECT; - else ml->flag &= ~SELECT; + for (ml = mb->editelems->first; ml; ml = ml->next) { + int screen_co[2]; + if (ED_view3d_project_int_object(vc->ar, &ml->x, screen_co, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_SUCCESS) + { + if (BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], INT_MAX)) { + if (select) ml->flag |= SELECT; + else ml->flag &= ~SELECT; + } } } } @@ -700,7 +765,7 @@ static int do_paintvert_box_select(ViewContext *vc, rcti *rect, int select, int return OPERATOR_FINISHED; } -static void do_lasso_select_paintvert(ViewContext *vc, int mcords[][2], short moves, short extend, short select) +static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], short moves, short extend, short select) { Object *ob = vc->obact; Mesh *me = ob ? ob->data : NULL; @@ -722,7 +787,7 @@ static void do_lasso_select_paintvert(ViewContext *vc, int mcords[][2], short mo paintvert_flush_flags(ob); } -static void do_lasso_select_paintface(ViewContext *vc, int mcords[][2], short moves, short extend, short select) +static void do_lasso_select_paintface(ViewContext *vc, const int mcords[][2], short moves, short extend, short select) { Object *ob = vc->obact; Mesh *me = ob ? ob->data : NULL; @@ -777,7 +842,9 @@ static void do_lasso_select_node(int mcords[][2], short moves, short select) } #endif -static void view3d_lasso_select(bContext *C, ViewContext *vc, int mcords[][2], short moves, short extend, short select) +static void view3d_lasso_select(bContext *C, ViewContext *vc, + const int mcords[][2], short moves, + short extend, short select) { Object *ob = CTX_data_active_object(C); @@ -828,7 +895,7 @@ static int view3d_lasso_select_exec(bContext *C, wmOperator *op) { ViewContext vc; int mcords_tot; - int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); + const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); if (mcords) { short extend, select; @@ -1059,8 +1126,7 @@ static Base *object_mouse_select_menu(bContext *C, ViewContext *vc, unsigned int } else { int temp, dist = 15; - - ED_view3d_project_short(vc->ar, base->object->obmat[3], &base->sx); + ED_view3d_project_base(vc->ar, base); temp = abs(base->sx - mval[0]) + abs(base->sy - mval[1]); if (temp < dist) @@ -1341,8 +1407,7 @@ static int mouse_select(bContext *C, const int mval[2], short extend, short dese base = startbase; while (base) { if (BASE_SELECTABLE(v3d, base)) { - ED_view3d_project_short(ar, base->object->obmat[3], &base->sx); - + ED_view3d_project_base(ar, base); temp = abs(base->sx - mval[0]) + abs(base->sy - mval[1]); if (base == BASACT) temp += 10; if (temp < dist) { @@ -1513,19 +1578,37 @@ static int mouse_select(bContext *C, const int mval[2], short extend, short dese typedef struct BoxSelectUserData { ViewContext *vc; - rcti *rect; - int select, pass, done; + const rcti *rect; + int select; + + /* runtime */ + int pass; + int is_done; + int is_change; } BoxSelectUserData; -int edge_inside_circle(int centx, int centy, int rad, int x1, int y1, int x2, int y2) +static void view3d_userdata_boxselect_init(BoxSelectUserData *r_data, + ViewContext *vc, const rcti *rect, const int select) +{ + r_data->vc = vc; + r_data->rect = rect; + r_data->select = select; + + /* runtime */ + r_data->pass = 0; + r_data->is_done = FALSE; + r_data->is_change = FALSE; +} + +int edge_inside_circle(int centx, int centy, int radius, int x1, int y1, int x2, int y2) { - int radsq = rad * rad; + int radius_squared = radius * radius; /* check points in circle itself */ - if ((x1 - centx) * (x1 - centx) + (y1 - centy) * (y1 - centy) <= radsq) { + if ((x1 - centx) * (x1 - centx) + (y1 - centy) * (y1 - centy) <= radius_squared) { return TRUE; } - else if ((x2 - centx) * (x2 - centx) + (y2 - centy) * (y2 - centy) <= radsq) { + else if ((x2 - centx) * (x2 - centx) + (y2 - centy) * (y2 - centy) <= radius_squared) { return TRUE; } else { @@ -1533,7 +1616,7 @@ int edge_inside_circle(int centx, int centy, int rad, int x1, int y1, int x2, in const float v1[2] = {x1, y1}; const float v2[2] = {x2, y2}; /* pointdistline */ - if (dist_squared_to_line_segment_v2(cent, v1, v2) < (float)radsq) { + if (dist_squared_to_line_segment_v2(cent, v1, v2) < (float)radius_squared) { return TRUE; } } @@ -1577,9 +1660,7 @@ static int do_nurbs_box_select(ViewContext *vc, rcti *rect, int select, int exte { BoxSelectUserData data; - data.vc = vc; - data.rect = rect; - data.select = select; + view3d_userdata_boxselect_init(&data, vc, rect, select); if (extend == 0 && select) CU_deselect_all(vc->obedit); @@ -1602,9 +1683,7 @@ static int do_lattice_box_select(ViewContext *vc, rcti *rect, int select, int ex { BoxSelectUserData data; - data.vc = vc; - data.rect = rect; - data.select = select; + view3d_userdata_boxselect_init(&data, vc, rect, select); if (extend == 0 && select) ED_setflagsLatt(vc->obedit, 0); @@ -1631,7 +1710,7 @@ static void do_mesh_box_select__doSelectEdge(void *userData, BMEdge *eed, int x0 if (data->pass == 0) { if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) { BM_edge_select_set(data->vc->em->bm, eed, data->select); - data->done = TRUE; + data->is_done = TRUE; } } else { @@ -1655,11 +1734,7 @@ static int do_mesh_box_select(ViewContext *vc, rcti *rect, int select, int exten ToolSettings *ts = vc->scene->toolsettings; int bbsel; - data.vc = vc; - data.rect = rect; - data.select = select; - data.pass = 0; - data.done = FALSE; + view3d_userdata_boxselect_init(&data, vc, rect, select); if (extend == 0 && select) EDBM_flag_disable_all(vc->em, BM_ELEM_SELECT); @@ -1684,7 +1759,7 @@ static int do_mesh_box_select(ViewContext *vc, rcti *rect, int select, int exten data.pass = 0; mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, V3D_CLIP_TEST_OFF); - if (data.done == 0) { + if (data.is_done == 0) { data.pass = 1; mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, V3D_CLIP_TEST_OFF); } @@ -2142,15 +2217,32 @@ typedef struct CircleSelectUserData { short select; int mval[2]; float radius; + float radius_squared; + + /* runtime */ + int is_change; } CircleSelectUserData; +static void view3d_userdata_circleselect_init(CircleSelectUserData *r_data, + ViewContext *vc, const int select, const int mval[2], const float rad) +{ + r_data->vc = vc; + r_data->select = select; + copy_v2_v2_int(r_data->mval, mval); + r_data->radius = rad; + r_data->radius_squared = rad * rad; + + /* runtime */ + r_data->is_change = FALSE; +} + static void mesh_circle_doSelectVert(void *userData, BMVert *eve, int x, int y, int UNUSED(index)) { CircleSelectUserData *data = userData; - int mx = x - data->mval[0], my = y - data->mval[1]; - float r = sqrt(mx * mx + my * my); + const float delta[2] = {(float)(x - data->mval[0]), + (float)(y - data->mval[1])}; - if (r <= data->radius) { + if (len_squared_v2(delta) <= data->radius_squared) { BM_vert_select_set(data->vc->em->bm, eve, data->select); } } @@ -2165,10 +2257,10 @@ static void mesh_circle_doSelectEdge(void *userData, BMEdge *eed, int x0, int y0 static void mesh_circle_doSelectFace(void *userData, BMFace *efa, int x, int y, int UNUSED(index)) { CircleSelectUserData *data = userData; - int mx = x - data->mval[0], my = y - data->mval[1]; - float r = sqrt(mx * mx + my * my); - - if (r <= data->radius) { + const float delta[2] = {(float)(x - data->mval[0]), + (float)(y - data->mval[1])}; + + if (len_squared_v2(delta) <= data->radius_squared) { BM_face_select_set(data->vc->em->bm, efa, data->select); } } @@ -2184,11 +2276,7 @@ static void mesh_circle_select(ViewContext *vc, int select, const int mval[2], f vc->em = BMEdit_FromObject(vc->obedit); - data.vc = vc; - data.select = select; - data.mval[0] = mval[0]; - data.mval[1] = mval[1]; - data.radius = rad; + view3d_userdata_circleselect_init(&data, vc, select, mval, rad); if (ts->selectmode & SCE_SELECT_VERTEX) { if (bbsel) { @@ -2259,12 +2347,13 @@ static void paint_vertsel_circle_select(ViewContext *vc, int select, const int m static void nurbscurve_circle_doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, int x, int y) { CircleSelectUserData *data = userData; - int mx = x - data->mval[0], my = y - data->mval[1]; - float r = sqrt(mx * mx + my * my); Object *obedit = data->vc->obedit; Curve *cu = (Curve *)obedit->data; - if (r <= data->radius) { + const float delta[2] = {(float)(x - data->mval[0]), + (float)(y - data->mval[1])}; + + if (len_squared_v2(delta) <= data->radius_squared) { if (bp) { bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT); @@ -2302,6 +2391,7 @@ static void nurbscurve_circle_select(ViewContext *vc, int select, const int mval data.mval[1] = mval[1]; data.radius = rad; data.vc = vc; + data.is_change = FALSE; ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ nurbs_foreachScreenVert(vc, nurbscurve_circle_doSelect, &data); @@ -2311,10 +2401,10 @@ static void nurbscurve_circle_select(ViewContext *vc, int select, const int mval static void latticecurve_circle_doSelect(void *userData, BPoint *bp, int x, int y) { CircleSelectUserData *data = userData; - int mx = x - data->mval[0], my = y - data->mval[1]; - float r = sqrt(mx * mx + my * my); + const float delta[2] = {(float)(x - data->mval[0]), + (float)(y - data->mval[1])}; - if (r <= data->radius) { + if (len_squared_v2(delta) <= data->radius_squared) { bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT); } } @@ -2322,12 +2412,7 @@ static void lattice_circle_select(ViewContext *vc, int select, const int mval[2] { CircleSelectUserData data; - /* set vc-> edit data */ - - data.select = select; - data.mval[0] = mval[0]; - data.mval[1] = mval[1]; - data.radius = rad; + view3d_userdata_circleselect_init(&data, vc, select, mval, rad); ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ lattice_foreachScreenVert(vc, latticecurve_circle_doSelect, &data); @@ -2338,10 +2423,10 @@ static void lattice_circle_select(ViewContext *vc, int select, const int mval[2] static short pchan_circle_doSelectJoint(void *userData, bPoseChannel *pchan, int x, int y) { CircleSelectUserData *data = userData; - int mx = x - data->mval[0], my = y - data->mval[1]; - float r = sqrt(mx * mx + my * my); - - if (r <= data->radius) { + const float delta[2] = {(float)(x - data->mval[0]), + (float)(y - data->mval[1])}; + + if (len_squared_v2(delta) <= data->radius_squared) { if (data->select) pchan->bone->flag |= BONE_SELECTED; else @@ -2350,63 +2435,78 @@ static short pchan_circle_doSelectJoint(void *userData, bPoseChannel *pchan, int } return 0; } +static void do_circle_select_pose__doSelectBone(void *userData, struct bPoseChannel *pchan, int x0, int y0, int x1, int y1) +{ + CircleSelectUserData *data = userData; + bArmature *arm = data->vc->obact->data; + + if (PBONE_SELECTABLE(arm, pchan->bone)) { + int is_point_done = FALSE; + int points_proj_tot = 0; + + /* project head location to screenspace */ + if (x0 != IS_CLIPPED) { + points_proj_tot++; + if (pchan_circle_doSelectJoint(data, pchan, x0, y0)) { + is_point_done = 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; + } + } + + /* 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; - bArmature *arm = vc->obact->data; - bPose *pose = vc->obact->pose; - bPoseChannel *pchan; - int change = FALSE; - /* set vc->edit data */ - data.select = select; - data.mval[0] = mval[0]; - data.mval[1] = mval[1]; - data.radius = rad; + view3d_userdata_circleselect_init(&data, vc, select, mval, rad); 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) { - short sco1[2], sco2[2], didpoint = 0; - float vec[3]; - - /* skip invisible bones */ - if (PBONE_VISIBLE(arm, pchan->bone) == 0) - continue; - - /* project head location to screenspace */ - mul_v3_m4v3(vec, vc->obact->obmat, pchan->pose_head); - ED_view3d_project_short(vc->ar, vec, sco1); - - /* project tail location to screenspace */ - mul_v3_m4v3(vec, vc->obact->obmat, pchan->pose_tail); - ED_view3d_project_short(vc->ar, vec, sco2); - - /* check if the head and/or tail is in the circle - * - the call to check also does the selection already - */ - if (pchan_circle_doSelectJoint(&data, pchan, sco1[0], sco1[1])) - didpoint = 1; - if (pchan_circle_doSelectJoint(&data, pchan, sco2[0], sco2[1])) - didpoint = 1; - - change |= didpoint; - } + pose_foreachScreenBone(vc, do_circle_select_pose__doSelectBone, &data); + + if (data.is_change) { + bArmature *arm = vc->obact->data; - if (change) { 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); + } } } static short armature_circle_doSelectJoint(void *userData, EditBone *ebone, int x, int y, short head) { CircleSelectUserData *data = userData; - int mx = x - data->mval[0], my = y - data->mval[1]; - float r = sqrt(mx * mx + my * my); + const float delta[2] = {(float)(x - data->mval[0]), + (float)(y - data->mval[1])}; - if (r <= data->radius) { + if (len_squared_v2(delta) <= data->radius_squared) { if (head) { if (data->select) ebone->flag |= BONE_ROOTSEL; @@ -2423,57 +2523,61 @@ static short armature_circle_doSelectJoint(void *userData, EditBone *ebone, int } return 0; } -static void armature_circle_select(ViewContext *vc, int select, const int mval[2], float rad) +static void do_circle_select_armature__doSelectBone(void *userData, struct EditBone *ebone, int x0, int y0, int x1, int y1) { - CircleSelectUserData data; - bArmature *arm = vc->obedit->data; - EditBone *ebone; - int change = FALSE; - - /* set vc->edit data */ - data.select = select; - data.mval[0] = mval[0]; - data.mval[1] = mval[1]; - data.radius = rad; + CircleSelectUserData *data = userData; + bArmature *arm = data->vc->obedit->data; + + if (EBONE_SELECTABLE(arm, ebone)) { + int is_point_done = FALSE; + int points_proj_tot = 0; - ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ - - /* check each EditBone... */ - /* TODO: could be optimized at some point */ - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - short sco1[2], sco2[2], didpoint = 0; - float vec[3]; - /* project head location to screenspace */ - mul_v3_m4v3(vec, vc->obedit->obmat, ebone->head); - ED_view3d_project_short(vc->ar, vec, sco1); - + if (x0 != IS_CLIPPED) { + points_proj_tot++; + if (armature_circle_doSelectJoint(data, ebone, x0, y0, TRUE)) { + is_point_done = TRUE; + } + } + /* project tail location to screenspace */ - mul_v3_m4v3(vec, vc->obedit->obmat, ebone->tail); - ED_view3d_project_short(vc->ar, vec, sco2); - - /* check if the head and/or tail is in the circle - * - the call to check also does the selection already + if (x1 != IS_CLIPPED) { + points_proj_tot++; + if (armature_circle_doSelectJoint(data, ebone, x1, y1, FALSE)) { + is_point_done = TRUE; + } + } + + /* check if the head and/or tail is in the circle + * - the call to check also does the selection already */ - if (armature_circle_doSelectJoint(&data, ebone, sco1[0], sco1[1], 1)) - didpoint = 1; - if (armature_circle_doSelectJoint(&data, ebone, sco2[0], sco2[1], 0)) - didpoint = 1; - - /* only if the endpoints didn't get selected, deal with the middle of the bone too */ - /* XXX should we just do this always? */ - if ((didpoint == 0) && edge_inside_circle(mval[0], mval[1], rad, sco1[0], sco1[1], sco2[0], sco2[1])) { - if (select) - ebone->flag |= BONE_TIPSEL | BONE_ROOTSEL | BONE_SELECTED; - else - ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - change = 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(data->mval[0], data->mval[1], data->radius, x0, y0, x1, y1)) + { + if (data->select) ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + else ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + data->is_change = TRUE; } - - change |= didpoint; + + data->is_change |= is_point_done; } +} +static void armature_circle_select(ViewContext *vc, int select, const int mval[2], float rad) +{ + CircleSelectUserData data; + bArmature *arm = vc->obedit->data; + + view3d_userdata_circleselect_init(&data, vc, select, mval, rad); + + ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); + + armature_foreachScreenBone(vc, do_circle_select_armature__doSelectBone, &data); - if (change) { + if (data.is_change) { ED_armature_sync_selection(arm->edbo); ED_armature_validate_active(arm); WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, vc->obedit); @@ -2556,7 +2660,7 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op) select = select ? BA_SELECT : BA_DESELECT; for (base = FIRSTBASE; base; base = base->next) { if (BASE_SELECTABLE(v3d, base)) { - ED_view3d_project_short(ar, base->object->obmat[3], &base->sx); + ED_view3d_project_base(ar, base); if (base->sx != IS_CLIPPED) { int dx = base->sx - x; int dy = base->sy - y; |