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
path: root/source
diff options
context:
space:
mode:
authorPablo Dobarro <pablodp606@gmail.com>2019-08-27 17:19:25 +0300
committerPablo Dobarro <pablodp606@gmail.com>2019-08-27 17:24:16 +0300
commitd8baafd693ebf830d6153bd31bd63521c7569984 (patch)
treeee44ef834e826322e9de79cc943edb8be66041a3 /source
parent2a2fd75ef90f18753d3d6ab33c30e60cd95bf174 (diff)
Edit Mesh: Poly build tool improvements
This commit changes the functionality of the Poly build tool to make it more suitable for retopology tasks: - Click and drag from a boundary edge extrudes a new quad - Click and drag on vertices tweaks the position - Ctrl + click adds geometry. There is a geometry preview in the gizmo. It also can automatically convert triangles to quads. - Shift + click deletes mesh elements (faces or vertices) - Updated preselection code. Different mesh elements take priority depending on the selected action. Reviewed By: campbellbarton Differential Revision: https://developer.blender.org/D5573
Diffstat (limited to 'source')
-rw-r--r--source/blender/editors/include/ED_mesh.h22
-rw-r--r--source/blender/editors/mesh/editmesh_polybuild.c180
-rw-r--r--source/blender/editors/mesh/editmesh_preselect_elem.c206
-rw-r--r--source/blender/editors/mesh/editmesh_select.c159
-rw-r--r--source/blender/editors/mesh/mesh_intern.h2
-rw-r--r--source/blender/editors/mesh/mesh_ops.c21
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c126
7 files changed, 591 insertions, 125 deletions
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 234f36a587b..194378d6bb6 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -194,8 +194,11 @@ bool EDBM_unified_findnearest(struct ViewContext *vc,
bool EDBM_unified_findnearest_from_raycast(struct ViewContext *vc,
struct Base **bases,
const uint bases_len,
- bool use_boundary,
- int *r_base_index,
+ bool use_boundary_vertices,
+ bool use_boundary_edges,
+ int *r_base_index_vert,
+ int *r_base_index_edge,
+ int *r_base_index_face,
struct BMVert **r_eve,
struct BMEdge **r_eed,
struct BMFace **r_efa);
@@ -245,15 +248,30 @@ void EDBM_preselect_edgering_update_from_edge(struct EditMesh_PreSelEdgeRing *ps
/* editmesh_preselect_elem.c */
struct EditMesh_PreSelElem;
+typedef enum eEditMesh_PreSelPreviewAction {
+ PRESELECT_ACTION_TRANSFORM = 1,
+ PRESELECT_ACTION_CREATE = 2,
+ PRESELECT_ACTION_DELETE = 3,
+} eEditMesh_PreSelPreviewAction;
+
struct EditMesh_PreSelElem *EDBM_preselect_elem_create(void);
void EDBM_preselect_elem_destroy(struct EditMesh_PreSelElem *psel);
void EDBM_preselect_elem_clear(struct EditMesh_PreSelElem *psel);
+void EDBM_preselect_preview_clear(struct EditMesh_PreSelElem *psel);
void EDBM_preselect_elem_draw(struct EditMesh_PreSelElem *psel, const float matrix[4][4]);
void EDBM_preselect_elem_update_from_single(struct EditMesh_PreSelElem *psel,
struct BMesh *bm,
struct BMElem *ele,
const float (*coords)[3]);
+void EDBM_preselect_elem_update_preview(struct EditMesh_PreSelElem *psel,
+ struct ViewContext *vc,
+ struct BMesh *bm,
+ struct BMElem *ele,
+ const int mval[2]);
+void EDBM_preselect_action_set(struct EditMesh_PreSelElem *psel,
+ eEditMesh_PreSelPreviewAction action);
+eEditMesh_PreSelPreviewAction EDBM_preselect_action_get(struct EditMesh_PreSelElem *psel);
/* mesh_ops.c */
void ED_operatortypes_mesh(void);
void ED_operatormacros_mesh(void);
diff --git a/source/blender/editors/mesh/editmesh_polybuild.c b/source/blender/editors/mesh/editmesh_polybuild.c
index 088d1672cc9..a182bfeb945 100644
--- a/source/blender/editors/mesh/editmesh_polybuild.c
+++ b/source/blender/editors/mesh/editmesh_polybuild.c
@@ -122,15 +122,151 @@ static bool edbm_preselect_or_active_init_viewcontext(bContext *C,
return ok;
}
+static int edbm_polybuild_transform_at_cursor_invoke(bContext *C,
+ wmOperator *UNUSED(op),
+ const wmEvent *UNUSED(event))
+{
+ 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);
+ ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
+
+ edbm_selectmode_ensure(vc.scene, vc.em, SCE_SELECT_VERTEX);
+
+ edbm_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
+ if (ele_act->head.htype == BM_VERT) {
+ BM_vert_select_set(bm, (BMVert *)ele_act, true);
+ }
+ if (ele_act->head.htype == BM_EDGE) {
+ BM_edge_select_set(bm, (BMEdge *)ele_act, true);
+ }
+ if (ele_act->head.htype == BM_FACE) {
+ BM_face_select_set(bm, (BMFace *)ele_act, true);
+ }
+
+ EDBM_mesh_normals_update(em);
+ EDBM_update_generic(em, true, true);
+ if (basact != NULL) {
+ if (vc.view_layer->basact != basact) {
+ ED_object_base_activate(C, basact);
+ }
+ }
+ BM_select_history_store(bm, ele_act);
+ WM_event_add_mousemove(C);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_polybuild_transform_at_cursor(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Poly Build Transform at Cursor";
+ ot->idname = "MESH_OT_polybuild_transform_at_cursor";
+
+ /* api callbacks */
+ ot->invoke = edbm_polybuild_transform_at_cursor_invoke;
+ ot->poll = EDBM_view3d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* to give to transform */
+ Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY);
+}
+
+static int edbm_polybuild_delete_at_cursor_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ bool changed = false;
+
+ 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);
+ ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
+
+ edbm_selectmode_ensure(vc.scene, vc.em, SCE_SELECT_VERTEX);
+
+ if (ele_act->head.htype == BM_FACE) {
+ BMFace *f_act = (BMFace *)ele_act;
+ EDBM_flag_disable_all(em, BM_ELEM_TAG);
+ BM_elem_flag_enable(f_act, BM_ELEM_TAG);
+ if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_TAG, DEL_FACES)) {
+ return OPERATOR_CANCELLED;
+ }
+ changed = true;
+ }
+ 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, true, true);
+ changed = true;
+ }
+ else {
+ EDBM_flag_disable_all(em, BM_ELEM_TAG);
+ BM_elem_flag_enable(v_act, BM_ELEM_TAG);
+
+ if (!EDBM_op_callf(em,
+ op,
+ "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
+ BM_ELEM_TAG,
+ false,
+ false)) {
+ return OPERATOR_CANCELLED;
+ }
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ EDBM_mesh_normals_update(em);
+ EDBM_update_generic(em, true, true);
+ if (basact != NULL) {
+ if (vc.view_layer->basact != basact) {
+ ED_object_base_activate(C, basact);
+ }
+ }
+ WM_event_add_mousemove(C);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void MESH_OT_polybuild_delete_at_cursor(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Poly Build Delete at Cursor";
+ ot->idname = "MESH_OT_polybuild_delete_at_cursor";
+
+ /* api callbacks */
+ ot->invoke = edbm_polybuild_delete_at_cursor_invoke;
+ ot->poll = EDBM_view3d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* to give to transform */
+ Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Face at Cursor
* \{ */
-static int edbm_polybuild_face_at_cursor_invoke(bContext *C,
- wmOperator *UNUSED(op),
- const wmEvent *event)
+static int edbm_polybuild_face_at_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
float center[3];
bool changed = false;
@@ -168,20 +304,27 @@ static int edbm_polybuild_face_at_cursor_invoke(bContext *C,
mul_m4_v3(vc.obedit->obmat, center);
ED_view3d_win_to_3d_int(vc.v3d, vc.ar, center, event->mval, center);
mul_m4_v3(vc.obedit->imat, center);
-
- BMVert *v_tri[3];
- v_tri[0] = e_act->v1;
- v_tri[1] = e_act->v2;
- v_tri[2] = BM_vert_create(bm, center, NULL, BM_CREATE_NOP);
- if (e_act->l && e_act->l->v == v_tri[0]) {
- SWAP(BMVert *, v_tri[0], v_tri[1]);
+ if (f_reference->len == 3 && RNA_boolean_get(op->ptr, "create_quads")) {
+ const float fac = line_point_factor_v3(center, e_act->v1->co, e_act->v2->co);
+ 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_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
+ BM_vert_select_set(bm, v_new, true);
+ BM_select_history_store(bm, v_new);
+ }
+ else {
+ BMVert *v_tri[3];
+ v_tri[0] = e_act->v1;
+ v_tri[1] = e_act->v2;
+ v_tri[2] = BM_vert_create(bm, center, NULL, BM_CREATE_NOP);
+ if (e_act->l && e_act->l->v == v_tri[0]) {
+ SWAP(BMVert *, v_tri[0], v_tri[1]);
+ }
+ BM_face_create_verts(bm, v_tri, 3, f_reference, BM_CREATE_NOP, true);
+ edbm_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
+ BM_vert_select_set(bm, v_tri[2], true);
+ BM_select_history_store(bm, v_tri[2]);
}
- // BMFace *f_new =
- BM_face_create_verts(bm, v_tri, 3, f_reference, BM_CREATE_NOP, true);
-
- edbm_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
- BM_vert_select_set(bm, v_tri[2], true);
- BM_select_history_store(bm, v_tri[2]);
changed = true;
}
else if (ele_act->head.htype == BM_VERT) {
@@ -281,6 +424,11 @@ void MESH_OT_polybuild_face_at_cursor(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ RNA_def_boolean(ot->srna,
+ "create_quads",
+ true,
+ "Create quads",
+ "Automatically split edges in triangles to maintain quad topology");
/* to give to transform */
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY);
}
diff --git a/source/blender/editors/mesh/editmesh_preselect_elem.c b/source/blender/editors/mesh/editmesh_preselect_elem.c
index a3e684a5493..05c4da68355 100644
--- a/source/blender/editors/mesh/editmesh_preselect_elem.c
+++ b/source/blender/editors/mesh/editmesh_preselect_elem.c
@@ -75,20 +75,49 @@ struct EditMesh_PreSelElem {
float (*verts)[3];
int verts_len;
+
+ float (*preview_tris)[3][3];
+ int preview_tris_len;
+ float (*preview_lines)[2][3];
+ int preview_lines_len;
+
+ eEditMesh_PreSelPreviewAction preview_action;
};
+void EDBM_preselect_action_set(struct EditMesh_PreSelElem *psel,
+ eEditMesh_PreSelPreviewAction action)
+{
+ psel->preview_action = action;
+}
+
+eEditMesh_PreSelPreviewAction EDBM_preselect_action_get(struct EditMesh_PreSelElem *psel)
+{
+ return psel->preview_action;
+}
+
struct EditMesh_PreSelElem *EDBM_preselect_elem_create(void)
{
struct EditMesh_PreSelElem *psel = MEM_callocN(sizeof(*psel), __func__);
+ psel->preview_action = PRESELECT_ACTION_TRANSFORM;
return psel;
}
void EDBM_preselect_elem_destroy(struct EditMesh_PreSelElem *psel)
{
EDBM_preselect_elem_clear(psel);
+ EDBM_preselect_preview_clear(psel);
MEM_freeN(psel);
}
+void EDBM_preselect_preview_clear(struct EditMesh_PreSelElem *psel)
+{
+ MEM_SAFE_FREE(psel->preview_tris);
+ psel->preview_tris_len = 0;
+
+ MEM_SAFE_FREE(psel->preview_lines);
+ psel->preview_lines_len = 0;
+}
+
void EDBM_preselect_elem_clear(struct EditMesh_PreSelElem *psel)
{
MEM_SAFE_FREE(psel->edges);
@@ -112,9 +141,42 @@ void EDBM_preselect_elem_draw(struct EditMesh_PreSelElem *psel, const float matr
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);
+
+ immUniformColor4ub(141, 171, 186, 100);
+ if (psel->preview_action != PRESELECT_ACTION_TRANSFORM) {
+ if (psel->preview_tris_len > 0) {
+ immBegin(GPU_PRIM_TRIS, psel->preview_tris_len * 3);
+
+ for (int i = 0; i < psel->preview_tris_len; i++) {
+ immVertex3fv(pos, psel->preview_tris[i][0]);
+ immVertex3fv(pos, psel->preview_tris[i][1]);
+ immVertex3fv(pos, psel->preview_tris[i][2]);
+ }
+ immEnd();
+ }
+
+ if (psel->preview_lines_len > 0) {
+
+ immUniformColor4ub(3, 161, 252, 200);
+ GPU_line_width(2.0f);
+ immBegin(GPU_PRIM_LINES, psel->preview_lines_len * 2);
+ for (int i = 0; i < psel->preview_lines_len; i++) {
+ immVertex3fv(pos, psel->preview_lines[i][0]);
+ immVertex3fv(pos, psel->preview_lines[i][1]);
+ }
+ immEnd();
+ }
+ }
+
+ if (psel->preview_action == PRESELECT_ACTION_DELETE) {
+ immUniformColor4ub(252, 49, 10, 200);
+ }
+ else {
+ immUniformColor4ub(3, 161, 252, 200);
+ }
if (psel->edges_len > 0) {
+ GPU_line_width(3.0f);
immBegin(GPU_PRIM_LINES, psel->edges_len * 2);
for (int i = 0; i < psel->edges_len; i++) {
@@ -126,7 +188,7 @@ void EDBM_preselect_elem_draw(struct EditMesh_PreSelElem *psel, const float matr
}
if (psel->verts_len > 0) {
- GPU_point_size(3.0f);
+ GPU_point_size(4.0f);
immBegin(GPU_PRIM_POINTS, psel->verts_len);
@@ -167,6 +229,122 @@ static void view3d_preselect_mesh_elem_update_from_edge(struct EditMesh_PreSelEl
psel->edges_len = 1;
}
+static void view3d_preselect_update_preview_triangle_from_vert(struct EditMesh_PreSelElem *psel,
+ ViewContext *vc,
+ BMesh *UNUSED(bm),
+ BMVert *eed,
+ const int mval[2])
+{
+ BMVert *v_act = eed;
+ BMEdge *e_pair[2] = {NULL};
+ float center[3];
+
+ if (v_act->e != NULL) {
+ for (uint allow_wire = 0; allow_wire < 2 && (e_pair[1] == NULL); allow_wire++) {
+ int i = 0;
+ BMEdge *e_iter = v_act->e;
+ do {
+ if ((BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == false) &&
+ (allow_wire ? BM_edge_is_wire(e_iter) : BM_edge_is_boundary(e_iter))) {
+ if (i == 2) {
+ e_pair[0] = e_pair[1] = NULL;
+ break;
+ }
+ e_pair[i++] = e_iter;
+ }
+ } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v_act)) != v_act->e);
+ }
+ }
+
+ if (e_pair[1] != NULL) {
+ mul_v3_m4v3(center, vc->obedit->obmat, v_act->co);
+ ED_view3d_win_to_3d_int(vc->v3d, vc->ar, center, mval, center);
+ mul_m4_v3(vc->obedit->imat, center);
+
+ psel->preview_tris = MEM_mallocN(sizeof(*psel->preview_tris) * 2, __func__);
+ psel->preview_lines = MEM_mallocN(sizeof(*psel->preview_lines) * 4, __func__);
+
+ copy_v3_v3(psel->preview_tris[0][0], e_pair[0]->v1->co);
+ copy_v3_v3(psel->preview_tris[0][1], e_pair[0]->v2->co);
+ copy_v3_v3(psel->preview_tris[0][2], center);
+
+ copy_v3_v3(psel->preview_tris[1][0], e_pair[1]->v1->co);
+ copy_v3_v3(psel->preview_tris[1][1], e_pair[1]->v2->co);
+ copy_v3_v3(psel->preview_tris[1][2], center);
+
+ copy_v3_v3(psel->preview_lines[0][0], e_pair[0]->v1->co);
+ copy_v3_v3(psel->preview_lines[0][1], e_pair[0]->v2->co);
+
+ copy_v3_v3(psel->preview_lines[1][0], e_pair[1]->v1->co);
+ copy_v3_v3(psel->preview_lines[1][1], e_pair[1]->v2->co);
+
+ copy_v3_v3(psel->preview_lines[2][0], center);
+ if (e_pair[0]->v1 == v_act) {
+ copy_v3_v3(psel->preview_lines[2][1], e_pair[0]->v2->co);
+ }
+ else {
+ copy_v3_v3(psel->preview_lines[2][1], e_pair[0]->v1->co);
+ }
+
+ copy_v3_v3(psel->preview_lines[3][0], center);
+ if (e_pair[1]->v1 == v_act) {
+ copy_v3_v3(psel->preview_lines[3][1], e_pair[1]->v2->co);
+ }
+ else {
+ copy_v3_v3(psel->preview_lines[3][1], e_pair[1]->v1->co);
+ }
+ psel->preview_tris_len = 2;
+ psel->preview_lines_len = 4;
+ }
+}
+
+static void view3d_preselect_update_preview_triangle_from_face(struct EditMesh_PreSelElem *psel,
+ ViewContext *UNUSED(vc),
+ BMesh *UNUSED(bm),
+ BMFace *efa,
+ const int UNUSED(mval[2]))
+{
+ float(*preview_lines)[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, preview_lines[i++], NULL);
+ } while ((l_iter = l_iter->next) != l_first);
+ psel->preview_lines = preview_lines;
+ psel->preview_lines_len = efa->len;
+}
+
+static void view3d_preselect_update_preview_triangle_from_edge(struct EditMesh_PreSelElem *psel,
+ ViewContext *vc,
+ BMesh *UNUSED(bm),
+ BMEdge *eed,
+ const int mval[2])
+{
+ float center[3];
+ psel->preview_tris = MEM_mallocN(sizeof(*psel->preview_tris), __func__);
+ psel->preview_lines = MEM_mallocN(sizeof(*psel->preview_lines) * 3, __func__);
+ mid_v3_v3v3(center, eed->v1->co, eed->v2->co);
+ mul_m4_v3(vc->obedit->obmat, center);
+ ED_view3d_win_to_3d_int(vc->v3d, vc->ar, center, mval, center);
+ mul_m4_v3(vc->obedit->imat, center);
+
+ copy_v3_v3(psel->preview_tris[0][0], eed->v1->co);
+ copy_v3_v3(psel->preview_tris[0][1], eed->v2->co);
+ copy_v3_v3(psel->preview_tris[0][2], center);
+
+ copy_v3_v3(psel->preview_lines[0][0], eed->v1->co);
+ copy_v3_v3(psel->preview_lines[0][1], eed->v2->co);
+
+ copy_v3_v3(psel->preview_lines[1][0], eed->v2->co);
+ copy_v3_v3(psel->preview_lines[1][1], center);
+
+ copy_v3_v3(psel->preview_lines[2][0], center);
+ copy_v3_v3(psel->preview_lines[2][1], eed->v1->co);
+ psel->preview_tris_len = 1;
+ psel->preview_lines_len = 3;
+}
+
static void view3d_preselect_mesh_elem_update_from_face(struct EditMesh_PreSelElem *psel,
BMesh *UNUSED(bm),
BMFace *efa,
@@ -209,4 +387,28 @@ void EDBM_preselect_elem_update_from_single(struct EditMesh_PreSelElem *psel,
}
}
+void EDBM_preselect_elem_update_preview(struct EditMesh_PreSelElem *psel,
+ struct ViewContext *vc,
+ struct BMesh *bm,
+ struct BMElem *ele,
+ const int mval[2])
+{
+ EDBM_preselect_preview_clear(psel);
+
+ switch (ele->head.htype) {
+ case BM_VERT:
+ if (EDBM_preselect_action_get(psel) == PRESELECT_ACTION_CREATE) {
+ view3d_preselect_update_preview_triangle_from_vert(psel, vc, bm, (BMVert *)ele, mval);
+ }
+ break;
+ case BM_EDGE:
+ view3d_preselect_update_preview_triangle_from_edge(psel, vc, bm, (BMEdge *)ele, mval);
+ break;
+ case BM_FACE:
+ view3d_preselect_update_preview_triangle_from_face(psel, vc, bm, (BMFace *)ele, mval);
+ break;
+ default:
+ BLI_assert(0);
+ }
+}
/** \} */
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index f1055103d16..4d511d45642 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -1448,8 +1448,11 @@ bool EDBM_unified_findnearest(ViewContext *vc,
bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
Base **bases,
const uint bases_len,
- bool use_boundary,
- int *r_base_index,
+ bool use_boundary_vertices,
+ bool use_boundary_edges,
+ int *r_base_index_vert,
+ int *r_base_index_edge,
+ int *r_base_index_face,
struct BMVert **r_eve,
struct BMEdge **r_eed,
struct BMFace **r_efa)
@@ -1463,9 +1466,27 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
BMElem *ele;
} best = {0, NULL};
+ struct {
+ uint base_index;
+ BMElem *ele;
+ } best_vert = {0, NULL};
+
+ struct {
+ uint base_index;
+ BMElem *ele;
+ } best_edge = {0, NULL};
+
+ struct {
+ uint base_index;
+ BMElem *ele;
+ } best_face = {0, NULL};
+
if (ED_view3d_win_to_ray_clipped(
vc->depsgraph, vc->ar, vc->v3d, mval_fl, ray_origin, ray_direction, true)) {
float dist_sq_best = FLT_MAX;
+ float dist_sq_best_vert = FLT_MAX;
+ float dist_sq_best_edge = FLT_MAX;
+ float dist_sq_best_face = FLT_MAX;
const bool use_vert = (r_eve != NULL);
const bool use_edge = (r_eed != NULL);
@@ -1495,18 +1516,23 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
BM_mesh_elem_index_ensure(bm, BM_VERT);
}
- if (use_boundary && (use_vert || use_edge)) {
+ if ((use_boundary_vertices || use_boundary_edges) && (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))) {
- if (use_vert) {
+ if (use_vert && use_boundary_vertices) {
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_normalized(
ray_origin, ray_direction, point);
+ if (dist_sq_test < dist_sq_best_vert) {
+ dist_sq_best_vert = dist_sq_test;
+ best_vert.base_index = base_index;
+ best_vert.ele = (BMElem *)v;
+ }
if (dist_sq_test < dist_sq_best) {
dist_sq_best = dist_sq_test;
best.base_index = base_index;
@@ -1515,7 +1541,7 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
}
}
- if (use_edge) {
+ if (use_edge && use_boundary_edges) {
float point[3];
#if 0
const float dist_sq_test = dist_squared_ray_to_seg_v3(
@@ -1531,6 +1557,11 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
mul_m4_v3(obedit->obmat, point);
const float dist_sq_test = dist_squared_to_ray_v3_normalized(
ray_origin, ray_direction, point);
+ if (dist_sq_test < dist_sq_best_edge) {
+ dist_sq_best_edge = dist_sq_test;
+ best_edge.base_index = base_index;
+ best_edge.ele = (BMElem *)e;
+ }
if (dist_sq_test < dist_sq_best) {
dist_sq_best = dist_sq_test;
best.base_index = base_index;
@@ -1541,46 +1572,55 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
}
}
}
- 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);
- const float dist_sq_test = dist_squared_to_ray_v3_normalized(
- ray_origin, ray_direction, v->co);
- if (dist_sq_test < dist_sq_best) {
- dist_sq_best = dist_sq_test;
- best.base_index = base_index;
- best.ele = (BMElem *)v;
- }
+ /* Non boundary case. */
+ if (use_vert && !use_boundary_vertices) {
+ 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, coords ? coords[BM_elem_index_get(v)] : v->co);
+ const float dist_sq_test = dist_squared_to_ray_v3_normalized(
+ ray_origin, ray_direction, point);
+ if (dist_sq_test < dist_sq_best_vert) {
+ dist_sq_best_vert = dist_sq_test;
+ best_vert.base_index = base_index;
+ best_vert.ele = (BMElem *)v;
+ }
+ if (dist_sq_test < dist_sq_best) {
+ dist_sq_best = dist_sq_test;
+ best.base_index = base_index;
+ 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);
- const float dist_sq_test = dist_squared_to_ray_v3_normalized(
- ray_origin, ray_direction, point);
- if (dist_sq_test < dist_sq_best) {
- dist_sq_best = dist_sq_test;
- best.base_index = base_index;
- best.ele = (BMElem *)e;
- }
+ }
+
+ if (use_edge && !use_boundary_edges) {
+ 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);
+ const float dist_sq_test = dist_squared_to_ray_v3_normalized(
+ ray_origin, ray_direction, point);
+ if (dist_sq_test < dist_sq_best_edge) {
+ dist_sq_best_edge = dist_sq_test;
+ best_edge.base_index = base_index;
+ best_edge.ele = (BMElem *)e;
+ }
+ if (dist_sq_test < dist_sq_best) {
+ dist_sq_best = dist_sq_test;
+ best.base_index = base_index;
+ best.ele = (BMElem *)e;
}
}
}
@@ -1601,6 +1641,11 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
mul_m4_v3(obedit->obmat, point);
const float dist_sq_test = dist_squared_to_ray_v3_normalized(
ray_origin, ray_direction, point);
+ if (dist_sq_test < dist_sq_best_face) {
+ dist_sq_best_face = dist_sq_test;
+ best_face.base_index = base_index;
+ best_face.ele = (BMElem *)f;
+ }
if (dist_sq_test < dist_sq_best) {
dist_sq_best = dist_sq_test;
best.base_index = base_index;
@@ -1612,7 +1657,10 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
}
}
- *r_base_index = best.base_index;
+ *r_base_index_vert = best_vert.base_index;
+ *r_base_index_edge = best_edge.base_index;
+ *r_base_index_face = best_face.base_index;
+
if (r_eve) {
*r_eve = NULL;
}
@@ -1623,22 +1671,17 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc,
*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);
- }
+ if (best_vert.ele) {
+ *r_eve = (BMVert *)best_vert.ele;
+ }
+ if (best_edge.ele) {
+ *r_eed = (BMEdge *)best_edge.ele;
}
- return (best.ele != NULL);
+ if (best_face.ele) {
+ *r_efa = (BMFace *)best_face.ele;
+ }
+
+ return (best_vert.ele != NULL || best_edge.ele != NULL || best_face.ele != NULL);
}
/** \} */
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 1a03879ed17..8332cb71f95 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -122,6 +122,8 @@ void MESH_GGT_spin_redo(struct wmGizmoGroupType *gzgt);
void MESH_OT_polybuild_face_at_cursor(struct wmOperatorType *ot);
void MESH_OT_polybuild_split_at_cursor(struct wmOperatorType *ot);
void MESH_OT_polybuild_dissolve_at_cursor(struct wmOperatorType *ot);
+void MESH_OT_polybuild_transform_at_cursor(struct wmOperatorType *ot);
+void MESH_OT_polybuild_delete_at_cursor(struct wmOperatorType *ot);
/* *** editmesh_inset.c *** */
void MESH_OT_inset(struct wmOperatorType *ot);
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index 102ce3efc22..28c55afbf2e 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -148,6 +148,8 @@ 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_transform_at_cursor);
+ WM_operatortype_append(MESH_OT_polybuild_delete_at_cursor);
WM_operatortype_append(MESH_OT_uv_texture_add);
WM_operatortype_append(MESH_OT_uv_texture_remove);
@@ -334,6 +336,25 @@ void ED_operatormacros_mesh(void)
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
RNA_boolean_set(otmacro->ptr, "mirror", false);
+
+ ot = WM_operatortype_append_macro("MESH_OT_polybuild_transform_at_cursor_move",
+ "Transform at Cursor Move",
+ "",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ WM_operatortype_macro_define(ot, "MESH_OT_polybuild_transform_at_cursor");
+ otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+ RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
+ RNA_boolean_set(otmacro->ptr, "mirror", false);
+
+ ot = WM_operatortype_append_macro("MESH_OT_polybuild_extrude_at_cursor_move",
+ "Extrude at Cursor Move",
+ "",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ WM_operatortype_macro_define(ot, "MESH_OT_polybuild_transform_at_cursor");
+ otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_edges_indiv");
+ otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+ RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
+ RNA_boolean_set(otmacro->ptr, "mirror", false);
}
/* note mesh keymap also for other space? */
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c
index a984e339305..bfc5956bb94 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c
@@ -77,7 +77,20 @@ static void gizmo_preselect_elem_draw(const bContext *UNUSED(C), wmGizmo *gz)
static int gizmo_preselect_elem_test_select(bContext *C, wmGizmo *gz, const int mval[2])
{
+ wmEvent *event = CTX_wm_window(C)->eventstate;
MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz;
+
+ /* Hack: Switch action mode based on key input */
+ const bool is_ctrl_pressed = WM_event_modifier_flag(event) & KM_CTRL;
+ const bool is_shift_pressed = WM_event_modifier_flag(event) & KM_SHIFT;
+ EDBM_preselect_action_set(gz_ele->psel, PRESELECT_ACTION_TRANSFORM);
+ if (is_ctrl_pressed && !is_shift_pressed) {
+ EDBM_preselect_action_set(gz_ele->psel, PRESELECT_ACTION_CREATE);
+ }
+ if (!is_ctrl_pressed && is_shift_pressed) {
+ EDBM_preselect_action_set(gz_ele->psel, PRESELECT_ACTION_DELETE);
+ }
+
struct {
Object *ob;
BMElem *ele;
@@ -87,18 +100,6 @@ static int gizmo_preselect_elem_test_select(bContext *C, wmGizmo *gz, const int
.dist = ED_view3d_select_dist_px(),
};
- struct {
- int base_index;
- int vert_index;
- int edge_index;
- int face_index;
- } prev = {
- .base_index = gz_ele->base_index,
- .vert_index = gz_ele->vert_index,
- .edge_index = gz_ele->edge_index,
- .face_index = gz_ele->face_index,
- };
-
{
ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = CTX_wm_view3d(C);
@@ -115,32 +116,66 @@ static int gizmo_preselect_elem_test_select(bContext *C, wmGizmo *gz, const int
{
/* TODO: support faces. */
- int base_index = -1;
+ int base_index_vert = -1;
+ int base_index_edge = -1;
+ int base_index_face = -1;
BMVert *eve_test;
BMEdge *eed_test;
+ BMFace *efa_test;
if (EDBM_unified_findnearest_from_raycast(&vc,
gz_ele->bases,
gz_ele->bases_len,
+ false,
true,
- &base_index,
+ &base_index_vert,
+ &base_index_edge,
+ &base_index_face,
&eve_test,
&eed_test,
- NULL)) {
- Base *base = gz_ele->bases[base_index];
- best.ob = base->object;
- if (eve_test) {
- best.ele = (BMElem *)eve_test;
- }
- else if (eed_test) {
- best.ele = (BMElem *)eed_test;
+ &efa_test)) {
+ if (EDBM_preselect_action_get(gz_ele->psel) == PRESELECT_ACTION_DELETE) {
+ /* Delete action */
+ if (efa_test) {
+ best.ele = (BMElem *)efa_test;
+ best.base_index = base_index_face;
+ }
}
+
else {
- BLI_assert(0);
+ /* Transform and create action */
+ if (eed_test) {
+ best.ele = (BMElem *)eed_test;
+ best.base_index = base_index_edge;
+ }
+ }
+
+ /* All actions use same vertex preselection */
+ /* Retopology should always prioritize edge preselection. Only preselct a vertex when the
+ * cursor is really close to it*/
+ if (eve_test) {
+ BMVert *vert = (BMVert *)eve_test;
+ float vert_p_co[3], vert_co[3];
+ float mval_f[2] = {UNPACK2(vc.mval)};
+ mul_v3_m4v3(vert_co, gz_ele->bases[base_index_vert]->object->obmat, vert->co);
+ ED_view3d_project(vc.ar, vert_co, vert_p_co);
+ float len = len_v2v2(vert_p_co, mval_f);
+ if (len < 35) {
+ best.ele = (BMElem *)eve_test;
+ best.base_index = base_index_vert;
+ }
+ if (!BM_vert_is_boundary(vert) &&
+ EDBM_preselect_action_get(gz_ele->psel) != PRESELECT_ACTION_DELETE) {
+ best.ele = (BMElem *)eve_test;
+ best.base_index = base_index_vert;
+ }
}
- best.base_index = base_index;
+
/* Check above should never fail, if it does it's an internal error. */
BLI_assert(best.base_index != -1);
+
+ Base *base = gz_ele->bases[best.base_index];
+ best.ob = base->object;
}
}
@@ -167,32 +202,30 @@ static int gizmo_preselect_elem_test_select(bContext *C, wmGizmo *gz, const int
}
}
- if ((prev.base_index == gz_ele->base_index) && (prev.vert_index == gz_ele->vert_index) &&
- (prev.edge_index == gz_ele->edge_index) && (prev.face_index == gz_ele->face_index)) {
- /* pass (only recalculate on change) */
- }
- else {
- if (best.ele) {
- const float(*coords)[3] = NULL;
- {
- Object *ob = gz_ele->bases[gz_ele->base_index]->object;
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(depsgraph, ob->data);
- if (me_eval->runtime.edit_data) {
- coords = me_eval->runtime.edit_data->vertexCos;
- }
+ if (best.ele) {
+ const float(*coords)[3] = NULL;
+ {
+ Object *ob = gz_ele->bases[gz_ele->base_index]->object;
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(depsgraph, ob->data);
+ if (me_eval->runtime.edit_data) {
+ coords = me_eval->runtime.edit_data->vertexCos;
}
- EDBM_preselect_elem_update_from_single(gz_ele->psel, bm, best.ele, coords);
- }
- else {
- EDBM_preselect_elem_clear(gz_ele->psel);
}
+ EDBM_preselect_elem_update_from_single(gz_ele->psel, bm, best.ele, coords);
+ EDBM_preselect_elem_update_preview(gz_ele->psel, &vc, bm, best.ele, mval);
+ }
+ else {
+ EDBM_preselect_elem_clear(gz_ele->psel);
+ EDBM_preselect_preview_clear(gz_ele->psel);
+ }
- RNA_int_set(gz->ptr, "object_index", gz_ele->base_index);
- RNA_int_set(gz->ptr, "vert_index", gz_ele->vert_index);
- RNA_int_set(gz->ptr, "edge_index", gz_ele->edge_index);
- RNA_int_set(gz->ptr, "face_index", gz_ele->face_index);
+ RNA_int_set(gz->ptr, "object_index", gz_ele->base_index);
+ RNA_int_set(gz->ptr, "vert_index", gz_ele->vert_index);
+ RNA_int_set(gz->ptr, "edge_index", gz_ele->edge_index);
+ RNA_int_set(gz->ptr, "face_index", gz_ele->face_index);
+ if (best.ele) {
ARegion *ar = CTX_wm_region(C);
ED_region_tag_redraw(ar);
}
@@ -471,5 +504,4 @@ void ED_view3d_gizmo_mesh_preselect_get_active(bContext *C,
}
}
}
-
/** \} */