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
This commit is contained in:
2019-08-27 16:19:25 +02:00
parent 2a2fd75ef9
commit d8baafd693
9 changed files with 599 additions and 128 deletions

View File

@@ -5454,11 +5454,11 @@ def km_3d_view_tool_edit_mesh_poly_build(params):
"3D View Tool: Edit Mesh, Poly Build",
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
{"items": [
("mesh.polybuild_face_at_cursor_move", {"type": params.tool_mouse, "value": 'PRESS'},
("mesh.polybuild_extrude_at_cursor_move", {"type": params.tool_mouse, "value": 'PRESS'},
{"properties": [("TRANSFORM_OT_translate", [("release_confirm", True)])]}),
("mesh.polybuild_split_at_cursor_move", {"type": params.tool_mouse, "value": 'PRESS', "ctrl": True},
("mesh.polybuild_face_at_cursor_move", {"type": params.tool_mouse, "value": 'PRESS', "ctrl": True},
{"properties": [("TRANSFORM_OT_translate", [("release_confirm", True)])]}),
("mesh.polybuild_dissolve_at_cursor", {"type": params.tool_mouse, "value": 'CLICK', "alt": True}, None),
("mesh.polybuild_delete_at_cursor", {"type": params.tool_mouse, "value": 'CLICK', "shift": True}, None),
]},
)

View File

@@ -490,12 +490,17 @@ class _defs_edit_mesh:
@ToolDef.from_fn
def poly_build():
def draw_settings(context, layout, tool):
props = tool.operator_properties("mesh.polybuild_face_at_cursor_move")
props_macro = props.MESH_OT_polybuild_face_at_cursor
layout.prop(props_macro, "create_quads")
return dict(
idname="builtin.poly_build",
label="Poly Build",
icon="ops.mesh.polybuild_hover",
widget="VIEW3D_GGT_mesh_preselect_elem",
keymap=(),
draw_settings=draw_settings,
)
@ToolDef.from_fn

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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);
}
}
/** \} */

View File

@@ -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;
}
return (best.ele != NULL);
if (best_edge.ele) {
*r_eed = (BMEdge *)best_edge.ele;
}
if (best_face.ele) {
*r_efa = (BMFace *)best_face.ele;
}
return (best_vert.ele != NULL || best_edge.ele != NULL || best_face.ele != NULL);
}
/** \} */

View File

@@ -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);

View File

@@ -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? */

View File

@@ -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;
}
}
best.base_index = base_index;
/* 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;
}
}
/* 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) */
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);
EDBM_preselect_elem_update_preview(gz_ele->psel, &vc, bm, best.ele, mval);
}
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;
}
}
EDBM_preselect_elem_update_from_single(gz_ele->psel, bm, best.ele, coords);
}
else {
EDBM_preselect_elem_clear(gz_ele->psel);
}
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,
}
}
}
/** \} */