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.
This commit is contained in:
@@ -572,7 +572,7 @@ class _defs_edit_mesh:
|
||||
return dict(
|
||||
text="Poly Build",
|
||||
icon="ops.mesh.polybuild_hover",
|
||||
widget=None,
|
||||
widget="VIEW3D_GGT_mesh_preselect_elem",
|
||||
keymap=(
|
||||
("mesh.polybuild_face_at_cursor_move",
|
||||
dict(TRANSFORM_OT_translate=dict(release_confirm=True)),
|
||||
@@ -581,8 +581,6 @@ class _defs_edit_mesh:
|
||||
dict(TRANSFORM_OT_translate=dict(release_confirm=True)),
|
||||
dict(type='ACTIONMOUSE', value='PRESS', ctrl=True)),
|
||||
("mesh.polybuild_dissolve_at_cursor", dict(), dict(type='ACTIONMOUSE', value='CLICK', alt=True)),
|
||||
("mesh.polybuild_hover", dict(use_boundary=False), dict(type='MOUSEMOVE', value='ANY', alt=True)),
|
||||
("mesh.polybuild_hover", dict(use_boundary=True), dict(type='MOUSEMOVE', value='ANY', any=True)),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ struct Mesh;
|
||||
struct UvVertMap;
|
||||
struct UvMapVert;
|
||||
struct BMEditMesh;
|
||||
struct BMElem;
|
||||
struct BMesh;
|
||||
struct BMVert;
|
||||
struct BMLoop;
|
||||
@@ -177,6 +178,14 @@ bool EDBM_unified_findnearest(
|
||||
struct BMEdge **r_eed,
|
||||
struct BMFace **r_efa);
|
||||
|
||||
bool EDBM_unified_findnearest_from_raycast(
|
||||
struct ViewContext *vc,
|
||||
bool use_boundary,
|
||||
struct Base **r_base,
|
||||
struct BMVert **r_eve,
|
||||
struct BMEdge **r_eed,
|
||||
struct BMFace **r_efa);
|
||||
|
||||
bool EDBM_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
|
||||
|
||||
void EDBM_selectmode_set(struct BMEditMesh *em);
|
||||
@@ -210,6 +219,16 @@ void EDBM_preselect_edgering_update_from_edge(
|
||||
struct EditMesh_PreSelEdgeRing *psel,
|
||||
struct BMesh *bm, struct BMEdge *eed_start, int previewlines, const float (*coords)[3]);
|
||||
|
||||
/* editmesh_preselect_elem.c */
|
||||
struct EditMesh_PreSelElem;
|
||||
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_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]);
|
||||
|
||||
/* mesh_ops.c */
|
||||
void ED_operatortypes_mesh(void);
|
||||
void ED_operatormacros_mesh(void);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
218
source/blender/editors/mesh/editmesh_preselect_elem.c
Normal file
218
source/blender/editors/mesh/editmesh_preselect_elem.c
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -1097,6 +1097,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
|
||||
* \{ */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -702,6 +702,7 @@ static void view3d_widgets(void)
|
||||
|
||||
WM_gizmogrouptype_append(TRANSFORM_GGT_gizmo);
|
||||
WM_gizmogrouptype_append(VIEW3D_GGT_xform_cage);
|
||||
WM_gizmogrouptype_append(VIEW3D_GGT_mesh_preselect_elem);
|
||||
WM_gizmogrouptype_append(VIEW3D_GGT_mesh_preselect_edgering);
|
||||
|
||||
WM_gizmogrouptype_append(VIEW3D_GGT_ruler);
|
||||
|
||||
@@ -40,6 +40,54 @@
|
||||
|
||||
#include "view3d_intern.h" /* own include */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Mesh Pre-Select Element Gizmo
|
||||
*
|
||||
* \{ */
|
||||
|
||||
struct GizmoGroupPreSelElem {
|
||||
wmGizmo *gizmo;
|
||||
};
|
||||
|
||||
static bool WIDGETGROUP_mesh_preselect_elem_poll(const bContext *C, wmGizmoGroupType *gzgt)
|
||||
{
|
||||
bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C);
|
||||
if ((tref_rt == NULL) ||
|
||||
!STREQ(gzgt->idname, tref_rt->gizmo_group))
|
||||
{
|
||||
WM_gizmo_group_type_unlink_delayed_ptr(gzgt);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void WIDGETGROUP_mesh_preselect_elem_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
|
||||
{
|
||||
const wmGizmoType *gzt_presel = WM_gizmotype_find("GIZMO_GT_preselect_elem_3d", true);
|
||||
struct GizmoGroupPreSelElem *man = MEM_callocN(sizeof(struct GizmoGroupPreSelElem), __func__);
|
||||
gzgroup->customdata = man;
|
||||
|
||||
wmGizmo *gz = man->gizmo = WM_gizmo_new_ptr(gzt_presel, gzgroup, NULL);
|
||||
UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
|
||||
UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi);
|
||||
}
|
||||
|
||||
void VIEW3D_GGT_mesh_preselect_elem(wmGizmoGroupType *gzgt)
|
||||
{
|
||||
gzgt->name = "Mesh Preselect Element";
|
||||
gzgt->idname = "VIEW3D_GGT_mesh_preselect_elem";
|
||||
|
||||
gzgt->flag = WM_GIZMOGROUPTYPE_3D;
|
||||
|
||||
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
|
||||
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
|
||||
|
||||
gzgt->poll = WIDGETGROUP_mesh_preselect_elem_poll;
|
||||
gzgt->setup = WIDGETGROUP_mesh_preselect_elem_setup;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Mesh Pre-Select Edge Ring Gizmo
|
||||
*
|
||||
|
||||
@@ -54,6 +54,207 @@
|
||||
#include "ED_view3d.h"
|
||||
#include "ED_gizmo_library.h"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Mesh Element (Vert/Edge/Face) Pre-Select Gizmo API
|
||||
*
|
||||
* \{ */
|
||||
|
||||
|
||||
typedef struct MeshElemGizmo3D {
|
||||
wmGizmo gizmo;
|
||||
Object **objects;
|
||||
uint objects_len;
|
||||
int object_index;
|
||||
int vert_index;
|
||||
int edge_index;
|
||||
int face_index;
|
||||
struct EditMesh_PreSelElem *psel;
|
||||
} MeshElemGizmo3D;
|
||||
|
||||
static void gizmo_preselect_elem_draw(const bContext *UNUSED(C), wmGizmo *gz)
|
||||
{
|
||||
MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz;
|
||||
if (gz_ele->object_index != -1) {
|
||||
Object *ob = gz_ele->objects[gz_ele->object_index];
|
||||
EDBM_preselect_elem_draw(gz_ele->psel, ob->obmat);
|
||||
}
|
||||
}
|
||||
|
||||
static int gizmo_preselect_elem_test_select(
|
||||
bContext *C, wmGizmo *gz, const int mval[2])
|
||||
{
|
||||
MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz;
|
||||
struct {
|
||||
Object *ob;
|
||||
BMElem *ele;
|
||||
float dist;
|
||||
int ob_index;
|
||||
} best = {
|
||||
.dist = ED_view3d_select_dist_px(),
|
||||
};
|
||||
|
||||
struct {
|
||||
int object_index;
|
||||
int vert_index;
|
||||
int edge_index;
|
||||
int face_index;
|
||||
} prev = {
|
||||
.object_index = gz_ele->object_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);
|
||||
if (((gz_ele->objects)) == NULL ||
|
||||
(gz_ele->objects[0] != OBEDIT_FROM_VIEW_LAYER(view_layer)))
|
||||
{
|
||||
gz_ele->objects = BKE_view_layer_array_from_objects_in_edit_mode(
|
||||
view_layer, &gz_ele->objects_len);
|
||||
}
|
||||
}
|
||||
|
||||
ViewContext vc;
|
||||
em_setup_viewcontext(C, &vc);
|
||||
copy_v2_v2_int(vc.mval, mval);
|
||||
|
||||
{
|
||||
/* TODO: support faces. */
|
||||
Base *base = NULL;
|
||||
BMVert *eve_test;
|
||||
BMEdge *eed_test;
|
||||
|
||||
if (EDBM_unified_findnearest_from_raycast(&vc, true, &base, &eve_test, &eed_test, NULL)) {
|
||||
best.ob = base->object;
|
||||
if (eve_test) {
|
||||
best.ele = (BMElem *)eve_test;
|
||||
}
|
||||
else if (eed_test) {
|
||||
best.ele = (BMElem *)eed_test;
|
||||
}
|
||||
else {
|
||||
BLI_assert(0);
|
||||
}
|
||||
best.ob_index = -1;
|
||||
/* weak, we could ensure the arrays are aligned,
|
||||
* or allow EDBM_unified_findnearest_from_raycast to take an array arg. */
|
||||
for (int ob_index = 0; ob_index < gz_ele->objects_len; ob_index++) {
|
||||
if (best.ob == gz_ele->objects[ob_index]) {
|
||||
best.ob_index = ob_index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Check above should never fail, if it does it's an internal error. */
|
||||
BLI_assert(best.ob_index != -1);
|
||||
}
|
||||
}
|
||||
|
||||
BMesh *bm = NULL;
|
||||
|
||||
gz_ele->object_index = -1;
|
||||
gz_ele->vert_index = -1;
|
||||
gz_ele->edge_index = -1;
|
||||
gz_ele->face_index = -1;
|
||||
|
||||
if (best.ele) {
|
||||
gz_ele->object_index = best.ob_index;
|
||||
bm = BKE_editmesh_from_object(gz_ele->objects[gz_ele->object_index])->bm;
|
||||
BM_mesh_elem_index_ensure(bm, best.ele->head.htype);
|
||||
|
||||
if (best.ele->head.htype == BM_VERT) {
|
||||
gz_ele->vert_index = BM_elem_index_get(best.ele);
|
||||
}
|
||||
else if (best.ele->head.htype == BM_EDGE) {
|
||||
gz_ele->edge_index = BM_elem_index_get(best.ele);
|
||||
}
|
||||
else if (best.ele->head.htype == BM_FACE) {
|
||||
gz_ele->face_index = BM_elem_index_get(best.ele);
|
||||
}
|
||||
}
|
||||
|
||||
if ((prev.object_index == gz_ele->object_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->objects[gz_ele->object_index];
|
||||
Depsgraph *depsgraph = CTX_data_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);
|
||||
}
|
||||
|
||||
RNA_int_set(gz->ptr, "object_index", gz_ele->object_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);
|
||||
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
ED_region_tag_redraw(ar);
|
||||
}
|
||||
|
||||
// return best.eed ? 0 : -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void gizmo_preselect_elem_setup(wmGizmo *gz)
|
||||
{
|
||||
MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz;
|
||||
if (gz_ele->psel == NULL) {
|
||||
gz_ele->psel = EDBM_preselect_elem_create();
|
||||
}
|
||||
gz_ele->object_index = -1;
|
||||
}
|
||||
|
||||
static void gizmo_preselect_elem_free(wmGizmo *gz)
|
||||
{
|
||||
MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz;
|
||||
EDBM_preselect_elem_destroy(gz_ele->psel);
|
||||
gz_ele->psel = NULL;
|
||||
MEM_SAFE_FREE(gz_ele->objects);
|
||||
}
|
||||
|
||||
static int gizmo_preselect_elem_invoke(
|
||||
bContext *UNUSED(C), wmGizmo *UNUSED(gz), const wmEvent *UNUSED(event))
|
||||
{
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
static void GIZMO_GT_preselect_elem_3d(wmGizmoType *gzt)
|
||||
{
|
||||
/* identifiers */
|
||||
gzt->idname = "GIZMO_GT_preselect_elem_3d";
|
||||
|
||||
/* api callbacks */
|
||||
gzt->invoke = gizmo_preselect_elem_invoke;
|
||||
gzt->draw = gizmo_preselect_elem_draw;
|
||||
gzt->test_select = gizmo_preselect_elem_test_select;
|
||||
gzt->setup = gizmo_preselect_elem_setup;
|
||||
gzt->free = gizmo_preselect_elem_free;
|
||||
|
||||
gzt->struct_size = sizeof(MeshElemGizmo3D);
|
||||
|
||||
RNA_def_int(gzt->srna, "object_index", -1, -1, INT_MAX, "Object Index", "", -1, INT_MAX);
|
||||
RNA_def_int(gzt->srna, "vert_index", -1, -1, INT_MAX, "Vert Index", "", -1, INT_MAX);
|
||||
RNA_def_int(gzt->srna, "edge_index", -1, -1, INT_MAX, "Edge Index", "", -1, INT_MAX);
|
||||
RNA_def_int(gzt->srna, "face_index", -1, -1, INT_MAX, "Face Index", "", -1, INT_MAX);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Mesh Edge-Ring Pre-Select Gizmo API
|
||||
*
|
||||
@@ -98,10 +299,14 @@ static int gizmo_preselect_edgering_test_select(
|
||||
.edge_index = gz_ring->edge_index,
|
||||
};
|
||||
|
||||
if (gz_ring->objects == NULL) {
|
||||
{
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
gz_ring->objects = BKE_view_layer_array_from_objects_in_edit_mode(
|
||||
view_layer, &gz_ring->objects_len);
|
||||
if (((gz_ring->objects)) == NULL ||
|
||||
(gz_ring->objects[0] != OBEDIT_FROM_VIEW_LAYER(view_layer)))
|
||||
{
|
||||
gz_ring->objects = BKE_view_layer_array_from_objects_in_edit_mode(
|
||||
view_layer, &gz_ring->objects_len);
|
||||
}
|
||||
}
|
||||
|
||||
ViewContext vc;
|
||||
@@ -207,8 +412,17 @@ static void GIZMO_GT_preselect_edgering_3d(wmGizmoType *gzt)
|
||||
RNA_def_int(gzt->srna, "edge_index", -1, -1, INT_MAX, "Edge Index", "", -1, INT_MAX);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Gizmo API
|
||||
*
|
||||
* \{ */
|
||||
|
||||
void ED_gizmotypes_preselect_3d(void)
|
||||
{
|
||||
WM_gizmotype_append(GIZMO_GT_preselect_elem_3d);
|
||||
WM_gizmotype_append(GIZMO_GT_preselect_edgering_3d);
|
||||
}
|
||||
|
||||
|
||||
@@ -263,6 +263,7 @@ void VIEW3D_GGT_force_field(struct wmGizmoGroupType *gzgt);
|
||||
void VIEW3D_GGT_empty_image(struct wmGizmoGroupType *gzgt);
|
||||
void VIEW3D_GGT_armature_spline(struct wmGizmoGroupType *gzgt);
|
||||
void VIEW3D_GGT_navigate(struct wmGizmoGroupType *gzgt);
|
||||
void VIEW3D_GGT_mesh_preselect_elem(struct wmGizmoGroupType *gzgt);
|
||||
void VIEW3D_GGT_mesh_preselect_edgering(struct wmGizmoGroupType *gzgt);
|
||||
|
||||
void VIEW3D_GGT_ruler(struct wmGizmoGroupType *gzgt);
|
||||
|
||||
Reference in New Issue
Block a user