diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index e950f9bc679..30e93e71968 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -235,12 +235,17 @@ typedef enum {
GHOST_kStandardCursorCrosshairA,
GHOST_kStandardCursorCrosshairB,
GHOST_kStandardCursorCrosshairC,
+ GHOST_kStandardCursorCrosshairD,
+ GHOST_kStandardCursorBox,
+ GHOST_kStandardCursorBoxDot,
+ GHOST_kStandardCursorBoxPointer,
GHOST_kStandardCursorPencil,
GHOST_kStandardCursorUpArrow,
GHOST_kStandardCursorDownArrow,
GHOST_kStandardCursorVerticalSplit,
GHOST_kStandardCursorHorizontalSplit,
GHOST_kStandardCursorEraser,
+ GHOST_kStandardCursorPointer,
GHOST_kStandardCursorKnife,
GHOST_kStandardCursorEyedropper,
GHOST_kStandardCursorZoomIn,
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index 3e82f55c583..506edbf022e 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -727,6 +727,9 @@ HCURSOR GHOST_WindowWin32::getStandardCursor(GHOST_TStandardCursor shape) const
case GHOST_kStandardCursorHorizontalSplit:
cursor = ::LoadImage(module, "splith_cursor", IMAGE_CURSOR, cx, cy, flags);
break;
+ case GHOST_kStandardCursorPointer:
+ cursor = ::LoadImage(module, "pointer_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break;
case GHOST_kStandardCursorKnife:
cursor = ::LoadImage(module, "knife_cursor", IMAGE_CURSOR, cx, cy, flags);
break;
@@ -772,6 +775,18 @@ HCURSOR GHOST_WindowWin32::getStandardCursor(GHOST_TStandardCursor shape) const
case GHOST_kStandardCursorCrosshairC:
cursor = ::LoadImage(module, "crossC_cursor", IMAGE_CURSOR, cx, cy, flags);
break; /* Minimal Crosshair C */
+ case GHOST_kStandardCursorCrosshairD:
+ cursor = ::LoadImage(module, "crossD_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break; /* Open Crosshair D */
+ case GHOST_kStandardCursorBox:
+ cursor = ::LoadImage(module, "box_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break; /* Box */
+ case GHOST_kStandardCursorBoxDot:
+ cursor = ::LoadImage(module, "boxdot_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break; /* Box Dot */
+ case GHOST_kStandardCursorBoxPointer:
+ cursor = ::LoadImage(module, "boxpointer_cursor", IMAGE_CURSOR, cx, cy, flags);
+ break; /* Box Pointer */
case GHOST_kStandardCursorBottomSide:
case GHOST_kStandardCursorUpDown:
cursor = ::LoadImage(module, "movens_cursor", IMAGE_CURSOR, cx, cy, flags);
diff --git a/release/datafiles/blender_icons.svg b/release/datafiles/blender_icons.svg
index 9dc7b184b12..82ebc6f0ba3 100644
--- a/release/datafiles/blender_icons.svg
+++ b/release/datafiles/blender_icons.svg
@@ -7,7 +7,7 @@
inkscape:output_extension="org.inkscape.output.svg.inkscape"
sodipodi:docname="blender_icons.svg"
version="1.0"
- inkscape:version="1.2 (dc2aeda, 2022-05-15)"
+ inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
sodipodi:version="0.32"
id="svg2"
height="640"
@@ -42,19 +42,70 @@
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
- inkscape:window-width="1728"
- inkscape:window-height="1051"
+ inkscape:window-width="1920"
+ inkscape:window-height="1027"
id="namedview34335"
showgrid="false"
- inkscape:zoom="1.2495612"
- inkscape:cx="196.46897"
- inkscape:cy="320.51252"
- inkscape:window-x="767"
- inkscape:window-y="120"
- inkscape:window-maximized="0"
+ inkscape:zoom="22.627417"
+ inkscape:cx="423.44648"
+ inkscape:cy="332.84842"
+ inkscape:window-x="-8"
+ inkscape:window-y="-8"
+ inkscape:window-maximized="1"
inkscape:current-layer="layer8"
inkscape:showpageshadow="2"
- inkscape:deskcolor="#808080" />
+ inkscape:deskcolor="#808080"
+ showguides="true"
+ inkscape:guide-bbox="true">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
0) {
- return true;
- }
- for (uint a = 0; a < mcoords_len - 1; a++) {
- if (isect_seg_seg_v2_int(mcoords[a], mcoords[a + 1], v1, v2) > 0) {
+ if (!fully_inside) {
+ /* check points in lasso */
+ if (BLI_lasso_is_point_inside(mcoords, mcoords_len, v1[0], v1[1], error_value)) {
return true;
}
+ if (BLI_lasso_is_point_inside(mcoords, mcoords_len, v2[0], v2[1], error_value)) {
+ return true;
+ }
+
+ /* no points in lasso, so we have to intersect with lasso edge */
+
+ if (isect_seg_seg_v2_int(mcoords[0], mcoords[mcoords_len - 1], v1, v2) > 0) {
+ return true;
+ }
+ for (unsigned int a = 0; a < mcoords_len - 1; a++) {
+ if (isect_seg_seg_v2_int(mcoords[a], mcoords[a + 1], v1, v2) > 0) {
+ return true;
+ }
+ }
}
return false;
diff --git a/source/blender/blenloader/intern/versioning_defaults.cc b/source/blender/blenloader/intern/versioning_defaults.cc
index d19616223cd..4755ad7d625 100644
--- a/source/blender/blenloader/intern/versioning_defaults.cc
+++ b/source/blender/blenloader/intern/versioning_defaults.cc
@@ -183,6 +183,8 @@ static void blo_update_defaults_screen(bScreen *screen,
v3d->overlay.vertex_paint_mode_opacity = 1.0f;
/* Use dimmed selected edges. */
v3d->overlay.edit_flag &= ~V3D_OVERLAY_EDIT_EDGES;
+ /* Show xray facedots */
+ v3d->overlay.edit_flag |= V3D_OVERLAY_EDIT_FACE_DOT_XRAY;
/* grease pencil settings */
v3d->vertex_opacity = 1.0f;
v3d->gp_flag |= V3D_GP_SHOW_EDIT_LINES;
@@ -373,6 +375,25 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene)
if (idprop) {
IDP_ClearProperty(idprop);
}
+
+ /* X-Ray. */
+ ts->xray_button = true;
+ ts->auto_xray_object = true;
+ ts->auto_xray_edit = true;
+ ts->auto_xray_box = true;
+ ts->auto_xray_lasso = true;
+ ts->auto_xray_circle = true;
+ ts->select_through = true;
+ ts->select_through_object = true;
+ ts->select_through_box = true;
+ ts->select_through_lasso = true;
+ ts->select_through_circle = true;
+
+ /* Viewport-Facing Select */
+ ts->viewport_facing_select_mode = 1;
+ ts->viewport_facing_select_vert = 1;
+ ts->viewport_facing_select_edge = 1;
+ ts->viewport_facing_select_face = 1;
}
void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index 4b2acfa7205..bdb327fc5f3 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -434,9 +434,8 @@ void blo_do_versions_userdef(UserDef *userdef)
if (!USER_VERSION_ATLEAST(278, 6)) {
/* Clear preference flags for re-use. */
- userdef->flag &= ~(USER_FLAG_NUMINPUT_ADVANCED | USER_FLAG_UNUSED_2 | USER_FLAG_UNUSED_3 |
- USER_FLAG_UNUSED_6 | USER_FLAG_UNUSED_7 | USER_FLAG_UNUSED_9 |
- USER_DEVELOPER_UI);
+ userdef->flag &= ~(USER_FLAG_NUMINPUT_ADVANCED | USER_FLAG_UNUSED_6 | USER_FLAG_UNUSED_7 |
+ USER_FLAG_UNUSED_9 | USER_DEVELOPER_UI);
userdef->uiflag &= ~(USER_HEADER_BOTTOM);
userdef->transopts &= ~(USER_TR_UNUSED_2 | USER_TR_UNUSED_3 | USER_TR_UNUSED_4 |
USER_TR_UNUSED_6 | USER_TR_UNUSED_7);
diff --git a/source/blender/draw/engines/overlay/overlay_edit_mesh.cc b/source/blender/draw/engines/overlay/overlay_edit_mesh.cc
index 256588e56f2..eff0b81a165 100644
--- a/source/blender/draw/engines/overlay/overlay_edit_mesh.cc
+++ b/source/blender/draw/engines/overlay/overlay_edit_mesh.cc
@@ -59,8 +59,10 @@ void OVERLAY_edit_mesh_cache_init(OVERLAY_Data *vedata)
bool select_edge = pd->edit_mesh.select_edge = (tsettings->selectmode & SCE_SELECT_EDGE) != 0;
bool do_occlude_wire = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_OCCLUDE_WIRE) != 0;
- bool show_face_dots = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_DOT) != 0 ||
- pd->edit_mesh.do_zbufclip;
+ bool show_face_dots = !XRAY_FLAG_ENABLED(draw_ctx->v3d) &&
+ v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_DOT ||
+ XRAY_FLAG_ENABLED(draw_ctx->v3d) &&
+ v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_DOT_XRAY;
pd->edit_mesh.do_faces = true;
pd->edit_mesh.do_edges = true;
diff --git a/source/blender/draw/engines/select/select_draw_utils.c b/source/blender/draw/engines/select/select_draw_utils.c
index 03b189a3e5b..34615e47e16 100644
--- a/source/blender/draw/engines/select/select_draw_utils.c
+++ b/source/blender/draw/engines/select/select_draw_utils.c
@@ -72,7 +72,9 @@ static bool check_ob_drawface_dot(short select_mode, const View3D *v3d, eDrawTyp
{
if (select_mode & SCE_SELECT_FACE) {
if ((dt < OB_SOLID) || XRAY_FLAG_ENABLED(v3d)) {
- return true;
+ if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_DOT_XRAY) {
+ return true;
+ }
}
if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_DOT) {
return true;
diff --git a/source/blender/editors/curves/intern/curves_selection.cc b/source/blender/editors/curves/intern/curves_selection.cc
index 35afb6e1ed4..2af85ee1d7b 100644
--- a/source/blender/editors/curves/intern/curves_selection.cc
+++ b/source/blender/editors/curves/intern/curves_selection.cc
@@ -688,7 +688,8 @@ bool select_lasso(const ViewContext &vc,
int(pos1_proj.y),
int(pos2_proj.x),
int(pos2_proj.y),
- IS_CLIPPED)) {
+ IS_CLIPPED,
+ false)) {
apply_selection_operation_at_index(selection.span, curve_i, sel_op);
changed = true;
break;
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index d7fb108809f..b447630f98b 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -100,7 +100,10 @@ void ED_getTransformOrientationMatrix(const struct Scene *scene,
struct Object *ob,
struct Object *obedit,
short around,
- float r_orientation_mat[3][3]);
+ float r_orientation_mat[3][3],
+ struct BMVert *eve,
+ struct BMEdge *eed,
+ struct BMFace *efa);
int BIF_countTransformOrientation(const struct bContext *C);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 9507ab4d476..f1dfc564208 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -391,11 +391,20 @@ void mesh_foreachScreenEdge_clip_bb_segment(struct ViewContext *vc,
void *userData,
eV3DProjTest clip_flag);
-void mesh_foreachScreenFace(
+void mesh_foreachScreenFaceCenter(
struct ViewContext *vc,
void (*func)(void *userData, struct BMFace *efa, const float screen_co[2], int index),
void *userData,
eV3DProjTest clip_flag);
+void mesh_foreachScreenFaceVerts(struct ViewContext *vc,
+ void (*func)(void *userData,
+ struct BMFace *efa,
+ const float screen_co[][2],
+ int total_count,
+ struct rctf *poly_rect,
+ bool *face_hit),
+ void *userData,
+ const eV3DProjTest clip_flag);
void nurbs_foreachScreenVert(struct ViewContext *vc,
void (*func)(void *userData,
struct Nurb *nu,
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index 6e0edeace6a..0d7b6ca733c 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -447,8 +447,8 @@ DEF_ICON_BLANK(705)
DEF_ICON_BLANK(706)
DEF_ICON_BLANK(707)
DEF_ICON_BLANK(708)
-DEF_ICON_BLANK(709)
-DEF_ICON_BLANK(710)
+DEF_ICON(AUTO_XRAY)
+DEF_ICON(SELECT_THROUGH)
DEF_ICON(SELECT_SET)
DEF_ICON(SELECT_EXTEND)
DEF_ICON(SELECT_SUBTRACT)
diff --git a/source/blender/editors/interface/resources.cc b/source/blender/editors/interface/resources.cc
index 5982f8ad1c9..c457aa38f45 100644
--- a/source/blender/editors/interface/resources.cc
+++ b/source/blender/editors/interface/resources.cc
@@ -229,7 +229,7 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
case TH_HEADER_ACTIVE: {
cp = ts->header;
- const int factor = 5;
+ const int factor = U.header_highlight;
/* Lighten the header color when editor is active. */
header_active[0] = cp[0] > 245 ? cp[0] - factor : cp[0] + factor;
header_active[1] = cp[1] > 245 ? cp[1] - factor : cp[1] + factor;
diff --git a/source/blender/editors/mesh/editmesh_select.cc b/source/blender/editors/mesh/editmesh_select.cc
index 94c2e3352b3..c8ec4ab78c2 100644
--- a/source/blender/editors/mesh/editmesh_select.cc
+++ b/source/blender/editors/mesh/editmesh_select.cc
@@ -233,7 +233,8 @@ static void findnearestvert__doClosest(void *userData,
dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co);
- if (data->use_select_bias && BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ if (!(U.flag & USER_ADJUSTABLE_CLICK_SELECT && U.flag & USER_SELECT_UNBIASED) &&
+ data->use_select_bias && BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
dist_test_bias += FIND_NEAR_SELECT_BIAS;
}
@@ -438,7 +439,8 @@ static void find_nearest_edge__doClosest(
dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co);
- if (data->use_select_bias && BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ if (!(U.flag & USER_ADJUSTABLE_CLICK_SELECT && U.flag & USER_SELECT_UNBIASED) &&
+ data->use_select_bias && BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
dist_test_bias += FIND_NEAR_SELECT_BIAS;
}
@@ -670,7 +672,8 @@ static void findnearestface__doClosest(void *userData,
dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co);
- if (data->use_select_bias && BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ if (!(U.flag & USER_ADJUSTABLE_CLICK_SELECT && U.flag & USER_SELECT_UNBIASED) &&
+ data->use_select_bias && BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
dist_test_bias += FIND_NEAR_SELECT_BIAS;
}
@@ -706,27 +709,26 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc,
uint base_index = 0;
if (!XRAY_FLAG_ENABLED(vc->v3d)) {
- float dist_test;
+ float dist_test = 0.0f;
uint index;
BMFace *efa;
+ uint dist_px_manhattan_test = 0;
{
- uint dist_px_manhattan_test = 0;
- if (*dist_px_manhattan_p != 0.0f && (use_zbuf_single_px == false)) {
- dist_px_manhattan_test = uint(
- ED_view3d_backbuf_sample_size_clamp(vc->region, *dist_px_manhattan_p));
+ if (U.flag & USER_ADJUSTABLE_CLICK_SELECT ||
+ *dist_px_manhattan_p != 0.0f && (use_zbuf_single_px == false)) {
+ dist_px_manhattan_test = (uint)ED_view3d_backbuf_sample_size_clamp(vc->region,
+ *dist_px_manhattan_p);
}
DRW_select_buffer_context_create(bases, bases_len, SCE_SELECT_FACE);
- if (dist_px_manhattan_test == 0) {
+ if (!(U.flag & USER_ADJUSTABLE_CLICK_SELECT) && dist_px_manhattan_test == 0) {
index = DRW_select_buffer_sample_point(vc->depsgraph, vc->region, vc->v3d, vc->mval);
- dist_test = 0.0f;
}
else {
index = DRW_select_buffer_find_nearest_to_point(
vc->depsgraph, vc->region, vc->v3d, vc->mval, 1, UINT_MAX, &dist_px_manhattan_test);
- dist_test = dist_px_manhattan_test;
}
if (index) {
@@ -752,7 +754,7 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc,
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
- mesh_foreachScreenFace(
+ mesh_foreachScreenFaceCenter(
vc, find_nearest_face_center__doZBuf, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
*r_dist_center = data.dist_px_manhattan;
@@ -760,7 +762,14 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc,
/* end exception */
if (efa) {
- if (dist_test < *dist_px_manhattan_p) {
+ if (U.flag & USER_ADJUSTABLE_CLICK_SELECT && dist_px_manhattan_test < *dist_px_manhattan_p) {
+ if (r_base_index) {
+ *r_base_index = base_index;
+ }
+ *dist_px_manhattan_p = dist_px_manhattan_test;
+ return efa;
+ }
+ else if (!(U.flag & USER_ADJUSTABLE_CLICK_SELECT) && dist_test < *dist_px_manhattan_p) {
if (r_base_index) {
*r_base_index = base_index;
}
@@ -804,7 +813,7 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc,
*dist_px_manhattan_p;
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
- mesh_foreachScreenFace(vc, findnearestface__doClosest, &data, clip_flag);
+ mesh_foreachScreenFaceCenter(vc, findnearestface__doClosest, &data, clip_flag);
hit = (data.use_cycle && data.hit_cycle.face) ? &data.hit_cycle : &data.hit;
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 80e5da43423..10dc4b90421 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -3847,6 +3847,61 @@ static void SCREEN_OT_repeat_history(wmOperatorType *ot)
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Invoke Last Operator
+ * \{ */
+
+static int invoke_last_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmOperator *lastop = wm->operators.last;
+
+ /* Seek last registered operator */
+ while (lastop) {
+ if (lastop->type->flag & OPTYPE_REGISTER) {
+ if (STREQ(lastop->idname, "MESH_OT_delete") || STREQ(lastop->idname, "MESH_OT_select_all") ||
+ STREQ(lastop->idname, "MESH_OT_select_mode") ||
+ STREQ(lastop->idname, "OBJECT_OT_editmode_toggle") ||
+ STREQ(lastop->idname, "OBJECT_OT_select_all") ||
+ STREQ(lastop->idname, "TRANSFORM_OT_resize") ||
+ STREQ(lastop->idname, "TRANSFORM_OT_rotate") ||
+ STREQ(lastop->idname, "TRANSFORM_OT_trackball") ||
+ STREQ(lastop->idname, "TRANSFORM_OT_translate")) {
+ lastop = lastop->prev;
+ }
+ else {
+ //printf(lastop->idname, "\n");
+ break;
+ }
+ }
+ else {
+ lastop = lastop->prev;
+ }
+ }
+
+ if (lastop) {
+ WM_operator_free_all_after(wm, lastop);
+ WM_operator_invoke_last(C, lastop);
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+static void SCREEN_OT_invoke_last(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Invoke Last";
+ ot->description = "Invoke last operation";
+ ot->idname = "SCREEN_OT_invoke_last";
+
+ /* api callbacks */
+ ot->exec = invoke_last_exec;
+
+ ot->poll = ED_operator_screenactive;
+}
+
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Redo Operator
* \{ */
@@ -5679,6 +5734,7 @@ void ED_operatortypes_screen(void)
WM_operatortype_append(SCREEN_OT_actionzone);
WM_operatortype_append(SCREEN_OT_repeat_last);
WM_operatortype_append(SCREEN_OT_repeat_history);
+ WM_operatortype_append(SCREEN_OT_invoke_last);
WM_operatortype_append(SCREEN_OT_redo_last);
/* Screen tools. */
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index d5b96e03f13..87fb6e6c77f 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -1235,3 +1235,242 @@ void VIEW3D_OT_toggle_xray(wmOperatorType *ot)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Automatic XRay
+ * \{ */
+
+static int toggle_auto_xray_exec(bContext *C, wmOperator *op)
+{
+ ScrArea *area = CTX_wm_area(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *obedit = CTX_data_edit_object(C);
+ bToolRef *tref = area->runtime.tool;
+ const bool mode_match = obedit ? ts->auto_xray_edit : ts->auto_xray_object;
+
+ if (STREQ(tref->idname, "builtin.select_box") ||
+ STREQ(tref->idname_fallback, "builtin.select_box")) {
+ if (mode_match && ts->auto_xray && ts->auto_xray_box) {
+ ts->auto_xray ^= true;
+ }
+ else {
+ if (!mode_match) {
+ if (obedit) {
+ ts->auto_xray_edit ^= true;
+ }
+ else {
+ ts->auto_xray_object ^= true;
+ }
+ }
+
+ if (!ts->auto_xray) {
+ ts->auto_xray ^= true;
+ }
+
+ if (!ts->auto_xray_box) {
+ ts->auto_xray_box ^= true;
+ }
+ }
+ }
+ else if (STREQ(tref->idname, "builtin.select_lasso") ||
+ STREQ(tref->idname_fallback, "builtin.select_lasso")) {
+ if (mode_match && ts->auto_xray && ts->auto_xray_lasso) {
+ ts->auto_xray ^= true;
+ }
+ else {
+ if (!mode_match) {
+ if (obedit) {
+ ts->auto_xray_edit ^= true;
+ }
+ else {
+ ts->auto_xray_object ^= true;
+ }
+ }
+
+ if (!ts->auto_xray) {
+ ts->auto_xray ^= true;
+ }
+
+ if (!ts->auto_xray_lasso) {
+ ts->auto_xray_lasso ^= true;
+ }
+ }
+ }
+ else if (STREQ(tref->idname, "builtin.select_circle") ||
+ STREQ(tref->idname_fallback, "builtin.select_circle")) {
+ if (mode_match && ts->auto_xray && ts->auto_xray_circle) {
+ ts->auto_xray ^= true;
+ }
+ else {
+ if (!mode_match) {
+ if (obedit) {
+ ts->auto_xray_edit ^= true;
+ }
+ else {
+ ts->auto_xray_object ^= true;
+ }
+ }
+
+ if (!ts->auto_xray) {
+ ts->auto_xray ^= true;
+ }
+
+ if (!ts->auto_xray_circle) {
+ ts->auto_xray_circle ^= true;
+ }
+ }
+ }
+
+ ED_area_tag_redraw(area);
+
+ return OPERATOR_FINISHED;
+}
+
+void VIEW3D_OT_toggle_auto_xray(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Toggle Automatic X-Ray";
+ ot->idname = "VIEW3D_OT_toggle_auto_xray";
+ ot->description = "Transparent scene display during box, lasso, and circle select";
+
+ /* api callbacks */
+ ot->exec = toggle_auto_xray_exec;
+ ot->poll = ED_operator_view3d_active;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Select Through
+ * \{ */
+
+static int toggle_select_through_exec(bContext *C, wmOperator *op)
+{
+ ScrArea *area = CTX_wm_area(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *obedit = CTX_data_edit_object(C);
+ bToolRef *tref = area->runtime.tool;
+ const bool mode_match = obedit ? ts->select_through_edit : ts->select_through_object;
+
+ if (STREQ(tref->idname, "builtin.select_box") ||
+ STREQ(tref->idname_fallback, "builtin.select_box")) {
+ if (mode_match && ts->select_through && ts->select_through_box) {
+ ts->select_through ^= true;
+ }
+ else {
+ if (!mode_match) {
+ if (obedit) {
+ ts->select_through_edit ^= true;
+ }
+ else {
+ ts->select_through_object ^= true;
+ }
+ }
+
+ if (!ts->select_through) {
+ ts->select_through ^= true;
+ }
+
+ if (!ts->select_through_box) {
+ ts->select_through_box ^= true;
+ }
+ }
+ }
+ else if (STREQ(tref->idname, "builtin.select_lasso") ||
+ STREQ(tref->idname_fallback, "builtin.select_lasso")) {
+ if (mode_match && ts->select_through && ts->select_through_lasso) {
+ ts->select_through ^= true;
+ }
+ else {
+ if (!mode_match) {
+ if (obedit) {
+ ts->select_through_edit ^= true;
+ }
+ else {
+ ts->select_through_object ^= true;
+ }
+ }
+
+ if (!ts->select_through) {
+ ts->select_through ^= true;
+ }
+
+ if (!ts->select_through_lasso) {
+ ts->select_through_lasso ^= true;
+ }
+ }
+ }
+ else if (STREQ(tref->idname, "builtin.select_circle") ||
+ STREQ(tref->idname_fallback, "builtin.select_circle")) {
+ if (mode_match && ts->select_through && ts->select_through_circle) {
+ ts->select_through ^= true;
+ }
+ else {
+ if (!mode_match) {
+ if (obedit) {
+ ts->select_through_edit ^= true;
+ }
+ else {
+ ts->select_through_object ^= true;
+ }
+ }
+
+ if (!ts->select_through) {
+ ts->select_through ^= true;
+ }
+
+ if (!ts->select_through_circle) {
+ ts->select_through_circle ^= true;
+ }
+ }
+ }
+
+ ED_area_tag_redraw(area);
+
+ return OPERATOR_FINISHED;
+}
+
+void VIEW3D_OT_toggle_select_through(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Toggle Select Through";
+ ot->idname = "VIEW3D_OT_toggle_select_through";
+ ot->description = "Select occluded objects and mesh elements with box, lasso, and circle select";
+
+ /* api callbacks */
+ ot->exec = toggle_select_through_exec;
+ ot->poll = ED_operator_view3d_active;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Facedots
+ * \{ */
+
+static int toggle_facedots_exec(bContext *C, wmOperator *op)
+{
+ ScrArea *area = CTX_wm_area(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ if (!XRAY_FLAG_ENABLED(v3d)) {
+ v3d->overlay.edit_flag ^= V3D_OVERLAY_EDIT_FACE_DOT;
+ }
+ else {
+ v3d->overlay.edit_flag ^= V3D_OVERLAY_EDIT_FACE_DOT_XRAY;
+ }
+ ED_area_tag_redraw(area);
+ return OPERATOR_FINISHED;
+}
+
+void VIEW3D_OT_toggle_facedots(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Toggle Facedots";
+ ot->idname = "VIEW3D_OT_toggle_facedots";
+ ot->description = "Show face center dots in the current shading mode";
+ /* api callbacks */
+ ot->exec = toggle_facedots_exec;
+ ot->poll = ED_operator_view3d_active;
+}
+
+/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index b94833dd276..02d852e87ff 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -55,6 +55,9 @@ void VIEW3D_OT_render_border(struct wmOperatorType *ot);
void VIEW3D_OT_clear_render_border(struct wmOperatorType *ot);
void VIEW3D_OT_toggle_shading(struct wmOperatorType *ot);
void VIEW3D_OT_toggle_xray(struct wmOperatorType *ot);
+void VIEW3D_OT_toggle_auto_xray(struct wmOperatorType *ot);
+void VIEW3D_OT_toggle_select_through(struct wmOperatorType *ot);
+void VIEW3D_OT_toggle_facedots(struct wmOperatorType *ot);
/* view3d_draw.c */
diff --git a/source/blender/editors/space_view3d/view3d_iterators.cc b/source/blender/editors/space_view3d/view3d_iterators.cc
index e7e8eb5b275..d5e560331c4 100644
--- a/source/blender/editors/space_view3d/view3d_iterators.cc
+++ b/source/blender/editors/space_view3d/view3d_iterators.cc
@@ -13,6 +13,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "BLI_bitmap.h"
#include "BLI_math_geom.h"
#include "BLI_rect.h"
#include "BLI_utildefines.h"
@@ -38,6 +39,8 @@
#include "ED_screen.h"
#include "ED_view3d.h"
+#include "MEM_guardedalloc.h"
+
/* -------------------------------------------------------------------- */
/** \name Internal Clipping Utilities
* \{ */
@@ -238,7 +241,7 @@ struct foreachScreenEdge_userData {
int content_planes_len;
};
-struct foreachScreenFace_userData {
+struct foreachScreenFaceCenter_userData {
void (*func)(void *userData, BMFace *efa, const float screen_co_b[2], int index);
void *userData;
ViewContext vc;
@@ -536,12 +539,12 @@ void mesh_foreachScreenEdge_clip_bb_segment(ViewContext *vc,
/** \name Edit-Mesh: For Each Screen Face Center
* \{ */
-static void mesh_foreachScreenFace__mapFunc(void *userData,
+static void mesh_foreachScreenFaceCenter__mapFunc(void *userData,
int index,
const float cent[3],
const float /*no*/[3])
{
- foreachScreenFace_userData *data = static_cast(userData);
+ foreachScreenFaceCenter_userData *data = static_cast(userData);
BMFace *efa = BM_face_at_index(data->vc.em->bm, index);
if (UNLIKELY(BM_elem_flag_test(efa, BM_ELEM_HIDDEN))) {
return;
@@ -556,14 +559,14 @@ static void mesh_foreachScreenFace__mapFunc(void *userData,
data->func(data->userData, efa, screen_co, index);
}
-void mesh_foreachScreenFace(
+void mesh_foreachScreenFaceCenter(
ViewContext *vc,
void (*func)(void *userData, BMFace *efa, const float screen_co_b[2], int index),
void *userData,
const eV3DProjTest clip_flag)
{
BLI_assert((clip_flag & V3D_PROJ_TEST_CLIP_CONTENT) == 0);
- foreachScreenFace_userData data;
+ foreachScreenFaceCenter_userData data;
Mesh *me = editbmesh_get_eval_cage_from_orig(
vc->depsgraph, vc->scene, vc->obedit, &CD_MASK_BAREMESH);
@@ -580,16 +583,150 @@ void mesh_foreachScreenFace(
const int face_dot_tags_num = me->runtime->subsurf_face_dot_tags.size();
if (face_dot_tags_num && (face_dot_tags_num != me->totvert)) {
BKE_mesh_foreach_mapped_subdiv_face_center(
- me, mesh_foreachScreenFace__mapFunc, &data, MESH_FOREACH_NOP);
+ me, mesh_foreachScreenFaceCenter__mapFunc, &data, MESH_FOREACH_NOP);
}
else {
BKE_mesh_foreach_mapped_face_center(
- me, mesh_foreachScreenFace__mapFunc, &data, MESH_FOREACH_NOP);
+ me, mesh_foreachScreenFaceCenter__mapFunc, &data, MESH_FOREACH_NOP);
}
}
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Edit-Mesh: For Each Screen Face Verts
+ * \{ */
+
+void mesh_foreachScreenFaceVerts(ViewContext *vc,
+ void (*func)(void *userData,
+ struct BMFace *efa,
+ const float screen_co[][2],
+ int total_count,
+ rctf *screen_rect,
+ bool *face_hit),
+ void *userData,
+ const eV3DProjTest clip_flag)
+{
+ ED_view3d_check_mats_rv3d(vc->rv3d);
+ BM_mesh_elem_table_ensure(vc->em->bm, BM_FACE);
+
+ BMFace *efa;
+ const BMesh *bm = vc->em->bm;
+
+ float temp_screen_co[2];
+ int total_length = 0;
+
+ float(*screen_coords)[2] = static_cast(
+ MEM_mallocN(sizeof(float) * 2 * bm->totvert, __func__));
+ int face_screen_verts_size = 4;
+ float(*face_screen_verts)[2] = static_cast(
+ MEM_mallocN(sizeof(int) * 2 * face_screen_verts_size, __func__));
+
+ /* This makes only sense on subdivided meshes.*/
+ BLI_bitmap *faces_visited;
+ int cage_index = BKE_modifiers_get_cage_index(vc->scene, vc->obedit, NULL, 1);
+ const bool cage_display = cage_index != -1;
+ if (cage_display) {
+ faces_visited = BLI_BITMAP_NEW((size_t)bm->totface, __func__);
+ }
+
+ /* Transform and store all visible verts into screen coords. */
+ for (int i = 0; i < bm->totvert; i++) {
+ BMVert *bmvert = BM_vert_at_index(vc->em->bm, i);
+
+ if (BM_elem_flag_test_bool(bmvert, BM_ELEM_HIDDEN)) {
+ continue;
+ }
+
+ if (ED_view3d_project_float_object(vc->region, bmvert->co, temp_screen_co, clip_flag) ==
+ V3D_PROJ_RET_OK) {
+ screen_coords[i][0] = temp_screen_co[0];
+ screen_coords[i][1] = temp_screen_co[1];
+ }
+ else {
+ screen_coords[i][0] = 0.0f;
+ screen_coords[i][1] = 0.0f;
+ }
+ }
+
+ const int *poly_index = static_cast(CustomData_get_layer(&bm->pdata, CD_ORIGINDEX));
+ const bool use_original_index = poly_index != 0;
+
+ rctf poly_rect_data;
+ rctf *poly_rect = &poly_rect_data;
+ bool face_hit = false;
+
+ /* Collect polygon verts and send off per poly callback. */
+ for (int i = 0; i < bm->totface; i++) {
+ int original_index = i;
+ if (use_original_index) {
+ original_index = *poly_index++;
+ if (original_index == ORIGINDEX_NONE) {
+ continue;
+ }
+ }
+
+ if (cage_display && BLI_BITMAP_TEST(faces_visited, original_index)) {
+ continue;
+ }
+
+ efa = BM_face_at_index(vc->em->bm, original_index);
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+
+ if (bm->totvert > face_screen_verts_size) {
+ face_screen_verts_size = bm->totvert;
+ MEM_freeN(face_screen_verts);
+ face_screen_verts = static_cast(
+ MEM_mallocN(sizeof(float) * 2 * face_screen_verts_size, __func__));
+ }
+
+ total_length = 0;
+ BLI_rctf_init_minmax(poly_rect);
+
+ bool skip = false;
+
+ BMLoop *l_first, *l_iter;
+ int j = 0;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
+ do {
+ const int k = BM_elem_index_get(l_iter->v);
+ face_screen_verts[j][0] = screen_coords[k][0];
+ face_screen_verts[j][1] = screen_coords[k][1];
+
+ /* Ignore polygons with invalid screen coords.*/
+ if (face_screen_verts[j][0] == 0.0f && face_screen_verts[j][1] == 0.0f) {
+ skip = true;
+ break;
+ }
+
+ total_length++, j++;
+ BLI_rctf_do_minmax_v(poly_rect, screen_coords[k]);
+ } while ((l_iter = l_iter->next) != l_first);
+
+ if (skip) {
+ continue;
+ }
+
+ face_hit = false;
+
+ func(
+ userData, efa, (const float(*)[2])face_screen_verts, total_length, poly_rect, &face_hit);
+
+ if (cage_display && face_hit) {
+ BLI_BITMAP_ENABLE(faces_visited, original_index);
+ }
+ }
+ }
+
+ if (cage_display) {
+ MEM_freeN(faces_visited);
+ }
+ MEM_freeN(screen_coords);
+ MEM_freeN(face_screen_verts);
+}
+
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Edit-Nurbs: For Each Screen Vertex
* \{ */
diff --git a/source/blender/editors/space_view3d/view3d_navigate.c b/source/blender/editors/space_view3d/view3d_navigate.c
index d47f7325cc5..54ffc020477 100644
--- a/source/blender/editors/space_view3d/view3d_navigate.c
+++ b/source/blender/editors/space_view3d/view3d_navigate.c
@@ -99,6 +99,26 @@ void view3d_operator_properties_common(wmOperatorType *ot, const enum eV3D_OpPro
if (flag & V3D_OP_PROP_USE_MOUSE_INIT) {
WM_operator_properties_use_cursor_init(ot);
}
+
+ if (flag & V3D_OP_PROP_FRAME_SELECTED_DISTANCE) {
+ PropertyRNA *prop;
+ prop = RNA_def_int(ot->srna,
+ "frame_selected_distance",
+ 0,
+ 0,
+ 1000,
+ "Camera Offset",
+ "Distance to put camera from selected",
+ 0,
+ 1000);
+
+ }
+
+ if (flag & V3D_OP_PROP_ZOOM_SPEED) {
+ PropertyRNA *prop;
+ prop = RNA_def_float(
+ ot->srna, "zoom_speed", 1.2f, 1.001, 10, "Zoom Speed", "Speed to zoom camera", 1.001f, 10);
+ }
}
/** \} */
@@ -665,7 +685,8 @@ static void view3d_from_minmax(bContext *C,
const float min[3],
const float max[3],
bool ok_dist,
- const int smooth_viewtx)
+ const int smooth_viewtx,
+ const int view_dist)
{
RegionView3D *rv3d = region->regiondata;
float afm[3];
@@ -708,7 +729,7 @@ static void view3d_from_minmax(bContext *C,
v3d, region, depsgraph, persp, true, (size / 2) * VIEW3D_MARGIN);
if (rv3d->is_persp) {
/* don't zoom closer than the near clipping plane */
- new_dist = max_ff(new_dist, v3d->clip_start * 1.5f);
+ new_dist = max_ff(new_dist, v3d->clip_start * 1.5f + view_dist);
}
}
}
@@ -754,7 +775,8 @@ static void view3d_from_minmax_multi(bContext *C,
const float min[3],
const float max[3],
const bool ok_dist,
- const int smooth_viewtx)
+ const int smooth_viewtx,
+ const int view_dist)
{
ScrArea *area = CTX_wm_area(C);
ARegion *region;
@@ -764,7 +786,7 @@ static void view3d_from_minmax_multi(bContext *C,
/* when using all regions, don't jump out of camera view,
* but _do_ allow locked cameras to be moved */
if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) {
- view3d_from_minmax(C, v3d, region, min, max, ok_dist, smooth_viewtx);
+ view3d_from_minmax(C, v3d, region, min, max, ok_dist, smooth_viewtx, view_dist);
}
}
}
@@ -844,10 +866,10 @@ static int view3d_all_exec(bContext *C, wmOperator *op)
ED_view3d_smooth_view_undo_begin(C, area);
if (use_all_regions) {
- view3d_from_minmax_multi(C, v3d, min, max, true, smooth_viewtx);
+ view3d_from_minmax_multi(C, v3d, min, max, true, smooth_viewtx, 0);
}
else {
- view3d_from_minmax(C, v3d, region, min, max, true, smooth_viewtx);
+ view3d_from_minmax(C, v3d, region, min, max, true, smooth_viewtx, 0);
}
ED_view3d_smooth_view_undo_end(C, area, op->type->name, false);
@@ -906,6 +928,7 @@ static int viewselected_exec(bContext *C, wmOperator *op)
/* any one of the regions may be locked */
(use_all_regions && v3d->flag2 & V3D_LOCK_CAMERA));
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
+ const int view_dist = RNA_int_get(op->ptr, "frame_selected_distance");
INIT_MINMAX(min, max);
if (is_face_map) {
@@ -1020,10 +1043,10 @@ static int viewselected_exec(bContext *C, wmOperator *op)
ED_view3d_smooth_view_undo_begin(C, area);
if (use_all_regions) {
- view3d_from_minmax_multi(C, v3d, min, max, ok_dist, smooth_viewtx);
+ view3d_from_minmax_multi(C, v3d, min, max, ok_dist, smooth_viewtx, view_dist);
}
else {
- view3d_from_minmax(C, v3d, region, min, max, ok_dist, smooth_viewtx);
+ view3d_from_minmax(C, v3d, region, min, max, ok_dist, smooth_viewtx, view_dist);
}
ED_view3d_smooth_view_undo_end(C, area, op->type->name, false);
@@ -1046,7 +1069,8 @@ void VIEW3D_OT_view_selected(wmOperatorType *ot)
ot->flag = 0;
/* properties */
- view3d_operator_properties_common(ot, V3D_OP_PROP_USE_ALL_REGIONS);
+ view3d_operator_properties_common(
+ ot, V3D_OP_PROP_USE_ALL_REGIONS | V3D_OP_PROP_FRAME_SELECTED_DISTANCE);
}
/** \} */
@@ -1205,7 +1229,7 @@ static int view_axis_exec(bContext *C, wmOperator *op)
Object *obedit = CTX_data_edit_object(C);
/* same as transform gizmo when normal is set */
ED_getTransformOrientationMatrix(
- scene, view_layer, v3d, obact, obedit, V3D_AROUND_ACTIVE, twmat);
+ scene, view_layer, v3d, obact, obedit, V3D_AROUND_ACTIVE, twmat, NULL, NULL, NULL);
align_quat = align_quat_buf;
mat3_to_quat(align_quat, twmat);
invert_qt_normalized(align_quat);
diff --git a/source/blender/editors/space_view3d/view3d_navigate.h b/source/blender/editors/space_view3d/view3d_navigate.h
index 46dacbc606f..a641a3748fa 100644
--- a/source/blender/editors/space_view3d/view3d_navigate.h
+++ b/source/blender/editors/space_view3d/view3d_navigate.h
@@ -34,6 +34,8 @@ enum eV3D_OpPropFlag {
V3D_OP_PROP_DELTA = (1 << 1),
V3D_OP_PROP_USE_ALL_REGIONS = (1 << 2),
V3D_OP_PROP_USE_MOUSE_INIT = (1 << 3),
+ V3D_OP_PROP_FRAME_SELECTED_DISTANCE = (1 << 4),
+ V3D_OP_PROP_ZOOM_SPEED = (1 << 5),
};
enum {
diff --git a/source/blender/editors/space_view3d/view3d_navigate_zoom.c b/source/blender/editors/space_view3d/view3d_navigate_zoom.c
index 51aab367959..a5f8341dd27 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_zoom.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_zoom.c
@@ -506,9 +506,10 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
}
ED_view3d_dist_range_get(v3d, dist_range);
+ const float zoom_speed = RNA_float_get(op->ptr, "zoom_speed");
if (delta < 0) {
- const float step = 1.2f;
+ const float step = zoom_speed;
if (use_cam_zoom) {
view_zoom_to_window_xy_camera(scene, depsgraph, v3d, region, step, zoom_xy);
}
@@ -519,7 +520,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
}
}
else {
- const float step = 1.0f / 1.2f;
+ const float step = 1.0f / zoom_speed;
if (use_cam_zoom) {
view_zoom_to_window_xy_camera(scene, depsgraph, v3d, region, step, zoom_xy);
}
@@ -631,8 +632,9 @@ void VIEW3D_OT_zoom(wmOperatorType *ot)
ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY;
/* properties */
- view3d_operator_properties_common(
- ot, V3D_OP_PROP_DELTA | V3D_OP_PROP_MOUSE_CO | V3D_OP_PROP_USE_MOUSE_INIT);
+ view3d_operator_properties_common(ot,
+ V3D_OP_PROP_DELTA | V3D_OP_PROP_MOUSE_CO |
+ V3D_OP_PROP_USE_MOUSE_INIT | V3D_OP_PROP_ZOOM_SPEED);
}
/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index ad12aef6d67..5551508fe8a 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -200,6 +200,9 @@ void view3d_operatortypes(void)
WM_operatortype_append(VIEW3D_OT_toggle_shading);
WM_operatortype_append(VIEW3D_OT_toggle_xray);
WM_operatortype_append(VIEW3D_OT_toggle_matcap_flip);
+ WM_operatortype_append(VIEW3D_OT_toggle_auto_xray);
+ WM_operatortype_append(VIEW3D_OT_toggle_select_through);
+ WM_operatortype_append(VIEW3D_OT_toggle_facedots);
WM_operatortype_append(VIEW3D_OT_ruler_add);
WM_operatortype_append(VIEW3D_OT_ruler_remove);
diff --git a/source/blender/editors/space_view3d/view3d_select.cc b/source/blender/editors/space_view3d/view3d_select.cc
index 51c6517c1d1..f763166b90f 100644
--- a/source/blender/editors/space_view3d/view3d_select.cc
+++ b/source/blender/editors/space_view3d/view3d_select.cc
@@ -81,6 +81,7 @@
#include "ED_screen.h"
#include "ED_sculpt.h"
#include "ED_select_utils.h"
+#include "ED_transform.h"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -104,7 +105,12 @@
float ED_view3d_select_dist_px(void)
{
- return 75.0f * U.pixelsize;
+ if (U.flag & USER_ADJUSTABLE_CLICK_SELECT) {
+ return U.selection_radius * U.pixelsize;
+ }
+ else {
+ return 75.0f * U.pixelsize;
+ }
}
void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc, Depsgraph *depsgraph)
@@ -240,15 +246,339 @@ static void editselect_buf_cache_init_with_generic_userdata(wmGenericUserData *w
/** \name Internal Edit-Mesh Utilities
* \{ */
-static bool edbm_backbuf_check_and_select_verts(EditSelectBuf_Cache *esel,
+struct BoxSelectUserData {
+ ViewContext *vc;
+ const rcti *rect;
+ const rctf *rect_fl;
+ rctf _rect_fl;
+ eSelectOp sel_op;
+ eBezTriple_Flag select_flag;
+ int edge_style;
+ int face_style;
+ bool check_mesh_direction;
+
+ /* runtime */
+ bool is_done;
+ bool is_changed;
+};
+
+struct LassoSelectUserData {
+ ViewContext *vc;
+ const rcti *rect;
+ const rctf *rect_fl;
+ rctf _rect_fl;
+ const int (*mcoords)[2];
+ int mcoords_len;
+ eSelectOp sel_op;
+ eBezTriple_Flag select_flag;
+ int edge_style;
+ int face_style;
+ bool check_mesh_direction;
+
+ /* runtime */
+ int pass;
+ bool is_done;
+ bool is_changed;
+};
+
+struct CircleSelectUserData {
+ ViewContext *vc;
+ bool select;
+ int mval[2];
+ float mval_fl[2];
+ float radius;
+ float radius_squared;
+ eBezTriple_Flag select_flag;
+ int edge_style;
+ int face_style;
+ bool check_mesh_direction;
+
+ /* runtime */
+ bool is_changed;
+};
+
+bool edbm_normal_facing_viewport(ViewContext *vc,
+ struct BMVert *eve,
+ struct BMEdge *eed,
+ struct BMFace *efa,
+ bool use_direction)
+{
+ ToolSettings *ts = vc->scene->toolsettings;
+ float meshmat[3][3];
+ bool backface = false;
+ int direction = 0;
+ if (eve != NULL) {
+ ED_getTransformOrientationMatrix(vc->scene,
+ vc->view_layer,
+ vc->v3d,
+ vc->obact,
+ vc->obedit,
+ V3D_AROUND_ACTIVE,
+ meshmat,
+ eve,
+ NULL,
+ NULL);
+ direction = ts->viewport_facing_select_vert;
+ if (use_direction && (direction == 4 || direction == 8)) {
+ backface = true;
+ }
+ }
+ else if (eed != NULL) {
+ ED_getTransformOrientationMatrix(vc->scene,
+ vc->view_layer,
+ vc->v3d,
+ vc->obact,
+ vc->obedit,
+ V3D_AROUND_ACTIVE,
+ meshmat,
+ NULL,
+ eed,
+ NULL);
+ direction = ts->viewport_facing_select_edge;
+ if (use_direction && (direction == 4 || direction == 8)) {
+ backface = true;
+ }
+ }
+ else if (efa != NULL) {
+ ED_getTransformOrientationMatrix(vc->scene,
+ vc->view_layer,
+ vc->v3d,
+ vc->obact,
+ vc->obedit,
+ V3D_AROUND_ACTIVE,
+ meshmat,
+ NULL,
+ NULL,
+ efa);
+ direction = ts->viewport_facing_select_face;
+ if (use_direction && (direction == 4 || direction == 8)) {
+ backface = true;
+ }
+ }
+ normalize_m3(meshmat);
+ invert_m3(meshmat);
+ float meshcol3[3] = {0, 0, 0};
+ meshcol3[0] = meshmat[0][2];
+ meshcol3[1] = meshmat[1][2];
+ meshcol3[2] = meshmat[2][2];
+ float viewcol3[3] = {0, 0, 0};
+ viewcol3[0] = vc->rv3d->viewmat[0][2];
+ viewcol3[1] = vc->rv3d->viewmat[1][2];
+ viewcol3[2] = vc->rv3d->viewmat[2][2];
+ bool mesh_facing;
+ if (backface) {
+ mesh_facing = dot_v3v3(meshcol3, viewcol3) < -ts->viewport_facing_select_threshold;
+ }
+ else {
+ mesh_facing = dot_v3v3(meshcol3, viewcol3) > ts->viewport_facing_select_threshold;
+ }
+ return mesh_facing;
+}
+
+bool edbm_facing_viewport_precheck(ToolSettings *ts, int style, bool xray)
+{
+ if (!ts->viewport_facing_select) {
+ return false;
+ }
+ const bool mode_match = xray ? ts->viewport_facing_select_mode == 1 ||
+ ts->viewport_facing_select_mode == 4 :
+ ts->viewport_facing_select_mode < 4;
+ const bool check_mesh_facing = mode_match && style > 0 && style < 16;
+ return check_mesh_facing;
+}
+
+bool edbm_facing_viewport(ViewContext *vc, BMVert *eve, BMEdge *eed, BMFace *efa, int style)
+{
+ BMIter iter;
+ bool mesh_facing = false;
+ if (eve != NULL) {
+ /* viewport-facing or rear-facing vert */
+ mesh_facing = edbm_normal_facing_viewport(vc, eve, NULL, NULL, true);
+ if (!mesh_facing && eve->e && eve->e->l && (style == 2 || style == 8)) {
+ BM_ITER_ELEM (efa, &iter, eve, BM_FACES_OF_VERT) {
+ const bool eve_efa_facing = edbm_normal_facing_viewport(vc, NULL, NULL, efa, false);
+ /* vert of a viewport-facing face */
+ if (style == 2) {
+ if (eve_efa_facing) {
+ mesh_facing = true;
+ break;
+ }
+ }
+ /* vert of a rear-facing face */
+ else if (!eve_efa_facing) {
+ mesh_facing = true;
+ break;
+ }
+ }
+ }
+ }
+ else if (eed != NULL) {
+ /* viewport-facing or rear-facing edge */
+ mesh_facing = edbm_normal_facing_viewport(vc, NULL, eed, NULL, true);
+ if (!mesh_facing && eed->l && (style == 2 || style == 8)) {
+ BM_ITER_ELEM (efa, &iter, eed, BM_FACES_OF_EDGE) {
+ const bool eed_efa_facing = edbm_normal_facing_viewport(vc, NULL, NULL, efa, false);
+ /* edge of a viewport-facing face */
+ if (style == 2) {
+ if (eed_efa_facing) {
+ mesh_facing = true;
+ break;
+ }
+ }
+ /* edge of a rear-facing face */
+ else if (!eed_efa_facing) {
+ mesh_facing = true;
+ break;
+ }
+ }
+ }
+ }
+ else if (efa != NULL) {
+ /* viewport-facing or rear-facing face */
+ mesh_facing = edbm_normal_facing_viewport(vc, NULL, NULL, efa, true);
+ if (!mesh_facing && (style == 2 || style == 8)) {
+ BM_ITER_ELEM (eve, &iter, efa, BM_VERTS_OF_FACE) {
+ const bool efa_eve_facing = edbm_normal_facing_viewport(vc, eve, NULL, NULL, false);
+ /* face has a viewport-facing vert */
+ if (style == 2) {
+ if (efa_eve_facing) {
+ mesh_facing = true;
+ break;
+ }
+ }
+ /* face has a rear-facing vert */
+ else if (!efa_eve_facing) {
+ mesh_facing = true;
+ break;
+ }
+ }
+ }
+ }
+ return mesh_facing;
+}
+
+bool edbm_circle_enclose_mesh(BMEdge *eed, BMFace *efa, struct CircleSelectUserData *data)
+{
+ BMVert *eve;
+ BMIter iter;
+ bool enclose = false;
+
+ if (eed != NULL) {
+ BM_ITER_ELEM (eve, &iter, eed, BM_VERTS_OF_EDGE) {
+ float vertv3[3] = {eve->co[0], eve->co[1], eve->co[2]};
+ float vertv2[2] = {0.0f, 0.0f};
+ ED_view3d_project_float_object(
+ data->vc->region, vertv3, vertv2, V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB);
+ enclose = len_squared_v2v2(data->mval_fl, vertv2) <= data->radius_squared;
+ if (!enclose) {
+ break;
+ }
+ }
+ }
+ else if (efa != NULL) {
+ BM_ITER_ELEM (eve, &iter, efa, BM_VERTS_OF_FACE) {
+ float vertv3[3] = {eve->co[0], eve->co[1], eve->co[2]};
+ float vertv2[2] = {0.0f, 0.0f};
+ ED_view3d_project_float_object(
+ data->vc->region, vertv3, vertv2, V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB);
+ enclose = len_squared_v2v2(data->mval_fl, vertv2) <= data->radius_squared;
+ if (!enclose) {
+ break;
+ }
+ }
+ }
+ return enclose;
+}
+
+bool edbm_center_face(ViewContext *vc,
+ BMFace *efa,
+ const rctf *rect,
+ struct LassoSelectUserData *lassoData,
+ struct CircleSelectUserData *circleData)
+{
+ BMVert *eve;
+ BMIter iter;
+ float centerv3[3] = {0.0f, 0.0f, 0.0f};
+ float centerv2[2] = {0.0f, 0.0f};
+ bool center_face = false;
+
+ /* tri */
+ if (efa->len == 3) {
+ float tri_vco[3][3] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
+ int tri_index = 0;
+ BM_ITER_ELEM (eve, &iter, efa, BM_VERTS_OF_FACE) {
+ tri_vco[tri_index][0] = eve->co[0];
+ tri_vco[tri_index][1] = eve->co[1];
+ tri_vco[tri_index][2] = eve->co[2];
+ tri_index++;
+ }
+ float triv1[3] = {tri_vco[0][0], tri_vco[0][1], tri_vco[0][2]};
+ float triv2[3] = {tri_vco[1][0], tri_vco[1][1], tri_vco[1][2]};
+ float triv3[3] = {tri_vco[2][0], tri_vco[2][1], tri_vco[2][2]};
+ mid_v3_v3v3v3(centerv3, triv1, triv2, triv3);
+ }
+ /* quad */
+ else if (efa->len == 4) {
+ float quad_vco[4][3] = {
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
+ int quad_index = 0;
+ BM_ITER_ELEM (eve, &iter, efa, BM_VERTS_OF_FACE) {
+ quad_vco[quad_index][0] = eve->co[0];
+ quad_vco[quad_index][1] = eve->co[1];
+ quad_vco[quad_index][2] = eve->co[2];
+ quad_index++;
+ }
+ float quadv1[3] = {quad_vco[0][0], quad_vco[0][1], quad_vco[0][2]};
+ float quadv2[3] = {quad_vco[1][0], quad_vco[1][1], quad_vco[1][2]};
+ float quadv3[3] = {quad_vco[2][0], quad_vco[2][1], quad_vco[2][2]};
+ float quadv4[3] = {quad_vco[3][0], quad_vco[3][1], quad_vco[3][2]};
+ mid_v3_v3v3v3v3(centerv3, quadv1, quadv2, quadv3, quadv4);
+ }
+ /* ngon */
+ else {
+ const float w = 1.0f / (float)efa->len;
+ BM_ITER_ELEM (eve, &iter, efa, BM_VERTS_OF_FACE) {
+ madd_v3_v3fl(centerv3, eve->co, w);
+ }
+ }
+ ED_view3d_project_float_object(
+ vc->region, centerv3, centerv2, V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB);
+
+ /* lasso center */
+ if (lassoData != NULL) {
+ center_face = BLI_rctf_isect_pt_v(rect, centerv2) &&
+ BLI_lasso_is_point_inside(lassoData->mcoords,
+ lassoData->mcoords_len,
+ centerv2[0],
+ centerv2[1],
+ IS_CLIPPED);
+ }
+ /* circle center */
+ else if (circleData != NULL) {
+ center_face = (len_squared_v2v2(circleData->mval_fl, centerv2) <= circleData->radius_squared);
+ }
+ /* box center */
+ else {
+ center_face = BLI_rctf_isect_pt_v(rect, centerv2);
+ }
+ return center_face;
+}
+
+
+
+static bool edbm_backbuf_check_and_select_verts(ViewContext *vc,
+ EditSelectBuf_Cache *esel,
Depsgraph *depsgraph,
Object *ob,
BMEditMesh *em,
const eSelectOp sel_op)
{
+ ToolSettings *ts = vc->scene->toolsettings;
BMVert *eve;
BMIter iter;
bool changed = false;
+ const int style = ts->viewport_facing_select_vert;
+ const bool check_mesh_facing = edbm_facing_viewport_precheck(ts, style, false);
const BLI_bitmap *select_bitmap = esel->select_bitmap;
uint index = DRW_select_buffer_context_offset_for_object_elem(depsgraph, ob, SCE_SELECT_VERTEX);
@@ -261,7 +591,12 @@ static bool edbm_backbuf_check_and_select_verts(EditSelectBuf_Cache *esel,
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT);
const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index);
- const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ bool mesh_facing = true;
+ if (is_inside && check_mesh_facing) {
+ mesh_facing = edbm_facing_viewport(vc, eve, NULL, NULL, style);
+ }
+ const int sel_op_result = ED_select_op_action_deselected(
+ sel_op, is_select, is_inside && mesh_facing);
if (sel_op_result != -1) {
BM_vert_select_set(em->bm, eve, sel_op_result);
changed = true;
@@ -272,15 +607,20 @@ static bool edbm_backbuf_check_and_select_verts(EditSelectBuf_Cache *esel,
return changed;
}
-static bool edbm_backbuf_check_and_select_edges(EditSelectBuf_Cache *esel,
+static bool edbm_backbuf_check_and_select_edges(void *userData,
+ EditSelectBuf_Cache *esel,
Depsgraph *depsgraph,
Object *ob,
BMEditMesh *em,
const eSelectOp sel_op)
{
+ CircleSelectUserData *data = static_cast(userData);
+ ToolSettings *ts = data->vc->scene->toolsettings;
BMEdge *eed;
BMIter iter;
bool changed = false;
+ const int style = ts->viewport_facing_select_edge;
+ const bool check_mesh_facing = edbm_facing_viewport_precheck(ts, style, false);
const BLI_bitmap *select_bitmap = esel->select_bitmap;
uint index = DRW_select_buffer_context_offset_for_object_elem(depsgraph, ob, SCE_SELECT_EDGE);
@@ -293,7 +633,19 @@ static bool edbm_backbuf_check_and_select_edges(EditSelectBuf_Cache *esel,
if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index);
- const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ bool enclose_edge = true;
+ bool mesh_facing = true;
+
+ if (data->edge_style == 4 && is_inside) {
+ enclose_edge = edbm_circle_enclose_mesh(eed, NULL, data);
+ }
+
+ if (check_mesh_facing && is_inside) {
+ mesh_facing = edbm_facing_viewport(data->vc, NULL, eed, NULL, style);
+ }
+
+ const int sel_op_result = ED_select_op_action_deselected(
+ sel_op, is_select, is_inside && enclose_edge && mesh_facing);
if (sel_op_result != -1) {
BM_edge_select_set(em->bm, eed, sel_op_result);
changed = true;
@@ -304,28 +656,74 @@ static bool edbm_backbuf_check_and_select_edges(EditSelectBuf_Cache *esel,
return changed;
}
-static bool edbm_backbuf_check_and_select_faces(EditSelectBuf_Cache *esel,
+static bool edbm_backbuf_check_and_select_faces(ViewContext *vc,
+ EditSelectBuf_Cache *esel,
Depsgraph *depsgraph,
Object *ob,
BMEditMesh *em,
- const eSelectOp sel_op)
+ const eSelectOp sel_op,
+ const rcti *rect,
+ const int face_style,
+ void *ldata,
+ void *cdata)
{
+ ToolSettings *ts = vc->scene->toolsettings;
+ BMIter iter, viter;
BMFace *efa;
- BMIter iter;
+ BMVert *eve;
+ rctf rectf;
bool changed = false;
-
+ const int style = ts->viewport_facing_select_face;
+ const bool check_mesh_facing = edbm_facing_viewport_precheck(ts, style, false);
const BLI_bitmap *select_bitmap = esel->select_bitmap;
+ LassoSelectUserData *lassoData = static_cast(ldata);
+ CircleSelectUserData *circleData = static_cast(cdata);
uint index = DRW_select_buffer_context_offset_for_object_elem(depsgraph, ob, SCE_SELECT_FACE);
- if (index == 0) {
+ uint vindex = DRW_select_buffer_context_offset_for_object_elem(depsgraph, ob, SCE_SELECT_VERTEX);
+
+ if (rect != NULL) {
+ BLI_rctf_rcti_copy(&rectf, rect);
+ }
+
+ if (index == 0 || vindex == 0) {
return false;
}
index -= 1;
+ vindex -= 1;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT);
const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index);
- const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ bool enclose_face = true;
+ bool center_face = true;
+ bool mesh_facing = true;
+
+ if (face_style > 2 && is_inside) {
+ if (face_style == 4) {
+ if (circleData != NULL) {
+ enclose_face = edbm_circle_enclose_mesh(NULL, efa, circleData);
+ }
+ else {
+ BM_ITER_ELEM (eve, &viter, efa, BM_VERTS_OF_FACE) {
+ enclose_face = BLI_BITMAP_TEST_BOOL(select_bitmap, vindex + BM_elem_index_get(eve));
+ if (!enclose_face) {
+ break;
+ }
+ }
+ }
+ }
+ else {
+ center_face = edbm_center_face(vc, efa, &rectf, lassoData, circleData);
+ }
+ }
+
+ if (check_mesh_facing && is_inside) {
+ mesh_facing = edbm_facing_viewport(vc, NULL, NULL, efa, style);
+ }
+
+ const int sel_op_result = ED_select_op_action_deselected(
+ sel_op, is_select, is_inside && enclose_face && center_face && mesh_facing);
if (sel_op_result != -1) {
BM_face_select_set(em->bm, efa, sel_op_result);
changed = true;
@@ -404,28 +802,14 @@ static bool edbm_backbuf_check_and_select_faces_obmode(Mesh *me,
/** \name Lasso Select
* \{ */
-struct LassoSelectUserData {
- ViewContext *vc;
- const rcti *rect;
- const rctf *rect_fl;
- rctf _rect_fl;
- const int (*mcoords)[2];
- int mcoords_len;
- eSelectOp sel_op;
- eBezTriple_Flag select_flag;
-
- /* runtime */
- int pass;
- bool is_done;
- bool is_changed;
-};
-
static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data,
ViewContext *vc,
const rcti *rect,
const int (*mcoords)[2],
const int mcoords_len,
- const eSelectOp sel_op)
+ const eSelectOp sel_op,
+ const int edge_style,
+ const int face_style)
{
r_data->vc = vc;
@@ -438,6 +822,9 @@ static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data,
r_data->sel_op = sel_op;
/* SELECT by default, but can be changed if needed (only few cases use and respect this). */
r_data->select_flag = (eBezTriple_Flag)SELECT;
+ r_data->edge_style = edge_style;
+ r_data->face_style = face_style;
+ r_data->check_mesh_direction = false;
/* runtime */
r_data->pass = 0;
@@ -527,8 +914,12 @@ static void do_lasso_select_pose__do_tag(void *userData,
}
if (BLI_rctf_isect_segment(data->rect_fl, screen_co_a, screen_co_b) &&
- BLI_lasso_is_edge_inside(
- data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX)) {
+ BLI_lasso_is_edge_inside(data->mcoords,
+ data->mcoords_len,
+ UNPACK2(screen_co_a),
+ UNPACK2(screen_co_b),
+ INT_MAX,
+ false)) {
pchan->bone->flag |= BONE_DONE;
data->is_changed = true;
}
@@ -552,7 +943,7 @@ static void do_lasso_tag_pose(ViewContext *vc,
BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
view3d_userdata_lassoselect_init(
- &data, vc, &rect, mcoords, mcoords_len, static_cast(0));
+ &data, vc, &rect, mcoords, mcoords_len, static_cast(0), 0, 0);
ED_view3d_init_mats_rv3d(vc_tmp.obact, vc->rv3d);
@@ -563,42 +954,225 @@ static void do_lasso_tag_pose(ViewContext *vc,
V3D_PROJ_TEST_CLIP_DEFAULT | V3D_PROJ_TEST_CLIP_CONTENT_DEFAULT);
}
+/**
+ * Compare result of 'GPU_select': 'GPUSelectResult',
+ * Needed for stable sorting, so cycling through all items near the cursor behaves predictably.
+ */
+static int gpu_select_buffer_depth_id_cmp(const void *sel_a_p, const void *sel_b_p)
+{
+ GPUSelectResult *a = (GPUSelectResult *)sel_a_p;
+ GPUSelectResult *b = (GPUSelectResult *)sel_b_p;
+
+ if (a->depth < b->depth) {
+ return -1;
+ }
+ if (a->depth > b->depth) {
+ return 1;
+ }
+
+ /* Depths match, sort by id. */
+ uint sel_a = a->id;
+ uint sel_b = b->id;
+
+#ifdef __BIG_ENDIAN__
+ BLI_endian_switch_uint32(&sel_a);
+ BLI_endian_switch_uint32(&sel_b);
+#endif
+
+ if (sel_a < sel_b) {
+ return -1;
+ }
+ if (sel_a > sel_b) {
+ return 1;
+ }
+ return 0;
+}
+
static bool do_lasso_select_objects(ViewContext *vc,
const int mcoords[][2],
const int mcoords_len,
- const eSelectOp sel_op)
+ const eSelectOp sel_op,
+ wmOperator *op,
+ int circle_data[3])
{
View3D *v3d = vc->v3d;
+ int totobj = MAXPICKELEMS; /* XXX solve later */
+ /* Selection buffer has bones potentially too, so we add #MAXPICKELEMS. */
+ GPUSelectResult *buffer = static_cast(
+ MEM_mallocN((totobj + MAXPICKELEMS) * sizeof(GPUSelectResult), __func__));
+ ToolSettings *ts = vc->scene->toolsettings;
- bool changed = false;
- if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- changed |= object_deselect_all_visible(vc->scene, vc->view_layer, vc->v3d);
+ const int select_through_int = RNA_enum_get(op->ptr, "select_through");
+ const bool select_through = circle_data == NULL ?
+ ts->select_through && ts->select_through_object &&
+ ts->select_through_lasso :
+ ts->select_through && ts->select_through_object &&
+ ts->select_through_circle;
+ float region_co[2];
+ float mval_fl[2];
+ if (circle_data != NULL) {
+ mval_fl[0] = circle_data[0];
+ mval_fl[1] = circle_data[1];
}
- BKE_view_layer_synced_ensure(vc->scene, vc->view_layer);
- LISTBASE_FOREACH (Base *, base, BKE_view_layer_object_bases_get(vc->view_layer)) {
- if (BASE_SELECTABLE(v3d, base)) { /* Use this to avoid unnecessary lasso look-ups. */
- float region_co[2];
- const bool is_select = base->flag & BASE_SELECTED;
- const bool is_inside = (ED_view3d_project_base(vc->region, base, region_co) ==
- V3D_PROJ_RET_OK) &&
- BLI_lasso_is_point_inside(mcoords,
- mcoords_len,
- int(region_co[0]),
- int(region_co[1]),
- /* Dummy value. */
- INT_MAX);
- const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
- if (sel_op_result != -1) {
- ED_object_base_select(base, sel_op_result ? BA_SELECT : BA_DESELECT);
- changed = true;
+ bool changed = false;
+
+ if (select_through && circle_data == NULL) {
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
+ changed |= object_deselect_all_visible(vc->scene, vc->view_layer, vc->v3d);
+ }
+ BKE_view_layer_synced_ensure(vc->scene, vc->view_layer);
+ LISTBASE_FOREACH (Base *, base, BKE_view_layer_object_bases_get(vc->view_layer)) {
+ if (BASE_SELECTABLE(v3d, base)) { /* Use this to avoid unnecessary lasso look-ups. */
+ float region_co[2];
+ const bool is_select = base->flag & BASE_SELECTED;
+ const bool is_inside = (ED_view3d_project_base(vc->region, base, region_co) ==
+ V3D_PROJ_RET_OK) &&
+ BLI_lasso_is_point_inside(mcoords,
+ mcoords_len,
+ int(region_co[0]),
+ int(region_co[1]),
+ /* Dummy value. */
+ INT_MAX);
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ ED_object_base_select(base, sel_op_result ? BA_SELECT : BA_DESELECT);
+ changed = true;
+ }
}
}
+
+ if (changed) {
+ DEG_id_tag_update(&vc->scene->id, ID_RECALC_SELECT);
+ WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, vc->scene);
+ }
}
- if (changed) {
- DEG_id_tag_update(&vc->scene->id, ID_RECALC_SELECT);
- WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, vc->scene);
+ else {
+ int hits = 0;
+ rcti rect_data;
+ rcti *rect = &rect_data;
+ blender::Vector bases;
+
+ if (circle_data != NULL) {
+ int point[4][2] = {};
+
+ for (int i = 0; i < 4; i++) {
+ float angle = 6.28f * (i + 1) / 4;
+ point[i][0] = circle_data[0] + circle_data[2] * cosf(angle);
+ point[i][1] = circle_data[1] + circle_data[2] * sinf(angle);
+ }
+ rect->xmin = rect->xmax = point[0][0];
+ rect->ymin = rect->ymax = point[0][1];
+ uint a;
+ for (a = 1; a < 4; a++) {
+ if (point[a][0] < rect->xmin) {
+ rect->xmin = point[a][0];
+ }
+ else if (point[a][0] > rect->xmax) {
+ rect->xmax = point[a][0];
+ }
+ if (point[a][1] < rect->ymin) {
+ rect->ymin = point[a][1];
+ }
+ else if (point[a][1] > rect->ymax) {
+ rect->ymax = point[a][1];
+ }
+ }
+ }
+ else {
+ BLI_lasso_boundbox(rect, mcoords, mcoords_len);
+ }
+ const eV3DSelectObjectFilter select_filter = ED_view3d_select_filter_from_mode(vc->scene,
+ vc->obact);
+ if (XRAY_FLAG_ENABLED(vc->v3d) || select_through) {
+ hits = view3d_opengl_select(
+ vc, buffer, (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL, select_filter);
+ }
+ else {
+ hits = view3d_opengl_select(
+ vc, buffer, (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_PICK_NEAREST, select_filter);
+ }
+ BKE_view_layer_synced_ensure(vc->scene, vc->view_layer);
+ LISTBASE_FOREACH (Base *, base, BKE_view_layer_object_bases_get(vc->view_layer)) {
+ base->object->id.tag &= ~LIB_TAG_DOIT;
+ }
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
+ changed |= object_deselect_all_visible(vc->scene, vc->view_layer, vc->v3d);
+ }
+
+ ListBase *object_bases = BKE_view_layer_object_bases_get(vc->view_layer);
+ if ((hits == -1) && !SEL_OP_USE_OUTSIDE(sel_op)) {
+ goto finally;
+ }
+
+ LISTBASE_FOREACH (Base *, base, object_bases) {
+ if (BASE_SELECTABLE(v3d, base)) {
+ if ((base->object->runtime.select_id & 0x0000FFFF) != 0) {
+ bases.append(base);
+ }
+ }
+ }
+
+ /* The draw order doesn't always match the order we populate the engine, see: T51695. */
+ qsort(buffer, hits, sizeof(GPUSelectResult), gpu_select_buffer_depth_id_cmp);
+
+ for (const GPUSelectResult *buf_iter = buffer, *buf_end = buf_iter + hits; buf_iter < buf_end;
+ buf_iter++) {
+ bPoseChannel *pchan_dummy;
+ Base *base = ED_armature_base_and_pchan_from_select_buffer(
+ bases.data(), bases.size(), buf_iter->id, &pchan_dummy);
+ if (base != nullptr) {
+ base->object->id.tag |= LIB_TAG_DOIT;
+ }
+ }
+
+ for (Base *base = static_cast(object_bases->first); base && hits; base = base->next) {
+ if (BASE_SELECTABLE(v3d, base)) {
+ const bool is_select = base->flag & BASE_SELECTED;
+ bool is_inside = false;
+
+ if (circle_data == NULL) {
+ is_inside = base->object->id.tag & LIB_TAG_DOIT &&
+ (ED_view3d_project_base(vc->region, base, region_co) == V3D_PROJ_RET_OK) &&
+ BLI_lasso_is_point_inside(mcoords,
+ mcoords_len,
+ int(region_co[0]),
+ int(region_co[1]),
+ /* Dummy value. */
+ INT_MAX);
+ }
+ else {
+ is_inside = base->object->id.tag & LIB_TAG_DOIT ?
+ RNA_boolean_get(op->ptr, "select_origin_circle") ?
+ (ED_view3d_project_float_global(vc->region,
+ base->object->object_to_world[3],
+ region_co,
+ V3D_PROJ_TEST_CLIP_DEFAULT) ==
+ V3D_PROJ_RET_OK) ?
+ len_squared_v2v2(mval_fl, region_co) <= circle_data[2] * circle_data[2] :
+ false :
+ true :
+ false;
+ }
+
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ ED_object_base_select(base, sel_op_result ? BA_SELECT : BA_DESELECT);
+ changed = true;
+ }
+ }
+ }
+
+ finally:
+
+ MEM_freeN(buffer);
+
+ if (changed) {
+ DEG_id_tag_update(&vc->scene->id, ID_RECALC_SELECT);
+ WM_event_add_notifier(vc->C, NC_SCENE | ND_OB_SELECT, vc->scene);
+ }
}
+
return changed;
}
@@ -712,7 +1286,15 @@ static void do_lasso_select_mesh__doSelectVert(void *userData,
(BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
BLI_lasso_is_point_inside(
data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED));
- const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ bool mesh_facing = true;
+
+ if (is_inside && data->check_mesh_direction) {
+ mesh_facing = edbm_facing_viewport(
+ data->vc, eve, NULL, NULL, data->vc->scene->toolsettings->viewport_facing_select_vert);
+ }
+
+ const int sel_op_result = ED_select_op_action_deselected(
+ data->sel_op, is_select, is_inside && mesh_facing);
if (sel_op_result != -1) {
BM_vert_select_set(data->vc->em->bm, eve, sel_op_result);
data->is_changed = true;
@@ -733,6 +1315,7 @@ static void do_lasso_select_mesh__doSelectEdge_pass0(void *user_data,
user_data);
LassoSelectUserData *data = data_for_edge->data;
bool is_visible = true;
+ bool mesh_facing = true;
if (data_for_edge->backbuf_offset) {
uint bitmap_inedx = data_for_edge->backbuf_offset + index - 1;
is_visible = BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, bitmap_inedx);
@@ -745,7 +1328,14 @@ static void do_lasso_select_mesh__doSelectEdge_pass0(void *user_data,
data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), IS_CLIPPED) &&
BLI_lasso_is_point_inside(
data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), IS_CLIPPED));
- const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+
+ if (is_inside && data->check_mesh_direction) {
+ mesh_facing = edbm_facing_viewport(
+ data->vc, NULL, eed, NULL, data->vc->scene->toolsettings->viewport_facing_select_edge);
+ }
+
+ const int sel_op_result = ED_select_op_action_deselected(
+ data->sel_op, is_select, is_inside && mesh_facing);
if (sel_op_result != -1) {
BM_edge_select_set(data->vc->em->bm, eed, sel_op_result);
data->is_done = true;
@@ -762,6 +1352,7 @@ static void do_lasso_select_mesh__doSelectEdge_pass1(void *user_data,
user_data);
LassoSelectUserData *data = data_for_edge->data;
bool is_visible = true;
+ bool mesh_facing = true;
if (data_for_edge->backbuf_offset) {
uint bitmap_inedx = data_for_edge->backbuf_offset + index - 1;
is_visible = BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, bitmap_inedx);
@@ -772,15 +1363,23 @@ static void do_lasso_select_mesh__doSelectEdge_pass1(void *user_data,
data->mcoords_len,
UNPACK2(screen_co_a),
UNPACK2(screen_co_b),
- IS_CLIPPED));
- const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ IS_CLIPPED,
+ false));
+
+ if (is_inside && data->check_mesh_direction) {
+ mesh_facing = edbm_facing_viewport(
+ data->vc, NULL, eed, NULL, data->vc->scene->toolsettings->viewport_facing_select_edge);
+ }
+
+ const int sel_op_result = ED_select_op_action_deselected(
+ data->sel_op, is_select, is_inside && mesh_facing);
if (sel_op_result != -1) {
BM_edge_select_set(data->vc->em->bm, eed, sel_op_result);
data->is_changed = true;
}
}
-static void do_lasso_select_mesh__doSelectFace(void *userData,
+static void do_lasso_select_mesh__doSelectFaceCenter(void *userData,
BMFace *efa,
const float screen_co[2],
int /*index*/)
@@ -791,7 +1390,86 @@ static void do_lasso_select_mesh__doSelectFace(void *userData,
(BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
BLI_lasso_is_point_inside(
data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED));
- const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ bool mesh_facing = true;
+
+ if (is_inside && data->check_mesh_direction) {
+ mesh_facing = edbm_facing_viewport(
+ data->vc, NULL, NULL, efa, data->vc->scene->toolsettings->viewport_facing_select_face);
+ }
+
+ const int sel_op_result = ED_select_op_action_deselected(
+ data->sel_op, is_select, is_inside && mesh_facing);
+ if (sel_op_result != -1) {
+ BM_face_select_set(data->vc->em->bm, efa, sel_op_result);
+ data->is_changed = true;
+ }
+}
+
+static void do_lasso_select_mesh__doSelectFace(void *user_data,
+ BMFace *efa,
+ const float screen_co[][2],
+ int total_count,
+ rctf *screen_rect,
+ bool *face_hit)
+{
+ LassoSelectUserData *data = static_cast(user_data);
+ int style = data->face_style;
+
+ if (!BLI_rctf_isect(data->rect_fl, screen_rect, NULL))
+ return;
+
+ bool inside = false;
+ bool mesh_facing = true;
+ for (int i = 0; i < total_count; i++) {
+
+ int a = i;
+ int b = (i + 1) % total_count;
+
+ /* enclose */
+ if (style == 4) {
+ inside = BLI_lasso_is_edge_inside(data->mcoords,
+ data->mcoords_len,
+ UNPACK2(screen_co[a]),
+ UNPACK2(screen_co[b]),
+ IS_CLIPPED,
+ true);
+ if (!inside) {
+ break;
+ }
+ }
+ /* touch */
+ else {
+ inside = BLI_lasso_is_edge_inside(data->mcoords,
+ data->mcoords_len,
+ UNPACK2(screen_co[a]),
+ UNPACK2(screen_co[b]),
+ IS_CLIPPED,
+ false);
+ if (inside) {
+ break;
+ }
+ }
+ }
+
+ /* touch interior of face */
+ if (style == 2) {
+ if (!inside) {
+ float point[2] = {static_cast(data->mcoords[0][0]), static_cast(data->mcoords[0][1])};
+ inside = isect_point_poly_v2(point, screen_co, total_count, true);
+ }
+ }
+
+ *face_hit = inside;
+
+ const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT);
+
+ if (inside && data->check_mesh_direction) {
+ mesh_facing = edbm_facing_viewport(
+ data->vc, NULL, NULL, efa, data->vc->scene->toolsettings->viewport_facing_select_face);
+ }
+
+ const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, inside && mesh_facing);
+
if (sel_op_result != -1) {
BM_face_select_set(data->vc->em->bm, efa, sel_op_result);
data->is_changed = true;
@@ -802,7 +1480,8 @@ static bool do_lasso_select_mesh(ViewContext *vc,
wmGenericUserData *wm_userdata,
const int mcoords[][2],
const int mcoords_len,
- const eSelectOp sel_op)
+ const eSelectOp sel_op,
+ wmOperator *op)
{
LassoSelectUserData data;
ToolSettings *ts = vc->scene->toolsettings;
@@ -813,7 +1492,8 @@ static bool do_lasso_select_mesh(ViewContext *vc,
BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
+ view3d_userdata_lassoselect_init(
+ &data, vc, &rect, mcoords, mcoords_len, sel_op, RNA_enum_get(op->ptr, "edge_type"), RNA_enum_get(op->ptr, "face_type"));
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
if (vc->em->bm->totvertsel) {
@@ -827,12 +1507,22 @@ static bool do_lasso_select_mesh(ViewContext *vc,
GPU_matrix_set(vc->rv3d->viewmat);
- const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d);
+ const bool select_through = ts->select_through && ts->select_through_edit &&
+ ts->select_through_lasso;
+ const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d) && !select_through;
EditSelectBuf_Cache *esel = static_cast(wm_userdata->data);
if (use_zbuf) {
if (wm_userdata->data == nullptr) {
- editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, ts->selectmode);
+ /* for near enclose face */
+ if (data.face_style == 4 && ts->selectmode & SCE_SELECT_FACE &&
+ !(ts->selectmode & SCE_SELECT_VERTEX)) {
+ editselect_buf_cache_init_with_generic_userdata(
+ wm_userdata, vc, ts->selectmode | SCE_SELECT_VERTEX);
+ }
+ else {
+ editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, ts->selectmode);
+ }
esel = static_cast(wm_userdata->data);
esel->select_bitmap = DRW_select_buffer_bitmap_from_poly(
vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, nullptr);
@@ -842,9 +1532,12 @@ static bool do_lasso_select_mesh(ViewContext *vc,
if (ts->selectmode & SCE_SELECT_VERTEX) {
if (use_zbuf) {
data.is_changed |= edbm_backbuf_check_and_select_verts(
- esel, vc->depsgraph, vc->obedit, vc->em, sel_op);
+ vc, esel, vc->depsgraph, vc->obedit, vc->em, sel_op);
}
else {
+ data.check_mesh_direction = edbm_facing_viewport_precheck(
+ ts, ts->viewport_facing_select_vert, true);
+
mesh_foreachScreenVert(
vc, do_lasso_select_mesh__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
}
@@ -860,12 +1553,20 @@ static bool do_lasso_select_mesh(ViewContext *vc,
const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_NEAR |
(use_zbuf ? (eV3DProjTest)0 : V3D_PROJ_TEST_CLIP_BB);
- /* Fully inside. */
- mesh_foreachScreenEdge_clip_bb_segment(
- vc, do_lasso_select_mesh__doSelectEdge_pass0, &data_for_edge, clip_flag);
- if (data.is_done == false) {
- /* Fall back to partially inside.
- * Clip content to account for edges partially behind the view. */
+
+ data.check_mesh_direction = use_zbuf ?
+ edbm_facing_viewport_precheck(
+ ts, ts->viewport_facing_select_edge, false) :
+ data.check_mesh_direction = edbm_facing_viewport_precheck(
+ ts, ts->viewport_facing_select_edge, true);
+
+ /* Fully inside, hybrid and enclose edge */
+ if (data.edge_style != 2) {
+ mesh_foreachScreenEdge_clip_bb_segment(
+ vc, do_lasso_select_mesh__doSelectEdge_pass0, &data_for_edge, clip_flag);
+ }
+ /* Partially inside, hybrid and touch edge */
+ if (data.edge_style == 2 || data.edge_style == 1 && data.is_done == false) {
mesh_foreachScreenEdge_clip_bb_segment(vc,
do_lasso_select_mesh__doSelectEdge_pass1,
&data_for_edge,
@@ -875,12 +1576,33 @@ static bool do_lasso_select_mesh(ViewContext *vc,
if (ts->selectmode & SCE_SELECT_FACE) {
if (use_zbuf) {
- data.is_changed |= edbm_backbuf_check_and_select_faces(
- esel, vc->depsgraph, vc->obedit, vc->em, sel_op);
+ data.is_changed |= edbm_backbuf_check_and_select_faces(vc,
+ esel,
+ vc->depsgraph,
+ vc->obedit,
+ vc->em,
+ sel_op,
+ &rect,
+ data.face_style,
+ &data,
+ NULL);
}
else {
- mesh_foreachScreenFace(
- vc, do_lasso_select_mesh__doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+ data.check_mesh_direction = edbm_facing_viewport_precheck(
+ ts, ts->viewport_facing_select_face, true);
+
+ /* xray center and auto face with fallback for touch and enclose intersect */
+ if (data.face_style == 1 || data.face_style == 8 || SEL_OP_USE_OUTSIDE(sel_op)) {
+ mesh_foreachScreenFaceCenter(
+ vc, do_lasso_select_mesh__doSelectFaceCenter, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+ }
+ /* xray touch and enclose face - doesn't work for intersect */
+ else {
+ mesh_foreachScreenFaceVerts(vc,
+ do_lasso_select_mesh__doSelectFace,
+ &data,
+ V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB);
+ }
}
}
@@ -944,7 +1666,7 @@ static bool do_lasso_select_curve(ViewContext *vc,
BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op, 0, 0);
Curve *curve = (Curve *)vc->obedit->data;
ListBase *nurbs = BKE_curve_editNurbs_get(curve);
@@ -993,7 +1715,7 @@ static bool do_lasso_select_lattice(ViewContext *vc,
BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op, 0, 0);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
data.is_changed |= ED_lattice_flags_set(vc->obedit, 0);
@@ -1022,7 +1744,8 @@ static void do_lasso_select_armature__doSelectBone(void *userData,
if (screen_co_a[0] != IS_CLIPPED) {
if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) &&
BLI_lasso_is_point_inside(
- data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), INT_MAX)) {
+ data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), INT_MAX),
+ false) {
is_inside_flag |= BONESEL_ROOT;
}
}
@@ -1033,7 +1756,8 @@ static void do_lasso_select_armature__doSelectBone(void *userData,
if (screen_co_b[0] != IS_CLIPPED) {
if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_b)) &&
BLI_lasso_is_point_inside(
- data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), INT_MAX)) {
+ data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), INT_MAX),
+ false) {
is_inside_flag |= BONESEL_TIP;
}
}
@@ -1047,7 +1771,8 @@ static void do_lasso_select_armature__doSelectBone(void *userData,
data->mcoords_len,
UNPACK2(screen_co_a),
UNPACK2(screen_co_b),
- INT_MAX)) {
+ INT_MAX,
+ false)) {
is_inside_flag |= BONESEL_BONE;
}
}
@@ -1076,7 +1801,7 @@ static void do_lasso_select_armature__doSelectBone_clip_content(void *userData,
}
if (BLI_lasso_is_edge_inside(
- data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX)) {
+ data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX, false)) {
is_inside_flag |= BONESEL_BONE;
}
@@ -1093,7 +1818,7 @@ static bool do_lasso_select_armature(ViewContext *vc,
BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op, 0, 0);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
data.is_changed |= ED_armature_edit_deselect_all_visible(vc->obedit);
@@ -1153,7 +1878,7 @@ static bool do_lasso_select_meta(ViewContext *vc,
BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op, 0, 0);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
data.is_changed |= BKE_mball_deselect_all(mb);
@@ -1237,7 +1962,8 @@ static bool do_lasso_select_paintvert(ViewContext *vc,
LassoSelectUserData_ForMeshVert data;
data.select_vert = select_vert.span;
- view3d_userdata_lassoselect_init(&data.lasso_data, vc, &rect, mcoords, mcoords_len, sel_op);
+ view3d_userdata_lassoselect_init(
+ &data.lasso_data, vc, &rect, mcoords, mcoords_len, sel_op, 0, 0);
ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d);
@@ -1302,7 +2028,8 @@ static bool view3d_lasso_select(bContext *C,
ViewContext *vc,
const int mcoords[][2],
const int mcoords_len,
- const eSelectOp sel_op)
+ const eSelectOp sel_op,
+ wmOperator *op)
{
using namespace blender;
Object *ob = CTX_data_active_object(C);
@@ -1332,7 +2059,7 @@ static bool view3d_lasso_select(bContext *C,
}
}
else {
- changed_multi |= do_lasso_select_objects(vc, mcoords, mcoords_len, sel_op);
+ changed_multi |= do_lasso_select_objects(vc, mcoords, mcoords_len, sel_op, op, NULL);
if (changed_multi) {
ED_outliner_select_sync_from_object_tag(C);
}
@@ -1346,7 +2073,7 @@ static bool view3d_lasso_select(bContext *C,
switch (vc->obedit->type) {
case OB_MESH:
- changed = do_lasso_select_mesh(vc, wm_userdata, mcoords, mcoords_len, sel_op);
+ changed = do_lasso_select_mesh(vc, wm_userdata, mcoords, mcoords_len, sel_op, op);
break;
case OB_CURVES_LEGACY:
case OB_SURF:
@@ -1417,7 +2144,7 @@ static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
ED_view3d_viewcontext_init(C, &vc, depsgraph);
eSelectOp sel_op = static_cast(RNA_enum_get(op->ptr, "mode"));
- bool changed_multi = view3d_lasso_select(C, &vc, mcoords, mcoords_len, sel_op);
+ bool changed_multi = view3d_lasso_select(C, &vc, mcoords, mcoords_len, sel_op, op);
MEM_freeN((void *)mcoords);
@@ -2140,40 +2867,6 @@ static int mixed_bones_object_selectbuffer_extended(ViewContext *vc,
return hits;
}
-/**
- * Compare result of 'GPU_select': 'GPUSelectResult',
- * Needed for stable sorting, so cycling through all items near the cursor behaves predictably.
- */
-static int gpu_select_buffer_depth_id_cmp(const void *sel_a_p, const void *sel_b_p)
-{
- GPUSelectResult *a = (GPUSelectResult *)sel_a_p;
- GPUSelectResult *b = (GPUSelectResult *)sel_b_p;
-
- if (a->depth < b->depth) {
- return -1;
- }
- if (a->depth > b->depth) {
- return 1;
- }
-
- /* Depths match, sort by id. */
- uint sel_a = a->id;
- uint sel_b = b->id;
-
-#ifdef __BIG_ENDIAN__
- BLI_endian_switch_uint32(&sel_a);
- BLI_endian_switch_uint32(&sel_b);
-#endif
-
- if (sel_a < sel_b) {
- return -1;
- }
- if (sel_a > sel_b) {
- return 1;
- }
- return 0;
-}
-
/**
* \param has_bones: When true, skip non-bone hits, also allow bases to be used
* that are visible but not select-able,
@@ -3277,23 +3970,12 @@ void VIEW3D_OT_select(wmOperatorType *ot)
/** \name Box Select
* \{ */
-struct BoxSelectUserData {
- ViewContext *vc;
- const rcti *rect;
- const rctf *rect_fl;
- rctf _rect_fl;
- eSelectOp sel_op;
- eBezTriple_Flag select_flag;
-
- /* runtime */
- bool is_done;
- bool is_changed;
-};
-
static void view3d_userdata_boxselect_init(BoxSelectUserData *r_data,
ViewContext *vc,
const rcti *rect,
- const eSelectOp sel_op)
+ const eSelectOp sel_op,
+ const int edge_style,
+ const int face_style)
{
r_data->vc = vc;
@@ -3304,6 +3986,9 @@ static void view3d_userdata_boxselect_init(BoxSelectUserData *r_data,
r_data->sel_op = sel_op;
/* SELECT by default, but can be changed if needed (only few cases use and respect this). */
r_data->select_flag = (eBezTriple_Flag)SELECT;
+ r_data->edge_style = edge_style;
+ r_data->face_style = face_style;
+ r_data->check_mesh_direction = false;
/* runtime */
r_data->is_done = false;
@@ -3379,7 +4064,7 @@ static bool do_paintvert_box_select(ViewContext *vc,
BoxSelectUserData_ForMeshVert data;
data.select_vert = select_vert.span;
- view3d_userdata_boxselect_init(&data.box_data, vc, rect, sel_op);
+ view3d_userdata_boxselect_init(&data.box_data, vc, rect, sel_op, 0, 0);
ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d);
@@ -3485,7 +4170,7 @@ static bool do_nurbs_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel
const bool deselect_all = (sel_op == SEL_OP_SET);
BoxSelectUserData data;
- view3d_userdata_boxselect_init(&data, vc, rect, sel_op);
+ view3d_userdata_boxselect_init(&data, vc, rect, sel_op, 0, 0);
Curve *curve = (Curve *)vc->obedit->data;
ListBase *nurbs = BKE_curve_editNurbs_get(curve);
@@ -3524,7 +4209,7 @@ static bool do_lattice_box_select(ViewContext *vc, rcti *rect, const eSelectOp s
{
BoxSelectUserData data;
- view3d_userdata_boxselect_init(&data, vc, rect, sel_op);
+ view3d_userdata_boxselect_init(&data, vc, rect, sel_op, 0, 0);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
data.is_changed |= ED_lattice_flags_set(vc->obedit, 0);
@@ -3545,7 +4230,15 @@ static void do_mesh_box_select__doSelectVert(void *userData,
BoxSelectUserData *data = static_cast(userData);
const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT);
const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
- const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+
+ bool mesh_facing = true;
+ if (is_inside && data->check_mesh_direction) {
+ mesh_facing = edbm_facing_viewport(
+ data->vc, eve, NULL, NULL, data->vc->scene->toolsettings->viewport_facing_select_vert);
+ }
+
+ const int sel_op_result = ED_select_op_action_deselected(
+ data->sel_op, is_select, is_inside && mesh_facing);
if (sel_op_result != -1) {
BM_vert_select_set(data->vc->em->bm, eve, sel_op_result);
data->is_changed = true;
@@ -3566,6 +4259,7 @@ static void do_mesh_box_select__doSelectEdge_pass0(
userData);
BoxSelectUserData *data = data_for_edge->data;
bool is_visible = true;
+ bool mesh_facing = true;
if (data_for_edge->backbuf_offset) {
uint bitmap_inedx = data_for_edge->backbuf_offset + index - 1;
is_visible = BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, bitmap_inedx);
@@ -3574,7 +4268,14 @@ static void do_mesh_box_select__doSelectEdge_pass0(
const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
const bool is_inside = (is_visible &&
edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b));
- const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+
+ if (is_inside && data->check_mesh_direction) {
+ mesh_facing = edbm_facing_viewport(
+ data->vc, NULL, eed, NULL, data->vc->scene->toolsettings->viewport_facing_select_edge);
+ }
+
+ const int sel_op_result = ED_select_op_action_deselected(
+ data->sel_op, is_select, is_inside && mesh_facing);
if (sel_op_result != -1) {
BM_edge_select_set(data->vc->em->bm, eed, sel_op_result);
data->is_done = true;
@@ -3591,6 +4292,7 @@ static void do_mesh_box_select__doSelectEdge_pass1(
userData);
BoxSelectUserData *data = data_for_edge->data;
bool is_visible = true;
+ bool mesh_facing = true;
if (data_for_edge->backbuf_offset) {
uint bitmap_inedx = data_for_edge->backbuf_offset + index - 1;
is_visible = BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, bitmap_inedx);
@@ -3598,13 +4300,79 @@ static void do_mesh_box_select__doSelectEdge_pass1(
const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
const bool is_inside = (is_visible && edge_inside_rect(data->rect_fl, screen_co_a, screen_co_b));
- const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+
+ if (is_inside && data->check_mesh_direction) {
+ mesh_facing = edbm_facing_viewport(
+ data->vc, NULL, eed, NULL, data->vc->scene->toolsettings->viewport_facing_select_edge);
+ }
+
+ const int sel_op_result = ED_select_op_action_deselected(
+ data->sel_op, is_select, is_inside && mesh_facing);
if (sel_op_result != -1) {
BM_edge_select_set(data->vc->em->bm, eed, sel_op_result);
data->is_changed = true;
}
}
+
static void do_mesh_box_select__doSelectFace(void *userData,
+ BMFace *efa,
+ const float screen_co[][2],
+ int total_count,
+ rctf *screen_rect,
+ bool *face_hit)
+{
+ BoxSelectUserData *data = static_cast(userData);
+
+ if (!BLI_rctf_isect(data->rect_fl, screen_rect, NULL))
+ return;
+
+ bool inside = false;
+ bool mesh_facing = true;
+ for (int i = 0; i < total_count; i++) {
+
+ int a = i;
+ int b = (i + 1) % total_count;
+
+ /* enclose */
+ if (data->face_style == 4) {
+ inside = edge_fully_inside_rect(data->rect_fl, screen_co[a], screen_co[b]);
+ if (!inside) {
+ break;
+ }
+ }
+ /* touch */
+ else {
+ inside = edge_inside_rect(data->rect_fl, screen_co[a], screen_co[b]);
+ if (inside) {
+ break;
+ }
+ }
+ }
+
+ /* touch interior of face */
+ if (data->face_style == 2 && !inside) {
+ float point[2] = {data->rect_fl->xmax, data->rect_fl->ymax};
+ inside = isect_point_poly_v2(point, screen_co, total_count, true);
+ }
+
+ *face_hit = inside;
+
+ const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT);
+
+ if (inside && data->check_mesh_direction) {
+ mesh_facing = edbm_facing_viewport(
+ data->vc, NULL, NULL, efa, data->vc->scene->toolsettings->viewport_facing_select_face);
+ }
+
+ const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, inside && mesh_facing);
+
+ if (sel_op_result != -1) {
+ BM_face_select_set(data->vc->em->bm, efa, sel_op_result);
+ data->is_changed = true;
+ }
+}
+
+static void do_mesh_box_select__doSelectFaceCenter(void *userData,
BMFace *efa,
const float screen_co[2],
int /*index*/)
@@ -3612,7 +4380,15 @@ static void do_mesh_box_select__doSelectFace(void *userData,
BoxSelectUserData *data = static_cast(userData);
const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT);
const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
- const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ bool mesh_facing = true;
+
+ if (is_inside && data->check_mesh_direction) {
+ mesh_facing = edbm_facing_viewport(
+ data->vc, NULL, NULL, efa, data->vc->scene->toolsettings->viewport_facing_select_face);
+ }
+
+ const int sel_op_result = ED_select_op_action_deselected(
+ data->sel_op, is_select, is_inside && mesh_facing);
if (sel_op_result != -1) {
BM_face_select_set(data->vc->em->bm, efa, sel_op_result);
data->is_changed = true;
@@ -3621,12 +4397,18 @@ static void do_mesh_box_select__doSelectFace(void *userData,
static bool do_mesh_box_select(ViewContext *vc,
wmGenericUserData *wm_userdata,
const rcti *rect,
- const eSelectOp sel_op)
+ const eSelectOp sel_op,
+ wmOperator *op)
{
BoxSelectUserData data;
ToolSettings *ts = vc->scene->toolsettings;
- view3d_userdata_boxselect_init(&data, vc, rect, sel_op);
+ view3d_userdata_boxselect_init(&data,
+ vc,
+ rect,
+ sel_op,
+ RNA_enum_get(op->ptr, "edge_type"),
+ RNA_enum_get(op->ptr, "face_type"));
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
if (vc->em->bm->totvertsel) {
@@ -3640,12 +4422,22 @@ static bool do_mesh_box_select(ViewContext *vc,
GPU_matrix_set(vc->rv3d->viewmat);
- const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d);
+ const bool select_through = ts->select_through && ts->select_through_edit &&
+ ts->select_through_box;
+ const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d) && !select_through;
EditSelectBuf_Cache *esel = static_cast(wm_userdata->data);
if (use_zbuf) {
if (wm_userdata->data == nullptr) {
- editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, ts->selectmode);
+ /* for near enclose face */
+ if (data.face_style == 4 && ts->selectmode & SCE_SELECT_FACE &&
+ !(ts->selectmode & SCE_SELECT_VERTEX)) {
+ editselect_buf_cache_init_with_generic_userdata(
+ wm_userdata, vc, ts->selectmode | SCE_SELECT_VERTEX);
+ }
+ else {
+ editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, ts->selectmode);
+ }
esel = static_cast(wm_userdata->data);
esel->select_bitmap = DRW_select_buffer_bitmap_from_rect(
vc->depsgraph, vc->region, vc->v3d, rect, nullptr);
@@ -3655,9 +4447,12 @@ static bool do_mesh_box_select(ViewContext *vc,
if (ts->selectmode & SCE_SELECT_VERTEX) {
if (use_zbuf) {
data.is_changed |= edbm_backbuf_check_and_select_verts(
- esel, vc->depsgraph, vc->obedit, vc->em, sel_op);
+ vc, esel, vc->depsgraph, vc->obedit, vc->em, sel_op);
}
else {
+ data.check_mesh_direction = edbm_facing_viewport_precheck(
+ ts, ts->viewport_facing_select_vert, true);
+
mesh_foreachScreenVert(
vc, do_mesh_box_select__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
}
@@ -3674,12 +4469,19 @@ static bool do_mesh_box_select(ViewContext *vc,
const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_NEAR |
(use_zbuf ? (eV3DProjTest)0 : V3D_PROJ_TEST_CLIP_BB);
- /* Fully inside. */
- mesh_foreachScreenEdge_clip_bb_segment(
- vc, do_mesh_box_select__doSelectEdge_pass0, &cb_data, clip_flag);
- if (data.is_done == false) {
- /* Fall back to partially inside.
- * Clip content to account for edges partially behind the view. */
+
+ data.check_mesh_direction = use_zbuf ?
+ edbm_facing_viewport_precheck(
+ ts, ts->viewport_facing_select_edge, false) :
+ data.check_mesh_direction = edbm_facing_viewport_precheck(
+ ts, ts->viewport_facing_select_edge, true);
+ /* Fully inside, hybrid and enclose edge */
+ if (data.edge_style != 2) {
+ mesh_foreachScreenEdge_clip_bb_segment(
+ vc, do_mesh_box_select__doSelectEdge_pass0, &cb_data, clip_flag);
+ }
+ /* Partially inside, hybrid and touch edge */
+ if (data.edge_style == 2 || data.edge_style == 1 && data.is_done == false) {
mesh_foreachScreenEdge_clip_bb_segment(vc,
do_mesh_box_select__doSelectEdge_pass1,
&cb_data,
@@ -3690,11 +4492,24 @@ static bool do_mesh_box_select(ViewContext *vc,
if (ts->selectmode & SCE_SELECT_FACE) {
if (use_zbuf) {
data.is_changed |= edbm_backbuf_check_and_select_faces(
- esel, vc->depsgraph, vc->obedit, vc->em, sel_op);
+ vc, esel, vc->depsgraph, vc->obedit, vc->em, sel_op, rect, data.face_style, NULL, NULL);
}
else {
- mesh_foreachScreenFace(
- vc, do_mesh_box_select__doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+ data.check_mesh_direction = edbm_facing_viewport_precheck(
+ ts, ts->viewport_facing_select_face, true);
+
+ /* xray center and auto face with fallback for touch and enclose intersect */
+ if (data.face_style == 1 || data.face_style == 8 || SEL_OP_USE_OUTSIDE(sel_op)) {
+ mesh_foreachScreenFaceCenter(
+ vc, do_mesh_box_select__doSelectFaceCenter, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+ }
+ /* xray touch and enclose face - doesn't work with intersect */
+ else {
+ mesh_foreachScreenFaceVerts(vc,
+ do_mesh_box_select__doSelectFace,
+ &data,
+ V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB);
+ }
}
}
@@ -3855,18 +4670,34 @@ static int opengl_bone_select_buffer_cmp(const void *sel_a_p, const void *sel_b_
return 0;
}
-static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const eSelectOp sel_op)
+static bool do_object_box_select(
+ bContext *C, ViewContext *vc, rcti *rect, const eSelectOp sel_op, wmOperator *op)
{
View3D *v3d = vc->v3d;
int totobj = MAXPICKELEMS; /* XXX solve later */
+ ToolSettings *ts = vc->scene->toolsettings;
+ rctf rect_f_data;
+ rctf *rect_f = &rect_f_data;
+ BLI_rctf_rcti_copy(rect_f, rect);
+ float region_co[2];
/* Selection buffer has bones potentially too, so we add #MAXPICKELEMS. */
GPUSelectResult *buffer = static_cast(
MEM_mallocN((totobj + MAXPICKELEMS) * sizeof(GPUSelectResult), __func__));
const eV3DSelectObjectFilter select_filter = ED_view3d_select_filter_from_mode(vc->scene,
vc->obact);
- const int hits = view3d_opengl_select(
- vc, buffer, (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL, select_filter);
+ const bool select_origin = RNA_boolean_get(op->ptr, "select_origin_box");
+ const bool select_through = ts->select_through && ts->select_through_object &&
+ ts->select_through_box;
+ int hits = 0;
+ if (XRAY_FLAG_ENABLED(vc->v3d) || select_through) {
+ hits = view3d_opengl_select(
+ vc, buffer, (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL, select_filter);
+ }
+ else {
+ hits = view3d_opengl_select(
+ vc, buffer, (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_PICK_NEAREST, select_filter);
+ }
BKE_view_layer_synced_ensure(vc->scene, vc->view_layer);
LISTBASE_FOREACH (Base *, base, BKE_view_layer_object_bases_get(vc->view_layer)) {
base->object->id.tag &= ~LIB_TAG_DOIT;
@@ -3908,7 +4739,13 @@ static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const
for (Base *base = static_cast(object_bases->first); base && hits; base = base->next) {
if (BASE_SELECTABLE(v3d, base)) {
const bool is_select = base->flag & BASE_SELECTED;
- const bool is_inside = base->object->id.tag & LIB_TAG_DOIT;
+ const bool is_inside = base->object->id.tag & LIB_TAG_DOIT ?
+ select_origin ?
+ (ED_view3d_project_base(vc->region, base, region_co) ==
+ V3D_PROJ_RET_OK) &&
+ BLI_rctf_isect_pt_v(rect_f, region_co) :
+ true :
+ false;
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
if (sel_op_result != -1) {
ED_object_base_select(base, sel_op_result ? BA_SELECT : BA_DESELECT);
@@ -4034,7 +4871,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op)
switch (vc.obedit->type) {
case OB_MESH:
vc.em = BKE_editmesh_from_object(vc.obedit);
- changed = do_mesh_box_select(&vc, wm_userdata, &rect, sel_op);
+ changed = do_mesh_box_select(&vc, wm_userdata, &rect, sel_op, op);
if (changed) {
DEG_id_tag_update(static_cast(vc.obedit->data), ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
@@ -4108,7 +4945,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op)
}
}
else { /* object mode with none active */
- changed_multi = do_object_box_select(C, &vc, &rect, sel_op);
+ changed_multi = do_object_box_select(C, &vc, &rect, sel_op, op);
if (changed_multi) {
ED_outliner_select_sync_from_object_tag(C);
}
@@ -4151,24 +4988,13 @@ void VIEW3D_OT_select_box(wmOperatorType *ot)
/** \name Circle Select
* \{ */
-struct CircleSelectUserData {
- ViewContext *vc;
- bool select;
- int mval[2];
- float mval_fl[2];
- float radius;
- float radius_squared;
- eBezTriple_Flag select_flag;
-
- /* runtime */
- bool is_changed;
-};
-
static void view3d_userdata_circleselect_init(CircleSelectUserData *r_data,
ViewContext *vc,
const bool select,
const int mval[2],
- const float rad)
+ const float rad,
+ const int edge_style,
+ const int face_style)
{
r_data->vc = vc;
r_data->select = select;
@@ -4181,6 +5007,9 @@ static void view3d_userdata_circleselect_init(CircleSelectUserData *r_data,
/* SELECT by default, but can be changed if needed (only few cases use and respect this). */
r_data->select_flag = (eBezTriple_Flag)SELECT;
+ r_data->edge_style = edge_style;
+ r_data->face_style = face_style;
+ r_data->check_mesh_direction = false;
/* runtime */
r_data->is_changed = false;
@@ -4194,8 +5023,16 @@ static void mesh_circle_doSelectVert(void *userData,
CircleSelectUserData *data = static_cast(userData);
if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
- BM_vert_select_set(data->vc->em->bm, eve, data->select);
+ bool mesh_facing = true;
data->is_changed = true;
+ if (data->check_mesh_direction) {
+ mesh_facing = edbm_facing_viewport(
+ data->vc, eve, NULL, NULL, data->vc->scene->toolsettings->viewport_facing_select_vert);
+ }
+ if (mesh_facing) {
+ BM_vert_select_set(data->vc->em->bm, eve, data->select);
+ data->is_changed = true;
+ }
}
}
static void mesh_circle_doSelectEdge(void *userData,
@@ -4205,22 +5042,91 @@ static void mesh_circle_doSelectEdge(void *userData,
int /*index*/)
{
CircleSelectUserData *data = static_cast(userData);
-
+
+ bool enclose_edge = true;
+ bool mesh_facing = true;
if (edge_inside_circle(data->mval_fl, data->radius, screen_co_a, screen_co_b)) {
- BM_edge_select_set(data->vc->em->bm, eed, data->select);
+ if (data->edge_style == 4) {
+ enclose_edge = edbm_circle_enclose_mesh(eed, NULL, data);
+ }
+
+ if (data->check_mesh_direction) {
+ mesh_facing = edbm_facing_viewport(
+ data->vc, NULL, eed, NULL, data->vc->scene->toolsettings->viewport_facing_select_edge);
+ }
+
+ if (enclose_edge && mesh_facing) {
+ BM_edge_select_set(data->vc->em->bm, eed, data->select);
+ data->is_changed = true;
+ }
+ }
+}
+
+static void mesh_circle_doSelectFace(void *userData,
+ BMFace *efa,
+ const float screen_co[][2],
+ int total_count,
+ rctf *screen_rect,
+ bool *face_hit)
+{
+ CircleSelectUserData *data = static_cast(userData);
+
+ if (!BLI_rctf_isect_circle(screen_rect, data->mval_fl, data->radius)) {
+ return;
+ }
+
+ bool inside = false;
+ bool enclose_face = true;
+ bool mesh_facing = true;
+ for (int i = 0; i < total_count; i++) {
+
+ int a = i;
+ int b = (i + 1) % total_count;
+
+ inside = edge_inside_circle(data->mval_fl, data->radius, screen_co[a], screen_co[b]);
+ if (inside)
+ break;
+ }
+
+ if (!inside) {
+ inside = isect_point_poly_v2(data->mval_fl, screen_co, total_count, true);
+ }
+
+ *face_hit = inside;
+
+ if (data->face_style == 4 && inside) {
+ enclose_face = edbm_circle_enclose_mesh(NULL, efa, data);
+ }
+
+ if (data->check_mesh_direction) {
+ mesh_facing = edbm_facing_viewport(
+ data->vc, NULL, NULL, efa, data->vc->scene->toolsettings->viewport_facing_select_face);
+ }
+
+ if (inside && enclose_face && mesh_facing) {
+ BM_face_select_set(data->vc->em->bm, efa, data->select);
data->is_changed = true;
}
}
-static void mesh_circle_doSelectFace(void *userData,
+
+static void mesh_circle_doSelectFaceCenter(void *userData,
BMFace *efa,
const float screen_co[2],
int /*index*/)
{
CircleSelectUserData *data = static_cast(userData);
+ bool mesh_facing = true;
if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
- BM_face_select_set(data->vc->em->bm, efa, data->select);
- data->is_changed = true;
+ if (data->check_mesh_direction) {
+ mesh_facing = edbm_facing_viewport(
+ data->vc, NULL, NULL, efa, data->vc->scene->toolsettings->viewport_facing_select_face);
+ }
+
+ if (mesh_facing) {
+ BM_face_select_set(data->vc->em->bm, efa, data->select);
+ data->is_changed = true;
+ }
}
}
@@ -4228,7 +5134,8 @@ static bool mesh_circle_select(ViewContext *vc,
wmGenericUserData *wm_userdata,
eSelectOp sel_op,
const int mval[2],
- float rad)
+ float rad,
+ wmOperator *op)
{
ToolSettings *ts = vc->scene->toolsettings;
CircleSelectUserData data;
@@ -4248,9 +5155,17 @@ static bool mesh_circle_select(ViewContext *vc,
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
- view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
+ view3d_userdata_circleselect_init(&data,
+ vc,
+ select,
+ mval,
+ rad,
+ RNA_enum_get(op->ptr, "edge_type"),
+ RNA_enum_get(op->ptr, "face_type"));
- const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d);
+ const bool select_through = ts->select_through && ts->select_through_edit &&
+ ts->select_through_circle;
+ const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d) && !select_through;
if (use_zbuf) {
if (wm_userdata->data == nullptr) {
@@ -4270,10 +5185,13 @@ static bool mesh_circle_select(ViewContext *vc,
if (use_zbuf) {
if (esel->select_bitmap != nullptr) {
changed |= edbm_backbuf_check_and_select_verts(
- esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
+ vc, esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
}
}
else {
+ data.check_mesh_direction = edbm_facing_viewport_precheck(
+ ts, ts->viewport_facing_select_vert, true);
+
mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
}
}
@@ -4282,10 +5200,13 @@ static bool mesh_circle_select(ViewContext *vc,
if (use_zbuf) {
if (esel->select_bitmap != nullptr) {
changed |= edbm_backbuf_check_and_select_edges(
- esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
+ &data, esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
}
}
else {
+ data.check_mesh_direction = edbm_facing_viewport_precheck(
+ ts, ts->viewport_facing_select_edge, true);
+
mesh_foreachScreenEdge_clip_bb_segment(
vc,
mesh_circle_doSelectEdge,
@@ -4296,13 +5217,33 @@ static bool mesh_circle_select(ViewContext *vc,
if (ts->selectmode & SCE_SELECT_FACE) {
if (use_zbuf) {
- if (esel->select_bitmap != nullptr) {
- changed |= edbm_backbuf_check_and_select_faces(
- esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
+ if (esel->select_bitmap != NULL) {
+ changed |= edbm_backbuf_check_and_select_faces(vc,
+ esel,
+ vc->depsgraph,
+ vc->obedit,
+ vc->em,
+ select ? SEL_OP_ADD : SEL_OP_SUB,
+ NULL,
+ data.face_style,
+ NULL,
+ &data);
}
}
else {
- mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+ data.check_mesh_direction = edbm_facing_viewport_precheck(
+ ts, ts->viewport_facing_select_face, true);
+
+ /* xray center and auto face */
+ if (data.face_style == 1 || data.face_style == 8) {
+ mesh_foreachScreenFaceCenter(
+ vc, mesh_circle_doSelectFaceCenter, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+ }
+ /* xray touch and enclose face */
+ else {
+ mesh_foreachScreenFaceVerts(
+ vc, mesh_circle_doSelectFace, &data, V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB);
+ }
}
}
@@ -4416,7 +5357,7 @@ static bool paint_vertsel_circle_select(ViewContext *vc,
ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); /* for foreach's screen/vert projection */
- view3d_userdata_circleselect_init(&data.circle_data, vc, select, mval, rad);
+ view3d_userdata_circleselect_init(&data.circle_data, vc, select, mval, rad, 0, 0);
meshobject_foreachScreenVert(
vc, paint_vertsel_circle_select_doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
changed |= data.circle_data.is_changed;
@@ -4470,7 +5411,7 @@ static bool nurbscurve_circle_select(ViewContext *vc,
const bool deselect_all = (sel_op == SEL_OP_SET);
CircleSelectUserData data;
- view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
+ view3d_userdata_circleselect_init(&data, vc, select, mval, rad, 0, 0);
Curve *curve = (Curve *)vc->obedit->data;
ListBase *nurbs = BKE_curve_editNurbs_get(curve);
@@ -4511,7 +5452,7 @@ static bool lattice_circle_select(ViewContext *vc,
CircleSelectUserData data;
const bool select = (sel_op != SEL_OP_SUB);
- view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
+ view3d_userdata_circleselect_init(&data, vc, select, mval, rad, 0, 0);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
data.is_changed |= ED_lattice_flags_set(vc->obedit, 0);
@@ -4602,7 +5543,7 @@ static bool pose_circle_select(ViewContext *vc,
CircleSelectUserData data;
const bool select = (sel_op != SEL_OP_SUB);
- view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
+ view3d_userdata_circleselect_init(&data, vc, select, mval, rad, 0, 0);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
data.is_changed |= ED_pose_deselect_all(vc->obact, SEL_DESELECT, false);
@@ -4739,7 +5680,7 @@ static bool armature_circle_select(ViewContext *vc,
const bool select = (sel_op != SEL_OP_SUB);
- view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
+ view3d_userdata_circleselect_init(&data, vc, select, mval, rad, 0, 0);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
data.is_changed |= ED_armature_edit_deselect_all_visible(vc->obedit);
@@ -4792,7 +5733,7 @@ static bool mball_circle_select(ViewContext *vc,
const bool select = (sel_op != SEL_OP_SUB);
- view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
+ view3d_userdata_circleselect_init(&data, vc, select, mval, rad, 0, 0);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
data.is_changed |= BKE_mball_deselect_all(static_cast(vc->obedit->data));
@@ -4813,14 +5754,15 @@ static bool obedit_circle_select(bContext *C,
wmGenericUserData *wm_userdata,
const eSelectOp sel_op,
const int mval[2],
- float rad)
+ float rad,
+ wmOperator *op)
{
using namespace blender;
bool changed = false;
BLI_assert(ELEM(sel_op, SEL_OP_SET, SEL_OP_ADD, SEL_OP_SUB));
switch (vc->obedit->type) {
case OB_MESH:
- changed = mesh_circle_select(vc, wm_userdata, sel_op, mval, rad);
+ changed = mesh_circle_select(vc, wm_userdata, sel_op, mval, rad, op);
break;
case OB_CURVES_LEGACY:
case OB_SURF:
@@ -4961,7 +5903,6 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
const eSelectOp sel_op = ED_select_op_modal(
static_cast(RNA_enum_get(op->ptr, "mode")), WM_gesture_is_modal_first(gesture));
-
ED_view3d_viewcontext_init(C, &vc, depsgraph);
Object *obact = vc.obact;
@@ -4981,7 +5922,7 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
obedit = vc.obedit;
if (obedit) {
- obedit_circle_select(C, &vc, wm_userdata, sel_op, mval, float(radius));
+ obedit_circle_select(C, &vc, wm_userdata, sel_op, mval, float(radius), op);
}
else if (BKE_paint_select_face_test(obact)) {
paint_facesel_circle_select(&vc, wm_userdata, sel_op, mval, float(radius));
@@ -5009,11 +5950,22 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
else {
- if (object_circle_select(&vc, sel_op, mval, float(radius))) {
- DEG_id_tag_update(&vc.scene->id, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc.scene);
+ ToolSettings *ts = vc.scene->toolsettings;
+ const bool default_object_select = RNA_boolean_get(op->ptr, "select_origin_circle") &&
+ ts->select_through && ts->select_through_object &&
+ ts->select_through_circle;
+ if (default_object_select) {
+ if (object_circle_select(&vc, sel_op, mval, float(radius))) {
+ DEG_id_tag_update(&vc.scene->id, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc.scene);
- ED_outliner_select_sync_from_object_tag(C);
+ ED_outliner_select_sync_from_object_tag(C);
+ }
+ }
+ else {
+ BKE_object_update_select_id(CTX_data_main(C));
+ int circle_data[3] = {mval[0], mval[1], radius};
+ do_lasso_select_objects(&vc, NULL, NULL, sel_op, op, circle_data);
}
}
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 0cf9d5fa309..5a067f0f7f9 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -516,7 +516,8 @@ short ED_transform_calc_orientation_from_type_ex(const Scene *scene,
}
case V3D_ORIENT_NORMAL: {
if (obedit || (ob && ob->mode & OB_MODE_POSE)) {
- ED_getTransformOrientationMatrix(scene, view_layer, v3d, ob, obedit, pivot_point, r_mat);
+ ED_getTransformOrientationMatrix(
+ scene, view_layer, v3d, ob, obedit, pivot_point, r_mat, NULL, NULL, NULL);
break;
}
/* No break we define 'normal' as 'local' in Object mode. */
@@ -529,7 +530,8 @@ short ED_transform_calc_orientation_from_type_ex(const Scene *scene,
* use the active pones axis for display #33575, this works as expected on a single
* bone and users who select many bones will understand what's going on and what local
* means when they start transforming. */
- ED_getTransformOrientationMatrix(scene, view_layer, v3d, ob, obedit, pivot_point, r_mat);
+ ED_getTransformOrientationMatrix(
+ scene, view_layer, v3d, ob, obedit, pivot_point, r_mat, NULL, NULL, NULL);
}
else {
transform_orientations_create_from_axis(r_mat, UNPACK3(ob->object_to_world));
@@ -752,13 +754,18 @@ int getTransformOrientation_ex(const Scene *scene,
struct Object *obedit,
float normal[3],
float plane[3],
- const short around)
+ const short around,
+ struct BMVert *eve,
+ struct BMEdge *eed,
+ struct BMFace *efa)
{
int result = ORIENTATION_NONE;
const bool activeOnly = (around == V3D_AROUND_ACTIVE);
- zero_v3(normal);
- zero_v3(plane);
+ if (efa == NULL && eed == NULL) {
+ zero_v3(normal);
+ zero_v3(plane);
+ }
if (obedit) {
float imat[3][3], mat[3][3];
@@ -777,20 +784,72 @@ int getTransformOrientation_ex(const Scene *scene,
float vec[3] = {0, 0, 0};
/* USE LAST SELECTED WITH ACTIVE */
- if (activeOnly && BM_select_history_active_get(em->bm, &ese)) {
- BM_editselection_normal(&ese, normal);
- BM_editselection_plane(&ese, plane);
+ if (efa != NULL || eed != NULL || eve != NULL ||
+ activeOnly && BM_select_history_active_get(em->bm, &ese)) {
+ if (efa != NULL) {
+ copy_v3_v3(normal, efa->no);
+ BM_face_calc_tangent_auto(efa, plane);
+ result = ORIENTATION_FACE;
+ }
+ else if (eed != NULL) {
+ float eed_plane[3];
+ float vec[3];
+ add_v3_v3v3(normal, eed->v1->no, eed->v2->no);
+ sub_v3_v3v3(eed_plane, eed->v2->co, eed->v1->co);
+ cross_v3_v3v3(vec, normal, eed_plane);
+ cross_v3_v3v3(normal, eed_plane, vec);
+ normalize_v3(normal);
- switch (ese.htype) {
- case BM_VERT:
- result = ORIENTATION_VERT;
- break;
- case BM_EDGE:
- result = ORIENTATION_EDGE;
- break;
- case BM_FACE:
- result = ORIENTATION_FACE;
- break;
+ if (BM_edge_is_boundary(eed)) {
+ sub_v3_v3v3(plane, eed->l->v->co, eed->l->next->v->co);
+ }
+ else {
+ if (eed->v2->co[1] > eed->v1->co[1]) {
+ sub_v3_v3v3(plane, eed->v2->co, eed->v1->co);
+ }
+ else {
+ sub_v3_v3v3(plane, eed->v1->co, eed->v2->co);
+ }
+ }
+ normalize_v3(plane);
+ result = ORIENTATION_EDGE;
+ }
+ else if (eve != NULL) {
+ copy_v3_v3(normal, eve->no);
+ if (eve->e) {
+ float vert1v3[3] = {eve->e->v1->co[0], eve->e->v1->co[1], eve->e->v1->co[2]};
+ float vert2v3[3] = {eve->e->v2->co[0], eve->e->v2->co[1], eve->e->v2->co[2]};
+ sub_v3_v3v3(plane, vert2v3, vert1v3);
+ }
+ else {
+ if (eve->no[0] < 0.5f) {
+ vec[0] = 1.0f;
+ }
+ else if (eve->no[1] < 0.5f) {
+ vec[1] = 1.0f;
+ }
+ else {
+ vec[2] = 1.0f;
+ }
+ cross_v3_v3v3(plane, eve->no, vec);
+ }
+ normalize_v3(plane);
+ result = ORIENTATION_VERT;
+ }
+ else {
+ BM_editselection_normal(&ese, normal);
+ BM_editselection_plane(&ese, plane);
+ switch (ese.htype) {
+ case BM_VERT:
+ result = ORIENTATION_VERT;
+ break;
+ case BM_EDGE:
+ result = ORIENTATION_EDGE;
+ break;
+ case BM_FACE:
+ result = ORIENTATION_FACE;
+ break;
+ }
}
}
else {
@@ -1289,7 +1348,8 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3])
ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = CTX_wm_view3d(C);
- return getTransformOrientation_ex(scene, view_layer, v3d, obact, obedit, normal, plane, around);
+ return getTransformOrientation_ex(
+ scene, view_layer, v3d, obact, obedit, normal, plane, around, NULL, NULL, NULL);
}
void ED_getTransformOrientationMatrix(const Scene *scene,
@@ -1298,14 +1358,32 @@ void ED_getTransformOrientationMatrix(const Scene *scene,
Object *ob,
Object *obedit,
const short around,
- float r_orientation_mat[3][3])
+ float r_orientation_mat[3][3],
+ struct BMVert *eve,
+ struct BMEdge *eed,
+ struct BMFace *efa)
{
float normal[3] = {0.0, 0.0, 0.0};
float plane[3] = {0.0, 0.0, 0.0};
int type;
- type = getTransformOrientation_ex(scene, view_layer, v3d, ob, obedit, normal, plane, around);
+ if (efa != NULL) {
+ type = getTransformOrientation_ex(
+ scene, view_layer, v3d, ob, obedit, normal, plane, around, NULL, NULL, efa);
+ }
+ else if (eed != NULL) {
+ type = getTransformOrientation_ex(
+ scene, view_layer, v3d, ob, obedit, normal, plane, around, NULL, eed, NULL);
+ }
+ else if (eve != NULL) {
+ type = getTransformOrientation_ex(
+ scene, view_layer, v3d, ob, obedit, normal, plane, around, eve, NULL, NULL);
+ }
+ else {
+ type = getTransformOrientation_ex(
+ scene, view_layer, v3d, ob, obedit, normal, plane, around, NULL, NULL, NULL);
+ }
/* Fallback, when the plane can't be calculated. */
if (ORIENTATION_USE_PLANE(type) && is_zero_v3(plane)) {
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
index 6897b171d8b..b4951e7aab6 100644
--- a/source/blender/editors/uvedit/uvedit_select.c
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -3947,8 +3947,12 @@ static bool do_lasso_select_mesh_uv_is_edge_inside(const ARegion *region,
if (UI_view2d_view_to_region_segment_clip(
®ion->v2d, co_test_a, co_test_b, co_screen_a, co_screen_b) &&
BLI_rcti_isect_segment(clip_rect, co_screen_a, co_screen_b) &&
- BLI_lasso_is_edge_inside(
- mcoords, mcoords_len, UNPACK2(co_screen_a), UNPACK2(co_screen_b), V2D_IS_CLIPPED)) {
+ BLI_lasso_is_edge_inside(mcoords,
+ mcoords_len,
+ UNPACK2(co_screen_a),
+ UNPACK2(co_screen_b),
+ V2D_IS_CLIPPED,
+ false)) {
return true;
}
return false;
diff --git a/source/blender/makesdna/DNA_scene_defaults.h b/source/blender/makesdna/DNA_scene_defaults.h
index 6cc01d254ce..c332d479da3 100644
--- a/source/blender/makesdna/DNA_scene_defaults.h
+++ b/source/blender/makesdna/DNA_scene_defaults.h
@@ -366,6 +366,25 @@
/* UV painting */ \
.uv_sculpt_settings = 0, \
.uv_relax_method = UV_SCULPT_TOOL_RELAX_LAPLACIAN, \
+ \
+ /* X-Ray */ \
+ .xray_button = true, \
+ .auto_xray_object = true, \
+ .auto_xray_edit = true, \
+ .auto_xray_box = true, \
+ .auto_xray_lasso = true, \
+ .auto_xray_circle = true, \
+ .select_through = true, \
+ .select_through_object = true, \
+ .select_through_box = true, \
+ .select_through_lasso = true, \
+ .select_through_circle = true, \
+ \
+ /* Viewport-Facing Select */ \
+ .viewport_facing_select_mode = 1, \
+ .viewport_facing_select_vert = 1, \
+ .viewport_facing_select_edge = 1, \
+ .viewport_facing_select_face = 1, \
}
/* clang-format off */
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 6fb38eae744..7164759a632 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1557,7 +1557,35 @@ typedef struct ToolSettings {
char gpencil_v3d_align;
/** General 2D Editor. */
char gpencil_v2d_align;
- char _pad0[2];
+
+ /* Mesh Normal Direction Select */
+ char viewport_facing_select;
+ char viewport_facing_select_mode;
+ char viewport_facing_select_vert;
+ float viewport_facing_select_threshold;
+ char viewport_facing_select_edge;
+ char viewport_facing_select_face;
+
+ /* X-Ray Options */
+ char xray_button;
+ char auto_xray;
+ char auto_xray_button;
+ char auto_xray_reset;
+ char auto_xray_object;
+ char auto_xray_edit;
+ char auto_xray_box;
+ char auto_xray_lasso;
+ char auto_xray_circle;
+ char select_through;
+ char select_through_button;
+ char select_through_object;
+ char select_through_edit;
+ char select_through_box;
+ char select_through_lasso;
+ char select_through_circle;
+
+ /* Combine shading and xray header buttons */
+ char shrink_shading_header;
/* Annotations. */
/** Stroke placement settings - 3D View. */
@@ -2331,6 +2359,71 @@ typedef enum eSnapTransformMode {
SCE_SNAP_TRANSFORM_MODE_SCALE = (1 << 2),
} eSnapTransformMode;
+/** #Viewport-facing select mode */
+enum {
+ VIEWPORT_FACING_SELECT_BOTH = (1 << 0),
+ VIEWPORT_FACING_SELECT_NEAR = (1 << 1),
+ VIEWPORT_FACING_SELECT_XRAY = (1 << 2),
+};
+
+/** #Viewport-facing select vert */
+enum {
+ VIEWPORT_FACING_SELECT_FRONT_VERTS = (1 << 0),
+ VIEWPORT_FACING_SELECT_FRONT_VERTS_FACE = (1 << 1),
+ VIEWPORT_FACING_SELECT_REAR_VERTS = (1 << 2),
+ VIEWPORT_FACING_SELECT_REAR_VERTS_FACE = (1 << 3),
+ VIEWPORT_FACING_SELECT_ALL_VERTS = (1 << 4),
+};
+
+/** #Viewport-facing select edge */
+enum {
+ VIEWPORT_FACING_SELECT_FRONT_EDGES = (1 << 0),
+ VIEWPORT_FACING_SELECT_FRONT_EDGES_FACE = (1 << 1),
+ VIEWPORT_FACING_SELECT_REAR_EDGES = (1 << 2),
+ VIEWPORT_FACING_SELECT_REAR_EDGES_FACE = (1 << 3),
+ VIEWPORT_FACING_SELECT_ALL_EDGES = (1 << 4),
+};
+
+/** #Viewport-facing select face */
+enum {
+ VIEWPORT_FACING_SELECT_FRONT_FACES = (1 << 0),
+ VIEWPORT_FACING_SELECT_FRONT_FACES_VERT = (1 << 1),
+ VIEWPORT_FACING_SELECT_REAR_FACES = (1 << 2),
+ VIEWPORT_FACING_SELECT_REAR_FACES_VERT = (1 << 3),
+ VIEWPORT_FACING_SELECT_ALL_FACES = (1 << 4),
+};
+
+/** #Face select style */
+enum {
+ FACE_DEFAULT = (1 << 0),
+ FACE_TOUCH = (1 << 1),
+ FACE_ENCLOSE = (1 << 2),
+ FACE_CENTER = (1 << 3),
+};
+
+/** #Edge select style */
+enum {
+ EDGE_DEFAULT = (1 << 0),
+ EDGE_TOUCH = (1 << 1),
+ EDGE_ENCLOSE = (1 << 2),
+};
+
+/** #Auto X-Ray mode */
+enum {
+ AUTO_XRAY_DISABLE = (1 << 0),
+ AUTO_XRAY_OBJECT = (1 << 1),
+ AUTO_XRAY_EDIT = (1 << 2),
+ AUTO_XRAY_BOTH = (1 << 3),
+};
+
+/** #Select through mode */
+enum {
+ SELECT_THROUGH_DISABLE = (1 << 0),
+ SELECT_THROUGH_OBJECT = (1 << 1),
+ SELECT_THROUGH_EDIT = (1 << 2),
+ SELECT_THROUGH_BOTH = (1 << 3),
+};
+
/** #ToolSettings.selectmode */
#define SCE_SELECT_VERTEX (1 << 0) /* for mesh */
#define SCE_SELECT_EDGE (1 << 1)
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 01b2c0464ce..b1709d9589d 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -800,7 +800,9 @@ typedef struct UserDef {
char gizmo_size;
/** Navigate gizmo size. */
char gizmo_size_navigate_v3d;
- char _pad3[5];
+ /** Header highlight */
+ char header_highlight;
+ char _pad3[4];
short edit_studio_light;
short lookdev_sphere_size;
short vbotimeout, vbocollectrate;
@@ -840,7 +842,9 @@ typedef struct UserDef {
/** #eGPUBackendType */
short gpu_backend;
- char _pad7[4];
+ /** Keymap click-drag direction style. */
+ char click_drag_direction;
+ char _pad7[3];
/** Private, defaults to 20 for 72 DPI setting. */
short widget_unit;
@@ -900,6 +904,15 @@ typedef struct UserDef {
char drag_threshold;
char move_threshold;
+ /** Adjustable selection radius. */
+ float selection_radius;
+ char adjustable_click_select;
+ char select_unbiased;
+
+ /** Edit mode cursor. **/
+ char edit_cursor;
+ char _pad9[1];
+
char font_path_ui[1024];
char font_path_ui_mono[1024];
@@ -1002,8 +1015,8 @@ typedef enum eUserPref_SpaceData_Flag {
typedef enum eUserPref_Flag {
USER_AUTOSAVE = (1 << 0),
USER_FLAG_NUMINPUT_ADVANCED = (1 << 1),
- USER_FLAG_UNUSED_2 = (1 << 2), /* cleared */
- USER_FLAG_UNUSED_3 = (1 << 3), /* cleared */
+ USER_ADJUSTABLE_CLICK_SELECT = (1 << 2),
+ USER_SELECT_UNBIASED = (1 << 3),
USER_FLAG_UNUSED_4 = (1 << 4), /* cleared */
USER_TRACKBALL = (1 << 5),
USER_FLAG_UNUSED_6 = (1 << 6), /* cleared */
@@ -1153,6 +1166,26 @@ typedef enum eUserpref_TableAPI {
USER_TABLET_WINTAB = 2,
} eUserpref_TabletAPI;
+/** #UserDef.click_drag_direction_types */
+typedef enum eUserpref_Click_Drag_Direction {
+ USER_CLICK_DRAG_DIRECTION_EIGHT_WAY = 0,
+ USER_CLICK_DRAG_DIRECTION_LEFT_RIGHT = 1,
+ USER_CLICK_DRAG_DIRECTION_UP_DOWN = 2,
+} eUserpref_Click_Drag_Direction;
+
+/** #UserDef.edit_cursor_types */
+typedef enum eUserpref_Edit_Cursor_Types {
+ USER_EDIT_CURSOR_CROSS = 0,
+ USER_EDIT_CURSOR_SYSTEM = 1,
+ USER_EDIT_CURSOR_POINTER = 2,
+ USER_EDIT_CURSOR_CROSS_OPEN = 3,
+ USER_EDIT_CURSOR_CROSS_DOT = 4,
+ USER_EDIT_CURSOR_CROSS_MIN = 5,
+ USER_EDIT_CURSOR_BOX = 6,
+ USER_EDIT_CURSOR_BOX_DOT = 7,
+ USER_EDIT_CURSOR_BOX_POINTER = 8,
+} eUserpref_Edit_Cursor_Types;
+
/** #UserDef.app_flag */
typedef enum eUserpref_APP_Flag {
USER_APP_LOCK_CORNER_SPLIT = (1 << 0),
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index fb70fe982ba..cb3ef48293f 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -588,6 +588,7 @@ enum {
V3D_OVERLAY_EDIT_CU_NORMALS = (1 << 21),
V3D_OVERLAY_EDIT_CONSTANT_SCREEN_SIZE_NORMALS = (1 << 22),
+ V3D_OVERLAY_EDIT_FACE_DOT_XRAY = (1 << 23),
};
/** #View3DOverlay.paint_flag */
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 078f7389fbd..4b706461e6b 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -3057,10 +3057,153 @@ static void rna_def_tool_settings(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem viewport_facing_select_mode_items[] = {
+ {VIEWPORT_FACING_SELECT_BOTH,
+ "BOTH",
+ 0,
+ "Near and X-Ray",
+ "Use viewport-facing selection in near select and X-Ray"},
+ {VIEWPORT_FACING_SELECT_NEAR,
+ "NEAR",
+ 0,
+ "Near",
+ "Use viewport-facing selection in near select"},
+ {VIEWPORT_FACING_SELECT_XRAY,
+ "XRAY",
+ 0,
+ "X-Ray",
+ "Use viewport-facing selection in X-Ray"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem viewport_facing_select_vert_items[] = {
+ {VIEWPORT_FACING_SELECT_FRONT_VERTS,
+ "FRONT_VERTS",
+ 0,
+ "Front Verts",
+ "Select vertices with viewport-facing normals"},
+ {VIEWPORT_FACING_SELECT_FRONT_VERTS_FACE,
+ "FRONT_VERTS_FACE",
+ 0,
+ "Verts of Front Face",
+ "Select vertices if they are part of a face that has a viewport-facing normal"},
+ {VIEWPORT_FACING_SELECT_REAR_VERTS,
+ "REAR_VERTS",
+ 0,
+ "Rear Verts",
+ "Select vertices without viewport-facing normals"},
+ {VIEWPORT_FACING_SELECT_REAR_VERTS_FACE,
+ "REAR_VERTS_FACE",
+ 0,
+ "Verts of Rear Face",
+ "Select vertices if they are part of a face that does not have a viewport-facing normal"},
+ {VIEWPORT_FACING_SELECT_ALL_VERTS,
+ "ALL_VERTS",
+ 0,
+ "All Verts",
+ "Select vertices regarless of their normal direction"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem viewport_facing_select_edge_items[] = {
+ {VIEWPORT_FACING_SELECT_FRONT_EDGES,
+ "FRONT_EDGES",
+ 0,
+ "Front Edges",
+ "Select edges with viewport-facing normals"},
+ {VIEWPORT_FACING_SELECT_FRONT_EDGES_FACE,
+ "FRONT_EDGES_FACE",
+ 0,
+ "Edges of Front Face",
+ "Select edges if they are part of a face that has a viewport-facing normal"},
+ {VIEWPORT_FACING_SELECT_REAR_EDGES,
+ "REAR_EDGES",
+ 0,
+ "Rear Edges",
+ "Select edges without viewport-facing normals"},
+ {VIEWPORT_FACING_SELECT_REAR_EDGES_FACE,
+ "REAR_EDGES_FACE",
+ 0,
+ "Edges of Rear Face",
+ "Select edges if they are part of a face that does not have a viewport-facing normal"},
+ {VIEWPORT_FACING_SELECT_ALL_EDGES,
+ "ALL_EDGES",
+ 0,
+ "All Edges",
+ "Select edges regarless of their normal direction"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem viewport_facing_select_face_items[] = {
+ {VIEWPORT_FACING_SELECT_FRONT_FACES,
+ "FRONT_FACES",
+ 0,
+ "Front Faces",
+ "Select faces with viewport-facing normals"},
+ {VIEWPORT_FACING_SELECT_FRONT_FACES_VERT,
+ "FRONT_FACES_VERT",
+ 0,
+ "Faces of Front Vert",
+ "Select faces if they have a vertex with a viewport-facing normal"},
+ {VIEWPORT_FACING_SELECT_REAR_FACES,
+ "REAR_FACES",
+ 0,
+ "Rear Faces",
+ "Select faces without viewport-facing normals"},
+ {VIEWPORT_FACING_SELECT_REAR_FACES_VERT,
+ "REAR_FACES_VERT",
+ 0,
+ "Faces of Rear Vert",
+ "Select faces if they have a vertex without a viewport-facing normal"},
+ {VIEWPORT_FACING_SELECT_ALL_FACES,
+ "ALL_FACES",
+ 0,
+ "All Faces",
+ "Select faces regarless of their normal direction"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
srna = RNA_def_struct(brna, "ToolSettings", NULL);
RNA_def_struct_path_func(srna, "rna_ToolSettings_path");
RNA_def_struct_ui_text(srna, "Tool Settings", "");
+ /* Viewport-Facing Select */
+ prop = RNA_def_property(srna, "viewport_facing_select", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "viewport_facing_select", 0);
+ RNA_def_property_ui_text(
+ prop,
+ "Viewport Facing Select",
+ "Filter box, lasso, and circle selection of mesh elements based on the direction of their "
+ "normals compared to the viewport");
+
+ prop = RNA_def_property(srna, "viewport_facing_select_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "viewport_facing_select_mode");
+ RNA_def_property_enum_items(prop, viewport_facing_select_mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "Which selection modes to use viewport-facing selection");
+
+ prop = RNA_def_property(srna, "viewport_facing_select_vert", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "viewport_facing_select_vert");
+ RNA_def_property_enum_items(prop, viewport_facing_select_vert_items);
+ RNA_def_property_ui_text(prop, "Vert", "Direction and mode for vertices");
+
+ prop = RNA_def_property(srna, "viewport_facing_select_edge", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "viewport_facing_select_edge");
+ RNA_def_property_enum_items(prop, viewport_facing_select_edge_items);
+ RNA_def_property_ui_text(prop, "Edge", "Direction and mode for edges");
+
+ prop = RNA_def_property(srna, "viewport_facing_select_face", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "viewport_facing_select_face");
+ RNA_def_property_enum_items(prop, viewport_facing_select_face_items);
+ RNA_def_property_ui_text(prop, "Face", "Direction and mode for faces");
+
+ prop = RNA_def_property(srna, "viewport_facing_select_threshold", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 1.0f, 2);
+ RNA_def_property_ui_text(
+ prop,
+ "Threshold",
+ "How close the angles of the viewport and mesh element need to be for selection to occur");
+
prop = RNA_def_property(srna, "sculpt", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "Sculpt");
RNA_def_property_ui_text(prop, "Sculpt", "");
@@ -3733,6 +3876,102 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Normal Vector", "Normal Vector used to copy, add or multiply");
RNA_def_property_ui_range(prop, -10000.0, 10000.0, 1, 3);
+ /* Shrink Shading Header */
+ prop = RNA_def_property(srna, "shrink_shading_header", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "shrink_shading_header", 0);
+ RNA_def_property_ui_text(
+ prop, "Shrink Header", "Combine the four Shading Header buttons into one button that also toggles X-Ray");
+
+ /* X-Ray header button */
+ prop = RNA_def_property(srna, "xray_button", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "xray_button", 0);
+ RNA_def_property_ui_text(
+ prop, "X-Ray", "Show button for X-Ray in viewport header");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ /* Auto X-Ray */
+ prop = RNA_def_property(srna, "auto_xray", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "auto_xray", 0);
+ RNA_def_property_ui_text(prop, "Enable", "Transparent scene display during drag select");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "auto_xray_button", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "auto_xray_button", 0);
+ RNA_def_property_ui_text(
+ prop, "Auto X-Ray", "Show button for automatic X-Ray in viewport header");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "auto_xray_reset", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "auto_xray_reset", 0);
+ RNA_def_property_ui_text(prop, "Auto X-Ray Reset", "Helper that turns xray off for autoxray");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "auto_xray_object", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "auto_xray_object", 0);
+ RNA_def_property_ui_text(prop, "Object", "Automatic X-Ray in object mode");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "auto_xray_edit", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "auto_xray_edit", 0);
+ RNA_def_property_ui_text(prop, "Edit", "Automatic X-Ray in edit mode");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "auto_xray_box", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "auto_xray_box", 0);
+ RNA_def_property_ui_text(prop, "Box", "Transparent scene display during box select");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "auto_xray_lasso", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "auto_xray_lasso", 0);
+ RNA_def_property_ui_text(prop, "Lasso", "Transparent scene display during lasso select");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "auto_xray_circle", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "auto_xray_circle", 0);
+ RNA_def_property_ui_text(prop, "Circle", "Transparent scene display during circle select");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ /* Select Through */
+ prop = RNA_def_property(srna, "select_through", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "select_through", 0);
+ RNA_def_property_ui_text(
+ prop, "Enable", "Select occluded objects and mesh elements with drag select");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "select_through_button", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "select_through_button", 0);
+ RNA_def_property_ui_text(
+ prop, "Select Through", "Show button for select through in viewport header");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "select_through_object", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "select_through_object", 0);
+ RNA_def_property_ui_text(prop, "Object", "Select through in object mode");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "select_through_edit", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "select_through_edit", 0);
+ RNA_def_property_ui_text(prop, "Edit", "Select through in edit mode");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "select_through_box", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "select_through_box", 0);
+ RNA_def_property_ui_text(
+ prop, "Box", "Select occluded objects and mesh elements with box select");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "select_through_lasso", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "select_through_lasso", 0);
+ RNA_def_property_ui_text(
+ prop, "Lasso", "Select occluded objects and mesh elements with lasso select");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "select_through_circle", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "select_through_circle", 0);
+ RNA_def_property_ui_text(
+ prop, "Circle", "Select occluded objects and mesh elements with circle select");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
/* Unified Paint Settings */
prop = RNA_def_property(srna, "unified_paint_settings", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 8edeb6dd29d..caf122f3a8b 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -4566,6 +4566,15 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
"Display face center when face selection is enabled in solid shading modes");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ prop = RNA_def_property(srna, "show_face_center_xray", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_FACE_DOT_XRAY);
+ RNA_def_property_boolean_default(prop, true);
+ RNA_def_property_ui_text(
+ prop,
+ "Display Face Center X-Ray",
+ "Display face center when face selection is enabled in X-Ray shading modes");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
prop = RNA_def_property(srna, "show_edge_crease", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_CREASES);
RNA_def_property_ui_text(
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 46be0067071..f5388dd3710 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -4999,6 +4999,19 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem edit_cursor_items[] = {
+ {USER_EDIT_CURSOR_CROSS, "CROSS", 0, "Cross", ""},
+ {USER_EDIT_CURSOR_SYSTEM, "SYSTEM", 0, "System", ""},
+ {USER_EDIT_CURSOR_POINTER, "POINTER", 0, "Pointer", ""},
+ {USER_EDIT_CURSOR_CROSS_OPEN, "CROSS_OPEN", 0, "Cross Open", ""},
+ {USER_EDIT_CURSOR_CROSS_DOT, "CROSS_DOT", 0, "Cross Dot", ""},
+ {USER_EDIT_CURSOR_CROSS_MIN, "CROSS_MIN", 0, "Cross Minimal", ""},
+ {USER_EDIT_CURSOR_BOX, "BOX", 0, "Box", ""},
+ {USER_EDIT_CURSOR_BOX_DOT, "BOX_DOT", 0, "Box Dot", ""},
+ {USER_EDIT_CURSOR_BOX_POINTER, "BOX_POINTER", 0, "Box Pointer", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
srna = RNA_def_struct(brna, "PreferencesEdit", NULL);
RNA_def_struct_sdna(srna, "UserDef");
RNA_def_struct_nested(brna, srna, "Preferences");
@@ -5310,6 +5323,21 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
prop, "Auto-offset Margin", "Minimum distance between nodes for Auto-offsetting nodes");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ prop = RNA_def_property(srna, "adjustable_click_select", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_ADJUSTABLE_CLICK_SELECT);
+ RNA_def_property_ui_text(
+ prop, "Enable", "Use additional options for single-click select");
+
+ prop = RNA_def_property(srna, "select_unbiased", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_SELECT_UNBIASED);
+ RNA_def_property_ui_text(
+ prop, "Select Unbiased", "Click-select will not favor unselected mesh elements");
+
+ prop = RNA_def_property(srna, "selection_radius", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_range(prop, 0.1f, 150.0f);
+ RNA_def_property_ui_range(prop, 0.1f, 150.0f, 0.01f, 2);
+ RNA_def_property_ui_text(prop, "Radius", "Size of single-click selection radius");
+
/* cursor */
prop = RNA_def_property(srna, "use_cursor_lock_adjust", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_LOCK_CURSOR_ADJUST);
@@ -5322,6 +5350,11 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_DEPTH_CURSOR);
RNA_def_property_ui_text(
prop, "Cursor Surface Project", "Use the surface depth for cursor placement");
+
+ prop = RNA_def_property(srna, "edit_cursor", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, edit_cursor_items);
+ RNA_def_property_enum_sdna(prop, NULL, "edit_cursor");
+ RNA_def_property_ui_text(prop, "Edit Cursor", "Edit mode cursor style");
}
static void rna_def_userdef_system(BlenderRNA *brna)
@@ -5774,6 +5807,17 @@ static void rna_def_userdef_input(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem click_drag_direction_types[] = {
+ {USER_CLICK_DRAG_DIRECTION_EIGHT_WAY,
+ "EIGHT_WAY",
+ 0,
+ "Eight",
+ "Eight directions (N, NE, E, SE, S, SW, W, NW)"},
+ {USER_CLICK_DRAG_DIRECTION_LEFT_RIGHT, "LEFT_RIGHT", 0, "Left Right", "Left and right"},
+ {USER_CLICK_DRAG_DIRECTION_UP_DOWN, "UP_DOWN", 0, "Up Down", "Up and down"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
static const EnumPropertyItem view_zoom_styles[] = {
{USER_ZOOM_CONTINUE,
"CONTINUE",
@@ -5880,6 +5924,11 @@ static void rna_def_userdef_input(BlenderRNA *brna)
"Release Confirms",
"Moving things with a mouse drag confirms when releasing the button");
+ prop = RNA_def_property(srna, "click_drag_direction", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, click_drag_direction_types);
+ RNA_def_property_ui_text(
+ prop, "Keymap Drag Directions", "Style of click-drag direction the keymap will use");
+
prop = RNA_def_property(srna, "use_numeric_input_advanced", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_FLAG_NUMINPUT_ADVANCED);
RNA_def_property_ui_text(prop,
@@ -5944,6 +5993,12 @@ static void rna_def_userdef_input(BlenderRNA *brna)
"Number of pixels to before the cursor is considered to have moved "
"(used for cycling selected items on successive clicks)");
+ prop = RNA_def_property(srna, "header_highlight", PROP_INT, PROP_FACTOR);
+ RNA_def_property_range(prop, 0, 10);
+ RNA_def_property_ui_range(prop, 0, 10, 1, -1);
+ RNA_def_property_ui_text(
+ prop, "Header Highlight", "How much brighter the header of the active window is");
+
/* tablet pressure curve */
prop = RNA_def_property(srna, "pressure_threshold_max", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_range(prop, 0.0f, 1.0f);
diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c
index 5d8bb533d7e..9952cfb1a57 100644
--- a/source/blender/makesrna/intern/rna_wm_api.c
+++ b/source/blender/makesrna/intern/rna_wm_api.c
@@ -389,6 +389,41 @@ static void rna_KeyMap_item_remove(wmKeyMap *km, ReportList *reports, PointerRNA
RNA_POINTER_INVALIDATE(kmi_ptr);
}
+static void rna_keymap_set_direction_any(wmKeyMap *km, PointerRNA *kmi_ptr)
+{
+ wmKeyMapItem *kmi = kmi_ptr->data;
+ kmi->direction = -1;
+ WM_keyconfig_update_tag(km, kmi);
+}
+
+static void rna_keymap_set_direction_left(wmKeyMap *km, PointerRNA *kmi_ptr)
+{
+ wmKeyMapItem *kmi = kmi_ptr->data;
+ kmi->direction = 7;
+ WM_keyconfig_update_tag(km, kmi);
+}
+
+static void rna_keymap_set_direction_right(wmKeyMap *km, PointerRNA *kmi_ptr)
+{
+ wmKeyMapItem *kmi = kmi_ptr->data;
+ kmi->direction = 3;
+ WM_keyconfig_update_tag(km, kmi);
+}
+
+static void rna_keymap_set_direction_up(wmKeyMap *km, PointerRNA *kmi_ptr)
+{
+ wmKeyMapItem *kmi = kmi_ptr->data;
+ kmi->direction = 1;
+ WM_keyconfig_update_tag(km, kmi);
+}
+
+static void rna_keymap_set_direction_down(wmKeyMap *km, PointerRNA *kmi_ptr)
+{
+ wmKeyMapItem *kmi = kmi_ptr->data;
+ kmi->direction = 5;
+ WM_keyconfig_update_tag(km, kmi);
+}
+
static PointerRNA rna_KeyMap_item_find_from_operator(ID *id,
wmKeyMap *km,
const char *idname,
@@ -1197,6 +1232,31 @@ void RNA_api_keymapitems(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+
+ func = RNA_def_function(srna, "set_direction_any", "rna_keymap_set_direction_any");
+ parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+
+ func = RNA_def_function(srna, "set_direction_left", "rna_keymap_set_direction_left");
+ parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+
+ func = RNA_def_function(srna, "set_direction_right", "rna_keymap_set_direction_right");
+ parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+
+ func = RNA_def_function(srna, "set_direction_up", "rna_keymap_set_direction_up");
+ parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+
+ func = RNA_def_function(srna, "set_direction_down", "rna_keymap_set_direction_down");
+ parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
func = RNA_def_function(srna, "from_id", "WM_keymap_item_find_id");
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 0d970685582..6d4860623f9 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -688,6 +688,7 @@ int WM_operator_call_notest(struct bContext *C, struct wmOperator *op);
* Execute this operator again, put here so it can share above code
*/
int WM_operator_repeat(struct bContext *C, struct wmOperator *op);
+int WM_operator_invoke_last(struct bContext *C, struct wmOperator *op);
int WM_operator_repeat_last(struct bContext *C, struct wmOperator *op);
/**
* \return true if #WM_operator_repeat can run.
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index c9624d0e14e..2baac067660 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -43,6 +43,7 @@ static BCursor *BlenderCursor[WM_CURSOR_NUM] = {0};
/* Blender cursor to GHOST standard cursor conversion. */
static GHOST_TStandardCursor convert_to_ghost_standard_cursor(WMCursorType curs)
{
+ const int edit_style = U.edit_cursor;
switch (curs) {
case WM_CURSOR_DEFAULT:
return GHOST_kStandardCursorDefault;
@@ -50,7 +51,33 @@ static GHOST_TStandardCursor convert_to_ghost_standard_cursor(WMCursorType curs)
return GHOST_kStandardCursorWait;
case WM_CURSOR_EDIT:
case WM_CURSOR_CROSS:
- return GHOST_kStandardCursorCrosshair;
+ if (edit_style == 1) {
+ return GHOST_kStandardCursorDefault;
+ }
+ else if (edit_style == 2) {
+ return GHOST_kStandardCursorPointer;
+ }
+ else if (edit_style == 3) {
+ return GHOST_kStandardCursorCrosshairD;
+ }
+ else if (edit_style == 4) {
+ return GHOST_kStandardCursorCrosshairA;
+ }
+ else if (edit_style == 5) {
+ return GHOST_kStandardCursorCrosshairC;
+ }
+ else if (edit_style == 6) {
+ return GHOST_kStandardCursorBox;
+ }
+ else if (edit_style == 7) {
+ return GHOST_kStandardCursorBoxDot;
+ }
+ else if (edit_style == 8) {
+ return GHOST_kStandardCursorBoxPointer;
+ }
+ else {
+ return GHOST_kStandardCursorCrosshair;
+ }
case WM_CURSOR_X_MOVE:
return GHOST_kStandardCursorLeftRight;
case WM_CURSOR_Y_MOVE:
diff --git a/source/blender/windowmanager/intern/wm_event_query.c b/source/blender/windowmanager/intern/wm_event_query.c
index d39a853ead1..59fa04430e2 100644
--- a/source/blender/windowmanager/intern/wm_event_query.c
+++ b/source/blender/windowmanager/intern/wm_event_query.c
@@ -272,29 +272,42 @@ int WM_event_drag_direction(const wmEvent *event)
event->xy[1] - event->prev_press_xy[1],
};
- int theta = round_fl_to_int(4.0f * atan2f((float)delta[1], (float)delta[0]) / (float)M_PI);
- int val = KM_DIRECTION_W;
+ const bool left_right = U.click_drag_direction & USER_CLICK_DRAG_DIRECTION_LEFT_RIGHT;
+ const bool up_down = U.click_drag_direction & USER_CLICK_DRAG_DIRECTION_UP_DOWN;
+ int theta = left_right ?
+ round_fl_to_int(atan2f(0.0f, (float)delta[0]) / (float)M_PI) :
+ up_down ?
+ round_fl_to_int(atan2f(0.0f, (float)delta[1]) / (float)M_PI) :
+ round_fl_to_int(4.0f * atan2f((float)delta[1], (float)delta[0]) / (float)M_PI);
+ int val = up_down ? KM_DIRECTION_S : KM_DIRECTION_W;
- if (theta == 0) {
- val = KM_DIRECTION_E;
+ if (left_right || up_down) {
+ if (theta == 0) {
+ val = up_down ? KM_DIRECTION_N : KM_DIRECTION_E;
+ }
}
- else if (theta == 1) {
- val = KM_DIRECTION_NE;
- }
- else if (theta == 2) {
- val = KM_DIRECTION_N;
- }
- else if (theta == 3) {
- val = KM_DIRECTION_NW;
- }
- else if (theta == -1) {
- val = KM_DIRECTION_SE;
- }
- else if (theta == -2) {
- val = KM_DIRECTION_S;
- }
- else if (theta == -3) {
- val = KM_DIRECTION_SW;
+ else {
+ if (theta == 0) {
+ val = KM_DIRECTION_E;
+ }
+ else if (theta == 1) {
+ val = KM_DIRECTION_NE;
+ }
+ else if (theta == 2) {
+ val = KM_DIRECTION_N;
+ }
+ else if (theta == 3) {
+ val = KM_DIRECTION_NW;
+ }
+ else if (theta == -1) {
+ val = KM_DIRECTION_SE;
+ }
+ else if (theta == -2) {
+ val = KM_DIRECTION_S;
+ }
+ else if (theta == -3) {
+ val = KM_DIRECTION_SW;
+ }
}
#if 0
diff --git a/source/blender/windowmanager/intern/wm_event_system.cc b/source/blender/windowmanager/intern/wm_event_system.cc
index cf779f1bdf9..c888f9a7692 100644
--- a/source/blender/windowmanager/intern/wm_event_system.cc
+++ b/source/blender/windowmanager/intern/wm_event_system.cc
@@ -1292,6 +1292,11 @@ int WM_operator_repeat(bContext *C, wmOperator *op)
op->flag &= ~op_flag;
return ret;
}
+int WM_operator_invoke_last(bContext *C, wmOperator *op)
+{
+ const int ret = WM_operator_name_call_ptr(C, op->type, WM_OP_INVOKE_DEFAULT, NULL, NULL);
+ return ret;
+}
int WM_operator_repeat_last(bContext *C, wmOperator *op)
{
const int op_flag = OP_IS_REPEAT_LAST;
diff --git a/source/blender/windowmanager/intern/wm_gesture_ops.c b/source/blender/windowmanager/intern/wm_gesture_ops.c
index ae8c446bd87..14c40af15f0 100644
--- a/source/blender/windowmanager/intern/wm_gesture_ops.c
+++ b/source/blender/windowmanager/intern/wm_gesture_ops.c
@@ -29,6 +29,7 @@
#include "ED_screen.h"
#include "ED_select_utils.h"
+#include "ED_view3d.h"
#include "UI_interface.h"
@@ -85,6 +86,18 @@ static void gesture_modal_state_to_operator(wmOperator *op, int modal_state)
}
}
+static void gesture_toggle_xray(bContext *C)
+{
+ wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_toggle_xray", true);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ BLI_assert(ot);
+ PointerRNA ptr;
+ WM_operator_properties_create_ptr(&ptr, ot);
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr, NULL);
+ WM_operator_properties_free(&ptr);
+ ts->auto_xray_reset ^= true;
+}
+
static int UNUSED_FUNCTION(gesture_modal_state_from_operator)(wmOperator *op)
{
PropertyRNA *prop;
@@ -163,9 +176,26 @@ static bool gesture_box_apply(bContext *C, wmOperator *op)
int WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
wmWindow *win = CTX_wm_window(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ Object *obedit = CTX_data_edit_object(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
const ARegion *region = CTX_wm_region(C);
const bool wait_for_input = !WM_event_is_mouse_drag_or_press(event) &&
RNA_boolean_get(op->ptr, "wait_for_input");
+
+ const bool auto_xray = ts->auto_xray && ts->auto_xray_box ?
+ obedit ? ts->auto_xray_edit : ts->auto_xray_object :
+ false;
+
+ if (ts->auto_xray_reset) {
+ ts->auto_xray_reset ^= true;
+ }
+
+ if (v3d && auto_xray) {
+ if (!XRAY_FLAG_ENABLED(v3d)) {
+ gesture_toggle_xray(C);
+ }
+ }
if (wait_for_input) {
op->customdata = WM_gesture_new(win, region, event, WM_GESTURE_CROSS_RECT);
@@ -190,8 +220,11 @@ int WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
wmWindow *win = CTX_wm_window(C);
+ View3D *v3d = CTX_wm_view3d(C);
wmGesture *gesture = op->customdata;
rcti *rect = gesture->customdata;
+ Object *obedit = CTX_data_edit_object(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
if (event->type == EVT_MODAL_MAP) {
switch (event->val) {
@@ -214,13 +247,22 @@ int WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
gesture->modal_state = event->val;
}
if (gesture_box_apply(C, op)) {
+ if (ts->auto_xray_reset) {
+ gesture_toggle_xray(C);
+ }
gesture_modal_end(C, op);
return OPERATOR_FINISHED;
}
+ if (ts->auto_xray_reset) {
+ gesture_toggle_xray(C);
+ }
gesture_modal_end(C, op);
return OPERATOR_CANCELLED;
}
case GESTURE_MODAL_CANCEL: {
+ if (ts->auto_xray_reset) {
+ gesture_toggle_xray(C);
+ }
gesture_modal_end(C, op);
return OPERATOR_CANCELLED;
}
@@ -286,8 +328,24 @@ static void gesture_circle_apply(bContext *C, wmOperator *op);
int WM_gesture_circle_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
wmWindow *win = CTX_wm_window(C);
+ View3D *v3d = CTX_wm_view3d(C);
const bool wait_for_input = !WM_event_is_mouse_drag_or_press(event) &&
RNA_boolean_get(op->ptr, "wait_for_input");
+ Object *obedit = CTX_data_edit_object(C);
+ ToolSettings *ts = win->scene->toolsettings;
+ const bool auto_xray = ts->auto_xray && ts->auto_xray_circle ?
+ obedit ? ts->auto_xray_edit : ts->auto_xray_object :
+ false;
+
+ if (ts->auto_xray_reset) {
+ ts->auto_xray_reset ^= true;
+ }
+
+ if (v3d && auto_xray) {
+ if (!XRAY_FLAG_ENABLED(v3d)) {
+ gesture_toggle_xray(C);
+ }
+ }
op->customdata = WM_gesture_new(win, CTX_wm_region(C), event, WM_GESTURE_CIRCLE);
wmGesture *gesture = op->customdata;
@@ -345,11 +403,14 @@ static void gesture_circle_apply(bContext *C, wmOperator *op)
int WM_gesture_circle_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
wmWindow *win = CTX_wm_window(C);
+ View3D *v3d = CTX_wm_view3d(C);
wmGesture *gesture = op->customdata;
rcti *rect = gesture->customdata;
- if (event->type == MOUSEMOVE) {
+ Object *obedit = CTX_data_edit_object(C);
+ ToolSettings *ts = win->scene->toolsettings;
+ if (event->type == MOUSEMOVE) {
rect->xmin = event->xy[0] - gesture->winrct.xmin;
rect->ymin = event->xy[1] - gesture->winrct.ymin;
@@ -415,6 +476,9 @@ int WM_gesture_circle_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
if (is_finished) {
+ if (ts->auto_xray_reset) {
+ gesture_toggle_xray(C);
+ }
gesture_modal_end(C, op);
return OPERATOR_FINISHED; /* use finish or we don't get an undo */
}
@@ -477,7 +541,24 @@ void WM_OT_circle_gesture(wmOperatorType *ot)
int WM_gesture_lasso_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
wmWindow *win = CTX_wm_window(C);
+ View3D *v3d = CTX_wm_view3d(C);
PropertyRNA *prop;
+ Object *obedit = CTX_data_edit_object(C);
+ ToolSettings *ts = win->scene->toolsettings;
+
+ const bool auto_xray = ts->auto_xray && ts->auto_xray_lasso ?
+ obedit ? ts->auto_xray_edit : ts->auto_xray_object :
+ false;
+
+ if (ts->auto_xray_reset) {
+ ts->auto_xray_reset ^= true;
+ }
+
+ if (v3d && auto_xray) {
+ if (!XRAY_FLAG_ENABLED(v3d)) {
+ gesture_toggle_xray(C);
+ }
+ }
op->customdata = WM_gesture_new(win, CTX_wm_region(C), event, WM_GESTURE_LASSO);
@@ -517,6 +598,10 @@ static int gesture_lasso_apply(bContext *C, wmOperator *op)
int retval = OPERATOR_FINISHED;
wmGesture *gesture = op->customdata;
PointerRNA itemptr;
+ View3D *v3d = CTX_wm_view3d(C);
+ Object *obedit = CTX_data_edit_object(C);
+ wmWindow *win = CTX_wm_window(C);
+ ToolSettings *ts = win->scene->toolsettings;
float loc[2];
int i;
const short *lasso = gesture->customdata;
@@ -538,12 +623,20 @@ static int gesture_lasso_apply(bContext *C, wmOperator *op)
OPERATOR_RETVAL_CHECK(retval);
}
+ if (ts->auto_xray_reset) {
+ gesture_toggle_xray(C);
+ }
+
return retval;
}
int WM_gesture_lasso_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
wmGesture *gesture = op->customdata;
+ View3D *v3d = CTX_wm_view3d(C);
+ Object *obedit = CTX_data_edit_object(C);
+ wmWindow *win = CTX_wm_window(C);
+ ToolSettings *ts = win->scene->toolsettings;
if (event->type == EVT_MODAL_MAP) {
switch (event->val) {
@@ -597,6 +690,9 @@ int WM_gesture_lasso_modal(bContext *C, wmOperator *op, const wmEvent *event)
break;
}
case EVT_ESCKEY: {
+ if (ts->auto_xray_reset) {
+ gesture_toggle_xray(C);
+ }
gesture_modal_end(C, op);
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c
index bd3322a8023..c2766a791aa 100644
--- a/source/blender/windowmanager/intern/wm_operator_props.c
+++ b/source/blender/windowmanager/intern/wm_operator_props.c
@@ -411,8 +411,60 @@ void WM_operator_properties_gesture_box_ex(wmOperatorType *ot, bool deselect, bo
{
PropertyRNA *prop;
+ static const EnumPropertyItem face_select_items[] = {
+ {FACE_DEFAULT,
+ "FACE_DEFAULT",
+ 0,
+ "Default",
+ "Select faces that are touched by the selection area in near select. Select faces whose "
+ "center is touched by the selection area in X-Ray select"},
+ {FACE_TOUCH,
+ "FACE_TOUCH",
+ 0,
+ "Touch",
+ "Select faces that are touched by the selection area"},
+ {FACE_ENCLOSE,
+ "FACE_ENCLOSE",
+ 0,
+ "Enclose",
+ "Select faces that are fully inside the selection area"},
+ {FACE_CENTER,
+ "FACE_CENTER",
+ 0,
+ "Center",
+ "Select faces whose center is touched by the selection area"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem edge_select_items[] = {
+ {EDGE_DEFAULT,
+ "EDGE_DEFAULT",
+ 0,
+ "Default",
+ "Select edges that are fully inside the selection area. If no edges are fully inside the "
+ "selection area, select edges that are touched by the selection area"},
+ {EDGE_TOUCH,
+ "EDGE_TOUCH",
+ 0,
+ "Touch",
+ "Select edges that are touched by the selection area"},
+ {EDGE_ENCLOSE,
+ "EDGE_ENCLOSE",
+ 0,
+ "Enclose",
+ "Select edges that are fully inside the selection area"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
WM_operator_properties_border(ot);
+ prop = RNA_def_boolean(ot->srna, "select_origin_box", false, "Select Object Origin", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_enum(ot->srna, "face_type", face_select_items, 0, "Face Select", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_enum(ot->srna, "edge_type", edge_select_items, 0, "Edge Select", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
if (deselect) {
prop = RNA_def_boolean(
ot->srna, "deselect", false, "Deselect", "Deselect rather than select items");
@@ -519,6 +571,57 @@ void WM_operator_properties_gesture_box_zoom(wmOperatorType *ot)
void WM_operator_properties_gesture_lasso(wmOperatorType *ot)
{
PropertyRNA *prop;
+ static const EnumPropertyItem face_select_items[] = {
+ {FACE_DEFAULT,
+ "FACE_DEFAULT",
+ 0,
+ "Default",
+ "Select faces that are touched by the selection area in near select. Select faces whose "
+ "center is touched by the selection area in X-Ray select"},
+ {FACE_TOUCH,
+ "FACE_TOUCH",
+ 0,
+ "Touch",
+ "Select faces that are touched by the selection area"},
+ {FACE_ENCLOSE,
+ "FACE_ENCLOSE",
+ 0,
+ "Enclose",
+ "Select faces that are fully inside the selection area"},
+ {FACE_CENTER,
+ "FACE_CENTER",
+ 0,
+ "Center",
+ "Select faces whose center is touched by the selection area"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem edge_select_items[] = {
+ {EDGE_DEFAULT,
+ "EDGE_DEFAULT",
+ 0,
+ "Default",
+ "Select edges that are fully inside the selection area. If no edges are fully inside the "
+ "selection area, select edges that are touched by the selection area"},
+ {EDGE_TOUCH,
+ "EDGE_TOUCH",
+ 0,
+ "Touch",
+ "Select edges that are touched by the selection area"},
+ {EDGE_ENCLOSE,
+ "EDGE_ENCLOSE",
+ 0,
+ "Enclose",
+ "Select edges that are fully inside the selection area"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ WM_operator_properties_border(ot);
+
+ prop = RNA_def_enum(ot->srna, "face_type", face_select_items, 0, "Face Select", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_enum(ot->srna, "edge_type", edge_select_items, 0, "Edge Select", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
@@ -557,6 +660,45 @@ void WM_operator_properties_gesture_circle(wmOperatorType *ot)
PropertyRNA *prop;
const int radius_default = 25;
+ static const EnumPropertyItem face_select_items[] = {
+ {FACE_DEFAULT,
+ "FACE_DEFAULT",
+ 0,
+ "Default",
+ "Select faces that are touched by the selection area in near select. Select faces whose "
+ "center is touched by the selection area in X-Ray select"},
+ {FACE_TOUCH,
+ "FACE_TOUCH",
+ 0,
+ "Touch",
+ "Select faces that are touched by the selection area"},
+ {FACE_ENCLOSE,
+ "FACE_ENCLOSE",
+ 0,
+ "Enclose",
+ "Select faces that are fully inside the selection area"},
+ {FACE_CENTER,
+ "FACE_CENTER",
+ 0,
+ "Center",
+ "Select faces whose center is touched by the selection area"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem edge_select_items[] = {
+ {EDGE_TOUCH,
+ "EDGE_TOUCH",
+ 0,
+ "Touch",
+ "Select edges that are touched by the selection area"},
+ {EDGE_ENCLOSE,
+ "EDGE_ENCLOSE",
+ 0,
+ "Enclose",
+ "Select edges that are fully inside the selection area"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
prop = RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
@@ -565,6 +707,13 @@ void WM_operator_properties_gesture_circle(wmOperatorType *ot)
prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ prop = RNA_def_boolean(ot->srna, "select_origin_circle", true, "Select Object Origin", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_enum(ot->srna, "face_type", face_select_items, 0, "Face Select", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_enum(ot->srna, "edge_type", edge_select_items, 0, "Edge Select", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
void WM_operator_properties_mouse_select(wmOperatorType *ot)