Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2018-09-09 09:11:02 +0300
committerCampbell Barton <ideasman42@gmail.com>2018-09-10 07:35:04 +0300
commit20634fd433b07bbd90358a625792292e9581a0f6 (patch)
treeb6be45ddf341ce7d2dc8c85a67480e6815d4a6e6 /source/blender/editors/mesh
parent2b5d4d426a9b8483539d14b6e9ab90da262c2ecb (diff)
Tool System: use preselect highlight w/ poly-build
- Poly build now uses a new gizmo for pre-selection which has the same behavior as loop-cut. This replaces hack where mouse-move set the active element which was no longer working properly because of missing depsgraph updates. - Multi-object support for poly-build. - Support for deformed cage. - Fix error where changing active object wasn't properly refreshing the preselect gizmo (for loopcut too). Currently holding Alt to select non-boundary element's isn't working.
Diffstat (limited to 'source/blender/editors/mesh')
-rw-r--r--source/blender/editors/mesh/CMakeLists.txt1
-rw-r--r--source/blender/editors/mesh/editmesh_polybuild.c321
-rw-r--r--source/blender/editors/mesh/editmesh_preselect_elem.c218
-rw-r--r--source/blender/editors/mesh/editmesh_select.c221
-rw-r--r--source/blender/editors/mesh/mesh_ops.c1
5 files changed, 575 insertions, 187 deletions
diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt
index 4784f07c297..43360af9e18 100644
--- a/source/blender/editors/mesh/CMakeLists.txt
+++ b/source/blender/editors/mesh/CMakeLists.txt
@@ -58,6 +58,7 @@ set(SRC
editmesh_path.c
editmesh_polybuild.c
editmesh_preselect.c
+ editmesh_preselect_elem.c
editmesh_rip.c
editmesh_rip_edge.c
editmesh_select.c
diff --git a/source/blender/editors/mesh/editmesh_polybuild.c b/source/blender/editors/mesh/editmesh_polybuild.c
index 9b7d460973a..adf5802cdcf 100644
--- a/source/blender/editors/mesh/editmesh_polybuild.c
+++ b/source/blender/editors/mesh/editmesh_polybuild.c
@@ -25,6 +25,8 @@
* an experimental tool for quickly constructing/manipulating faces.
*/
+#include "MEM_guardedalloc.h"
+
#include "DNA_object_types.h"
#include "BLI_math.h"
@@ -33,10 +35,13 @@
#include "BKE_report.h"
#include "BKE_editmesh.h"
#include "BKE_mesh.h"
+#include "BKE_layer.h"
#include "WM_types.h"
+#include "ED_object.h"
#include "ED_mesh.h"
+#include "ED_scene.h"
#include "ED_screen.h"
#include "ED_transform.h"
#include "ED_view3d.h"
@@ -50,6 +55,8 @@
#include "WM_api.h"
+#include "DEG_depsgraph.h"
+
/* -------------------------------------------------------------------- */
/** \name Local Utilities
* \{ */
@@ -63,6 +70,98 @@ static void edbm_selectmode_ensure(Scene *scene, BMEditMesh *em, short selectmod
}
}
+/* Could make public, for now just keep here. */
+static void edbm_flag_disable_all_multi(ViewLayer *view_layer, const char hflag)
+{
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_iter = objects[ob_index];
+ BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
+ BMesh *bm_iter = em_iter->bm;
+ if (bm_iter->totvertsel) {
+ EDBM_flag_disable_all(em_iter, hflag);
+ if (hflag & BM_ELEM_SELECT) {
+ BM_select_history_clear(em_iter->bm);
+ }
+ DEG_id_tag_update(ob_iter->data, DEG_TAG_SELECT_UPDATE);
+ }
+ }
+ MEM_freeN(objects);
+}
+
+/* When accessed as a tool, get the active edge from the preselection gizmo. */
+static bool edbm_preselect_or_active(
+ bContext *C,
+ Base **r_base,
+ BMElem **r_ele)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ ARegion *ar = CTX_wm_region(C);
+ wmGizmoMap *gzmap = ar->gizmo_map;
+ wmGizmoGroup *gzgroup = gzmap ? WM_gizmomap_group_find(gzmap, "VIEW3D_GGT_mesh_preselect_elem") : NULL;
+ if (gzgroup != NULL) {
+ wmGizmo *gz = gzgroup->gizmos.first;
+ const int object_index = RNA_int_get(gz->ptr, "object_index");
+
+ /* weak, allocate an array just to access the index. */
+ Base *base = NULL;
+ Object *obedit = NULL;
+ {
+ uint bases_len;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(view_layer, &bases_len);
+ if (object_index < bases_len) {
+ base = bases[object_index];
+ obedit = base->object;
+ }
+ MEM_freeN(bases);
+ }
+
+ *r_base = base;
+ *r_ele = NULL;
+
+ if (obedit) {
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ const int vert_index = RNA_int_get(gz->ptr, "vert_index");
+ const int edge_index = RNA_int_get(gz->ptr, "edge_index");
+ const int face_index = RNA_int_get(gz->ptr, "face_index");
+ if (vert_index != -1) {
+ *r_ele = (BMElem *)BM_vert_at_index_find(bm, vert_index);
+ }
+ else if (edge_index != -1) {
+ *r_ele = (BMElem *)BM_edge_at_index_find(bm, edge_index);
+ }
+ else if (face_index != -1) {
+ *r_ele = (BMElem *)BM_face_at_index_find(bm, face_index);
+ }
+ }
+ }
+ else {
+ Base *base = view_layer->basact;
+ Object *obedit = base->object;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ *r_base = base;
+ *r_ele = BM_mesh_active_elem_get(bm);
+ }
+ return (*r_ele != NULL);
+}
+
+static bool edbm_preselect_or_active_init_viewcontext(
+ bContext *C,
+ ViewContext *vc,
+ Base **r_base,
+ BMElem **r_ele)
+{
+ em_setup_viewcontext(C, vc);
+ bool ok = edbm_preselect_or_active(C, r_base, r_ele);
+ if (ok) {
+ ED_view3d_viewcontext_init_object(vc, (*r_base)->object);
+ }
+ return ok;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -72,15 +171,15 @@ static void edbm_selectmode_ensure(Scene *scene, BMEditMesh *em, short selectmod
static int edbm_polybuild_face_at_cursor_invoke(
bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
- ViewContext vc;
float center[3];
bool changed = false;
- em_setup_viewcontext(C, &vc);
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewContext vc;
+ Base *basact = NULL;
+ BMElem *ele_act = NULL;
+ edbm_preselect_or_active_init_viewcontext(C, &vc, &basact, &ele_act);
+ BMEditMesh *em = vc.em;
BMesh *bm = em->bm;
- BMElem *ele_act = BM_mesh_active_elem_get(bm);
invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
@@ -95,7 +194,7 @@ static int edbm_polybuild_face_at_cursor_invoke(
mul_m4_v3(vc.obedit->imat, center);
BMVert *v_new = BM_vert_create(bm, center, NULL, BM_CREATE_NOP);
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ edbm_flag_disable_all_multi(vc.view_layer, BM_ELEM_SELECT);
BM_vert_select_set(bm, v_new, true);
changed = true;
}
@@ -118,7 +217,7 @@ static int edbm_polybuild_face_at_cursor_invoke(
// BMFace *f_new =
BM_face_create_verts(bm, v_tri, 3, f_reference, BM_CREATE_NOP, true);
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ edbm_flag_disable_all_multi(vc.view_layer, BM_ELEM_SELECT);
BM_vert_select_set(bm, v_tri[2], true);
changed = true;
}
@@ -169,7 +268,7 @@ static int edbm_polybuild_face_at_cursor_invoke(
// BMFace *f_new =
BM_face_create_verts(bm, v_quad, 4, f_reference, BM_CREATE_NOP, true);
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ edbm_flag_disable_all_multi(vc.view_layer, BM_ELEM_SELECT);
BM_vert_select_set(bm, v_quad[2], true);
changed = true;
}
@@ -188,11 +287,13 @@ static int edbm_polybuild_face_at_cursor_invoke(
}
if (changed) {
- BM_select_history_clear(bm);
-
EDBM_mesh_normals_update(em);
EDBM_update_generic(em, true, true);
+ if (vc.view_layer->basact != basact) {
+ ED_object_base_activate(C, basact);
+ }
+
WM_event_add_mousemove(C);
return OPERATOR_FINISHED;
@@ -229,13 +330,14 @@ void MESH_OT_polybuild_face_at_cursor(wmOperatorType *ot)
static int edbm_polybuild_split_at_cursor_invoke(
bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
- ViewContext vc;
float center[3];
bool changed = false;
- em_setup_viewcontext(C, &vc);
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewContext vc;
+ Base *basact = NULL;
+ BMElem *ele_act = NULL;
+ edbm_preselect_or_active_init_viewcontext(C, &vc, &basact, &ele_act);
+ BMEditMesh *em = vc.em;
BMesh *bm = em->bm;
invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
@@ -243,8 +345,6 @@ static int edbm_polybuild_split_at_cursor_invoke(
edbm_selectmode_ensure(vc.scene, vc.em, SCE_SELECT_VERTEX);
- BMElem *ele_act = BM_mesh_active_elem_get(bm);
-
if (ele_act == NULL || ele_act->head.hflag == BM_FACE) {
return OPERATOR_PASS_THROUGH;
}
@@ -259,7 +359,7 @@ static int edbm_polybuild_split_at_cursor_invoke(
BMVert *v_new = BM_edge_split(bm, e_act, e_act->v1, NULL, CLAMPIS(fac, 0.0f, 1.0f));
copy_v3_v3(v_new->co, center);
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ edbm_flag_disable_all_multi(vc.view_layer, BM_ELEM_SELECT);
BM_vert_select_set(bm, v_new, true);
changed = true;
}
@@ -269,13 +369,15 @@ static int edbm_polybuild_split_at_cursor_invoke(
}
if (changed) {
- BM_select_history_clear(bm);
-
EDBM_mesh_normals_update(em);
EDBM_update_generic(em, true, true);
WM_event_add_mousemove(C);
+ if (vc.view_layer->basact != basact) {
+ ED_object_base_activate(C, basact);
+ }
+
return OPERATOR_FINISHED;
}
else {
@@ -312,23 +414,19 @@ void MESH_OT_polybuild_split_at_cursor(wmOperatorType *ot)
static int edbm_polybuild_dissolve_at_cursor_invoke(
bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- ViewContext vc;
- em_setup_viewcontext(C, &vc);
bool changed = false;
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewContext vc;
+ Base *basact = NULL;
+ BMElem *ele_act = NULL;
+ edbm_preselect_or_active_init_viewcontext(C, &vc, &basact, &ele_act);
+ BMEditMesh *em = vc.em;
BMesh *bm = em->bm;
- BMVert *v_act = BM_mesh_active_vert_get(bm);
- BMEdge *e_act = BM_mesh_active_edge_get(bm);
-
- invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
- ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
edbm_selectmode_ensure(vc.scene, vc.em, SCE_SELECT_VERTEX);
-
- if (e_act) {
+ if (ele_act->head.htype == BM_EDGE) {
+ BMEdge *e_act = (BMEdge *)ele_act;
BMLoop *l_a, *l_b;
if (BM_edge_loop_pair(e_act, &l_a, &l_b)) {
BMFace *f_new = BM_faces_join_pair(bm, l_a, l_b, true);
@@ -337,7 +435,8 @@ static int edbm_polybuild_dissolve_at_cursor_invoke(
}
}
}
- else if (v_act) {
+ else if (ele_act->head.htype == BM_VERT) {
+ BMVert *v_act = (BMVert *)ele_act;
if (BM_vert_is_edge_pair(v_act)) {
BM_edge_collapse(
bm, v_act->e, v_act,
@@ -356,13 +455,15 @@ static int edbm_polybuild_dissolve_at_cursor_invoke(
}
if (changed) {
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
-
- BM_select_history_clear(bm);
+ edbm_flag_disable_all_multi(vc.view_layer, BM_ELEM_SELECT);
EDBM_mesh_normals_update(em);
EDBM_update_generic(em, true, true);
+ if (vc.view_layer->basact != basact) {
+ ED_object_base_activate(C, basact);
+ }
+
WM_event_add_mousemove(C);
return OPERATOR_FINISHED;
@@ -388,155 +489,3 @@ void MESH_OT_polybuild_dissolve_at_cursor(wmOperatorType *ot)
}
/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Cursor Gizmo
- *
- * \note This may need its own file, for now not.
- * \{ */
-
-static BMElem *edbm_hover_preselect(
- bContext *C,
- const int mval[2],
- bool use_boundary)
-{
- ViewContext vc;
-
- em_setup_viewcontext(C, &vc);
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
-
- invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
- ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
-
- const float mval_fl[2] = {UNPACK2(mval)};
- float ray_origin[3], ray_direction[3];
-
- BMElem *ele_best = NULL;
-
- if (ED_view3d_win_to_ray(
- CTX_data_depsgraph(C),
- vc.ar, vc.v3d, mval_fl,
- ray_origin, ray_direction, true))
- {
- BMEdge *e;
-
- BMIter eiter;
- float dist_sq_best = FLT_MAX;
-
- BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
- if ((BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false) &&
- (!use_boundary || BM_edge_is_boundary(e)))
- {
- float dist_sq_test;
- float point[3];
- float depth;
-#if 0
- dist_sq_test = dist_squared_ray_to_seg_v3(
- ray_origin, ray_direction,
- e->v1->co, e->v2->co,
- point, &depth);
-#else
- mid_v3_v3v3(point, e->v1->co, e->v2->co);
- dist_sq_test = dist_squared_to_ray_v3(
- ray_origin, ray_direction,
- point, &depth);
-#endif
-
- if (dist_sq_test < dist_sq_best) {
- dist_sq_best = dist_sq_test;
- ele_best = (BMElem *)e;
- }
-
- dist_sq_test = dist_squared_to_ray_v3(
- ray_origin, ray_direction,
- e->v1->co, &depth);
- if (dist_sq_test < dist_sq_best) {
- dist_sq_best = dist_sq_test;
- ele_best = (BMElem *)e->v1;
- }
- dist_sq_test = dist_squared_to_ray_v3(
- ray_origin, ray_direction,
- e->v2->co, &depth);
- if (dist_sq_test < dist_sq_best) {
- dist_sq_best = dist_sq_test;
- ele_best = (BMElem *)e->v2;
- }
- }
- }
- }
- return ele_best;
-}
-
-/*
- * Developer note: this is not advocating pre-selection highlighting.
- * This is just a quick way to test how a tool for interactively editing polygons may work. */
-static int edbm_polybuild_hover_invoke(
- bContext *C, wmOperator *op, const wmEvent *event)
-{
- const bool use_boundary = RNA_boolean_get(op->ptr, "use_boundary");
- ViewContext vc;
-
- em_setup_viewcontext(C, &vc);
-
- /* Vertex selection is needed */
- if ((vc.scene->toolsettings->selectmode & SCE_SELECT_VERTEX) == 0) {
- return OPERATOR_PASS_THROUGH;
- }
-
- /* Don't overwrite click-drag events. */
- if (use_boundary == false) {
- /* pass */
- }
- else if (vc.win->tweak ||
- (vc.win->eventstate->check_click &&
- vc.win->eventstate->prevval == KM_PRESS &&
- ISMOUSE(vc.win->eventstate->prevtype)))
- {
- return OPERATOR_PASS_THROUGH;
- }
-
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
- BMElem *ele_active = BM_mesh_active_elem_get(bm);
- BMElem *ele_hover = edbm_hover_preselect(C, event->mval, use_boundary);
-
- if (ele_hover && (ele_hover != ele_active)) {
- if (event->shift == 0) {
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
- BM_select_history_clear(bm);
- }
- BM_elem_select_set(bm, ele_hover, true);
- BM_select_history_store(em->bm, ele_hover);
- BKE_mesh_batch_cache_dirty_tag(obedit->data, BKE_MESH_BATCH_DIRTY_SELECT);
-
- ED_region_tag_redraw(vc.ar);
-
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
-}
-
-void MESH_OT_polybuild_hover(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Poly Build Hover";
- ot->idname = "MESH_OT_polybuild_hover";
- ot->description = "";
-
- /* api callbacks */
- ot->invoke = edbm_polybuild_hover_invoke;
- ot->poll = EDBM_view3d_poll;
-
- /* flags */
- ot->flag = OPTYPE_INTERNAL;
-
- /* properties */
- RNA_def_boolean(ot->srna, "use_boundary", false, "Boundary", "Select only boundary geometry");
-}
-
-/** \} */
diff --git a/source/blender/editors/mesh/editmesh_preselect_elem.c b/source/blender/editors/mesh/editmesh_preselect_elem.c
new file mode 100644
index 00000000000..e0b06019de1
--- /dev/null
+++ b/source/blender/editors/mesh/editmesh_preselect_elem.c
@@ -0,0 +1,218 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/mesh/editmesh_preselect_elem.c
+ * \ingroup edmesh
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_stack.h"
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_editmesh.h"
+
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
+#include "DNA_object_types.h"
+
+#include "ED_mesh.h"
+#include "ED_view3d.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh Element Pre-Select
+ * Public API:
+ *
+ * #EDBM_preselect_elem_create
+ * #EDBM_preselect_elem_destroy
+ * #EDBM_preselect_elem_clear
+ * #EDBM_preselect_elem_draw
+ * #EDBM_preselect_elem_update_from_single
+ *
+ * \{ */
+
+static void vcos_get(BMVert *v, float r_co[3], const float (*coords)[3])
+{
+ if (coords) {
+ copy_v3_v3(r_co, coords[BM_elem_index_get(v)]);
+ }
+ else {
+ copy_v3_v3(r_co, v->co);
+ }
+}
+
+static void vcos_get_pair(BMVert *v[2], float r_cos[2][3], const float (*coords)[3])
+{
+ if (coords) {
+ for (int j = 0; j < 2; j++) {
+ copy_v3_v3(r_cos[j], coords[BM_elem_index_get(v[j])]);
+ }
+ }
+ else {
+ for (int j = 0; j < 2; j++) {
+ copy_v3_v3(r_cos[j], v[j]->co);
+ }
+ }
+}
+
+struct EditMesh_PreSelElem {
+ float (*edges)[2][3];
+ int edges_len;
+
+ float (*verts)[3];
+ int verts_len;
+};
+
+struct EditMesh_PreSelElem *EDBM_preselect_elem_create(void)
+{
+ struct EditMesh_PreSelElem *psel = MEM_callocN(sizeof(*psel), __func__);
+ return psel;
+}
+
+void EDBM_preselect_elem_destroy(
+ struct EditMesh_PreSelElem *psel)
+{
+ EDBM_preselect_elem_clear(psel);
+ MEM_freeN(psel);
+}
+
+void EDBM_preselect_elem_clear(
+ struct EditMesh_PreSelElem *psel)
+{
+ MEM_SAFE_FREE(psel->edges);
+ psel->edges_len = 0;
+
+ MEM_SAFE_FREE(psel->verts);
+ psel->verts_len = 0;
+}
+
+void EDBM_preselect_elem_draw(
+ struct EditMesh_PreSelElem *psel, const float matrix[4][4])
+{
+ if ((psel->edges_len == 0) && (psel->verts_len == 0)) {
+ return;
+ }
+
+ GPU_depth_test(false);
+
+ GPU_matrix_push();
+ GPU_matrix_mul(matrix);
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor3ub(255, 0, 255);
+
+ if (psel->edges_len > 0) {
+ immBegin(GPU_PRIM_LINES, psel->edges_len * 2);
+
+ for (int i = 0; i < psel->edges_len; i++) {
+ immVertex3fv(pos, psel->edges[i][0]);
+ immVertex3fv(pos, psel->edges[i][1]);
+ }
+
+ immEnd();
+ }
+
+ if (psel->verts_len > 0) {
+ GPU_point_size(3.0f);
+
+ immBegin(GPU_PRIM_POINTS, psel->verts_len);
+
+ for (int i = 0; i < psel->verts_len; i++) {
+ immVertex3fv(pos, psel->verts[i]);
+ }
+
+ immEnd();
+ }
+
+ immUnbindProgram();
+
+ GPU_matrix_pop();
+
+ /* Reset default */
+ GPU_depth_test(true);
+}
+
+static void view3d_preselect_mesh_elem_update_from_vert(
+ struct EditMesh_PreSelElem *psel,
+ BMesh *UNUSED(bm), BMVert *eve, const float (*coords)[3])
+{
+ float (*verts)[3] = MEM_mallocN(sizeof(*psel->verts), __func__);
+ vcos_get(eve, verts[0], coords);
+ psel->verts = verts;
+ psel->verts_len = 1;
+}
+
+static void view3d_preselect_mesh_elem_update_from_edge(
+ struct EditMesh_PreSelElem *psel,
+ BMesh *UNUSED(bm), BMEdge *eed, const float (*coords)[3])
+{
+ float (*edges)[2][3] = MEM_mallocN(sizeof(*psel->edges), __func__);
+ vcos_get_pair(&eed->v1, edges[0], coords);
+ psel->edges = edges;
+ psel->edges_len = 1;
+}
+
+static void view3d_preselect_mesh_elem_update_from_face(
+ struct EditMesh_PreSelElem *psel,
+ BMesh *UNUSED(bm), BMFace *efa, const float (*coords)[3])
+{
+ float (*edges)[2][3] = MEM_mallocN(sizeof(*psel->edges) * efa->len, __func__);
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
+ int i = 0;
+ do {
+ vcos_get_pair(&l_iter->e->v1, edges[i++], coords);
+ } while ((l_iter = l_iter->next) != l_first);
+ psel->edges = edges;
+ psel->edges_len = efa->len;
+}
+
+void EDBM_preselect_elem_update_from_single(
+ struct EditMesh_PreSelElem *psel,
+ BMesh *bm, BMElem *ele,
+ const float (*coords)[3])
+{
+ EDBM_preselect_elem_clear(psel);
+
+ if (coords) {
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+ }
+
+ switch (ele->head.htype) {
+ case BM_VERT:
+ view3d_preselect_mesh_elem_update_from_vert(psel, bm, (BMVert *)ele, coords);
+ break;
+ case BM_EDGE:
+ view3d_preselect_mesh_elem_update_from_edge(psel, bm, (BMEdge *)ele, coords);
+ break;
+ case BM_FACE:
+ view3d_preselect_mesh_elem_update_from_face(psel, bm, (BMFace *)ele, coords);
+ break;
+ default:
+ BLI_assert(0);
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index df8c095e7bd..86a1366bda3 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -1098,6 +1098,227 @@ bool EDBM_unified_findnearest(
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Alternate Find Nearest Vert/Edge (optional boundary)
+ *
+ * \note This uses ray-cast method instead of backbuffer,
+ * currently used for poly-build.
+ * \{ */
+
+bool EDBM_unified_findnearest_from_raycast(
+ ViewContext *vc,
+ bool use_boundary,
+ Base **r_base,
+ struct BMVert **r_eve,
+ struct BMEdge **r_eed,
+ struct BMFace **r_efa)
+{
+
+ const float mval_fl[2] = {UNPACK2(vc->mval)};
+ float ray_origin[3], ray_direction[3];
+
+ struct {
+ Base *base;
+ BMElem *ele;
+ } best = {NULL};
+
+ if (ED_view3d_win_to_ray(
+ vc->depsgraph,
+ vc->ar, vc->v3d, mval_fl,
+ ray_origin, ray_direction, true))
+ {
+ float dist_sq_best = FLT_MAX;
+
+ const bool use_vert = (r_eve != NULL);
+ const bool use_edge = (r_eed != NULL);
+ const bool use_face = (r_efa != NULL);
+
+ uint bases_len;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc->view_layer, &bases_len);
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ Base *base_iter = bases[base_index];
+ Object *obedit = base_iter->object;
+
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ float imat3[3][3];
+
+ ED_view3d_viewcontext_init_object(vc, obedit);
+ copy_m3_m4(imat3, obedit->obmat);
+ invert_m3(imat3);
+
+ const float (*coords)[3] = NULL;
+ {
+ Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(vc->depsgraph, obedit->data);
+ if (me_eval->runtime.edit_data) {
+ coords = me_eval->runtime.edit_data->vertexCos;
+ }
+ }
+
+ if (coords != NULL) {
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+ }
+
+ if (use_boundary && (use_vert || use_edge)) {
+ BMEdge *e;
+ BMIter eiter;
+ BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
+ if ((BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false) &&
+ (BM_edge_is_boundary(e)))
+ {
+ float depth;
+
+ if (use_vert) {
+ for (uint j = 0; j < 2; j++) {
+ BMVert *v = *((&e->v1) + j);
+ float point[3];
+ mul_v3_m4v3(point, obedit->obmat, coords ? coords[BM_elem_index_get(v)] : v->co);
+ const float dist_sq_test = dist_squared_to_ray_v3(
+ ray_origin, ray_direction,
+ point, &depth);
+ if (dist_sq_test < dist_sq_best) {
+ dist_sq_best = dist_sq_test;
+ best.base = base_iter;
+ best.ele = (BMElem *)v;
+ }
+ }
+ }
+
+ if (use_edge) {
+ float point[3];
+#if 0
+ const float dist_sq_test = dist_squared_ray_to_seg_v3(
+ ray_origin, ray_direction,
+ e->v1->co, e->v2->co,
+ point, &depth);
+#else
+ if (coords) {
+ mid_v3_v3v3(point, coords[BM_elem_index_get(e->v1)], coords[BM_elem_index_get(e->v2)]);
+ }
+ else {
+ mid_v3_v3v3(point, e->v1->co, e->v2->co);
+ }
+ mul_m4_v3(obedit->obmat, point);
+ const float dist_sq_test = dist_squared_to_ray_v3(
+ ray_origin, ray_direction,
+ point, &depth);
+ if (dist_sq_test < dist_sq_best) {
+ dist_sq_best = dist_sq_test;
+ best.base = base_iter;
+ best.ele = (BMElem *)e;
+ }
+#endif
+ }
+ }
+ }
+ }
+ else {
+ /* Non boundary case. */
+ if (use_vert) {
+ BMVert *v;
+ BMIter viter;
+ BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_HIDDEN) == false) {
+ float point[3];
+ mul_v3_m4v3(point, obedit->obmat, v->co);
+ float depth;
+ const float dist_sq_test = dist_squared_to_ray_v3(
+ ray_origin, ray_direction,
+ v->co, &depth);
+ if (dist_sq_test < dist_sq_best) {
+ dist_sq_best = dist_sq_test;
+ best.base = base_iter;
+ best.ele = (BMElem *)v;
+ }
+ }
+ }
+ }
+ if (use_edge) {
+ BMEdge *e;
+ BMIter eiter;
+ BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false) {
+ float point[3];
+ if (coords) {
+ mid_v3_v3v3(point, coords[BM_elem_index_get(e->v1)], coords[BM_elem_index_get(e->v2)]);
+ }
+ else {
+ mid_v3_v3v3(point, e->v1->co, e->v2->co);
+ }
+ mul_m4_v3(obedit->obmat, point);
+ float depth;
+ const float dist_sq_test = dist_squared_to_ray_v3(
+ ray_origin, ray_direction,
+ point, &depth);
+ if (dist_sq_test < dist_sq_best) {
+ dist_sq_best = dist_sq_test;
+ best.base = base_iter;
+ best.ele = (BMElem *)e;
+ }
+ }
+ }
+ }
+ }
+
+ if (use_face) {
+ BMFace *f;
+ BMIter fiter;
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, BM_ELEM_HIDDEN) == false) {
+ float point[3];
+ if (coords) {
+ BM_face_calc_center_mean_vcos(bm, f, point, coords);
+ }
+ else {
+ BM_face_calc_center_mean(f, point);
+ }
+ mul_m4_v3(obedit->obmat, point);
+ float depth;
+ const float dist_sq_test = dist_squared_to_ray_v3(
+ ray_origin, ray_direction,
+ point, &depth);
+ if (dist_sq_test < dist_sq_best) {
+ dist_sq_best = dist_sq_test;
+ best.base = base_iter;
+ best.ele = (BMElem *)f;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ *r_base = best.base;
+ if (r_eve) {
+ *r_eve = NULL;
+ }
+ if (r_eed) {
+ *r_eed = NULL;
+ }
+ if (r_efa) {
+ *r_efa = NULL;
+ }
+
+ if (best.ele) {
+ switch (best.ele->head.htype) {
+ case BM_VERT:
+ *r_eve = (BMVert *)best.ele;
+ break;
+ case BM_EDGE:
+ *r_eed = (BMEdge *)best.ele;
+ break;
+ case BM_FACE:
+ *r_efa = (BMFace *)best.ele;
+ break;
+ default:
+ BLI_assert(0);
+ }
+ }
+ return (best.ele != NULL);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Select Similar (Vert/Edge/Face) Operator
* \{ */
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index acd8079e75a..d1a3aec9551 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -157,7 +157,6 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_polybuild_face_at_cursor);
WM_operatortype_append(MESH_OT_polybuild_split_at_cursor);
WM_operatortype_append(MESH_OT_polybuild_dissolve_at_cursor);
- WM_operatortype_append(MESH_OT_polybuild_hover);
WM_operatortype_append(MESH_OT_uv_texture_add);
WM_operatortype_append(MESH_OT_uv_texture_remove);