Animation: Weight Paint select more/less for vertices #105633
@ -4437,6 +4437,8 @@ def km_weight_paint_vertex_selection(params):
|
|||||||
{"properties": [("select", True)]}),
|
{"properties": [("select", True)]}),
|
||||||
("paint.vert_select_linked_pick", {"type": 'L', "value": 'PRESS', "shift": True},
|
("paint.vert_select_linked_pick", {"type": 'L', "value": 'PRESS', "shift": True},
|
||||||
{"properties": [("select", False)]}),
|
{"properties": [("select", False)]}),
|
||||||
|
("paint.vert_select_more", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True}, None),
|
||||||
|
("paint.vert_select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True}, None),
|
||||||
])
|
])
|
||||||
|
|
||||||
return keymap
|
return keymap
|
||||||
|
@ -2032,6 +2032,9 @@ class VIEW3D_MT_select_paint_mask_vertex(Menu):
|
|||||||
layout.operator("paint.vert_select_all", text="None").action = 'DESELECT'
|
layout.operator("paint.vert_select_all", text="None").action = 'DESELECT'
|
||||||
layout.operator("paint.vert_select_all", text="Invert").action = 'INVERT'
|
layout.operator("paint.vert_select_all", text="Invert").action = 'INVERT'
|
||||||
|
|
||||||
|
layout.operator("paint.vert_select_more"),
|
||||||
|
layout.operator("paint.vert_select_less"),
|
||||||
|
|
||||||
layout.separator()
|
layout.separator()
|
||||||
|
|
||||||
layout.operator("view3d.select_box")
|
layout.operator("view3d.select_box")
|
||||||
|
@ -444,6 +444,8 @@ void paintvert_select_linked_pick(struct bContext *C,
|
|||||||
struct Object *ob,
|
struct Object *ob,
|
||||||
const int region_coordinates[2],
|
const int region_coordinates[2],
|
||||||
bool select);
|
bool select);
|
||||||
|
void paintvert_select_more(struct Mesh *mesh, bool face_step);
|
||||||
|
void paintvert_select_less(struct Mesh *mesh, bool face_step);
|
||||||
void paintvert_hide(struct bContext *C, struct Object *ob, bool unselected);
|
void paintvert_hide(struct bContext *C, struct Object *ob, bool unselected);
|
||||||
void paintvert_reveal(struct bContext *C, struct Object *ob, bool select);
|
void paintvert_reveal(struct bContext *C, struct Object *ob, bool select);
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "BKE_customdata.h"
|
#include "BKE_customdata.h"
|
||||||
#include "BKE_global.h"
|
#include "BKE_global.h"
|
||||||
#include "BKE_mesh.hh"
|
#include "BKE_mesh.hh"
|
||||||
|
#include "BKE_mesh_mapping.h"
|
||||||
#include "BKE_object.h"
|
#include "BKE_object.h"
|
||||||
|
|
||||||
#include "ED_mesh.h"
|
#include "ED_mesh.h"
|
||||||
@ -660,6 +661,126 @@ void paintvert_select_linked(bContext *C, Object *ob)
|
|||||||
paintvert_select_linked_vertices(C, ob, indices, true);
|
paintvert_select_linked_vertices(C, ob, indices, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void paintvert_select_more(Mesh *mesh, const bool face_step)
|
||||||
|
{
|
||||||
|
using namespace blender;
|
||||||
|
|
||||||
|
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
|
||||||
|
bke::SpanAttributeWriter<bool> select_vert = attributes.lookup_or_add_for_write_span<bool>(
|
||||||
|
".select_vert", ATTR_DOMAIN_POINT);
|
||||||
|
const VArray<bool> hide_edge = attributes.lookup_or_default<bool>(
|
||||||
|
".hide_edge", ATTR_DOMAIN_EDGE, false);
|
||||||
|
const VArray<bool> hide_poly = attributes.lookup_or_default<bool>(
|
||||||
|
".hide_poly", ATTR_DOMAIN_FACE, false);
|
||||||
|
|
||||||
|
const Span<MPoly> polys = mesh->polys();
|
||||||
|
const Span<int> corner_edges = mesh->corner_edges();
|
||||||
|
const Span<int> corner_verts = mesh->corner_verts();
|
||||||
|
const Span<MEdge> edges = mesh->edges();
|
||||||
|
|
||||||
|
Array<Vector<int, 2>> edge_to_face_map;
|
||||||
|
if (face_step) {
|
||||||
|
edge_to_face_map = bke::mesh_topology::build_edge_to_poly_map(
|
||||||
|
polys, corner_edges, mesh->totedge);
|
||||||
|
}
|
||||||
|
|||||||
|
|
||||||
Hans Goudey
commented
The functionality is the same, but The functionality is the same, but `mesh_topology::build_edge_to_poly_map(..)` has an interface that's a bit more friendly in C++. Performance might be slightly worse currently, but there are plans to improve those functions in the near future.
|
|||||||
|
/* Need a copy of the selected verts that we can read from and is not modified. */
|
||||||
|
BitVector<> select_vert_original(mesh->totvert, false);
|
||||||
|
for (int i = 0; i < mesh->totvert; i++) {
|
||||||
|
select_vert_original[i].set(select_vert.span[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we iterated over polys we wouldn't extend the selection through edges that have no face
|
||||||
|
* attached to them. */
|
||||||
|
for (const int i : edges.index_range()) {
|
||||||
|
const MEdge &edge = edges[i];
|
||||||
|
if ((!select_vert_original[edge.v1] && !select_vert_original[edge.v2]) || hide_edge[i]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
select_vert.span[edge.v1] = true;
|
||||||
|
select_vert.span[edge.v2] = true;
|
||||||
|
if (!face_step) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const Span<int> neighbor_polys = edge_to_face_map[i];
|
||||||
|
for (const int poly_i : neighbor_polys) {
|
||||||
|
if (hide_poly[poly_i]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const MPoly &poly = polys[poly_i];
|
||||||
|
for (const int vert : corner_verts.slice(poly.loopstart, poly.totloop)) {
|
||||||
|
select_vert.span[vert] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
select_vert.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
void paintvert_select_less(Mesh *mesh, const bool face_step)
|
||||||
|
{
|
||||||
|
using namespace blender;
|
||||||
|
|
||||||
|
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
|
||||||
|
bke::SpanAttributeWriter<bool> select_vert = attributes.lookup_or_add_for_write_span<bool>(
|
||||||
|
".select_vert", ATTR_DOMAIN_POINT);
|
||||||
|
const VArray<bool> hide_edge = attributes.lookup_or_default<bool>(
|
||||||
|
".hide_edge", ATTR_DOMAIN_EDGE, false);
|
||||||
|
const VArray<bool> hide_poly = attributes.lookup_or_default<bool>(
|
||||||
|
".hide_poly", ATTR_DOMAIN_FACE, false);
|
||||||
|
|
||||||
|
const Span<MPoly> polys = mesh->polys();
|
||||||
|
const Span<int> corner_edges = mesh->corner_edges();
|
||||||
|
const Span<int> corner_verts = mesh->corner_verts();
|
||||||
|
const Span<MEdge> edges = mesh->edges();
|
||||||
|
|
||||||
|
MeshElemMap *edge_poly_map;
|
||||||
|
int *edge_poly_mem = nullptr;
|
||||||
|
if (face_step) {
|
||||||
|
BKE_mesh_edge_poly_map_create(&edge_poly_map,
|
||||||
|
&edge_poly_mem,
|
||||||
|
edges.size(),
|
||||||
|
polys.data(),
|
||||||
|
polys.size(),
|
||||||
|
corner_edges.data(),
|
||||||
|
corner_edges.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Need a copy of the selected verts that we can read from and is not modified. */
|
||||||
|
BitVector<> select_vert_original(mesh->totvert);
|
||||||
|
for (int i = 0; i < mesh->totvert; i++) {
|
||||||
|
select_vert_original[i].set(select_vert.span[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const int i : edges.index_range()) {
|
||||||
|
const MEdge &edge = edges[i];
|
||||||
|
if ((select_vert_original[edge.v1] && select_vert_original[edge.v2]) && !hide_edge[i]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
select_vert.span[edge.v1] = false;
|
||||||
|
select_vert.span[edge.v2] = false;
|
||||||
|
|
||||||
|
if (!face_step) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const Span<int> neighbor_polys(edge_poly_map[i].indices, edge_poly_map[i].count);
|
||||||
|
for (const int poly_i : neighbor_polys) {
|
||||||
|
if (hide_poly[poly_i]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const MPoly &poly = polys[poly_i];
|
||||||
|
for (const int vert : corner_verts.slice(poly.loopstart, poly.totloop)) {
|
||||||
|
select_vert.span[vert] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (edge_poly_mem) {
|
||||||
|
MEM_freeN(edge_poly_map);
|
||||||
|
MEM_freeN(edge_poly_mem);
|
||||||
|
}
|
||||||
|
select_vert.finish();
|
||||||
|
}
|
||||||
|
|
||||||
void paintvert_tag_select_update(bContext *C, Object *ob)
|
void paintvert_tag_select_update(bContext *C, Object *ob)
|
||||||
{
|
{
|
||||||
DEG_id_tag_update(static_cast<ID *>(ob->data), ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT);
|
DEG_id_tag_update(static_cast<ID *>(ob->data), ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT);
|
||||||
|
@ -387,6 +387,8 @@ void PAINT_OT_vert_select_ungrouped(struct wmOperatorType *ot);
|
|||||||
void PAINT_OT_vert_select_hide(struct wmOperatorType *ot);
|
void PAINT_OT_vert_select_hide(struct wmOperatorType *ot);
|
||||||
void PAINT_OT_vert_select_linked(struct wmOperatorType *ot);
|
void PAINT_OT_vert_select_linked(struct wmOperatorType *ot);
|
||||||
void PAINT_OT_vert_select_linked_pick(struct wmOperatorType *ot);
|
void PAINT_OT_vert_select_linked_pick(struct wmOperatorType *ot);
|
||||||
|
void PAINT_OT_vert_select_more(struct wmOperatorType *ot);
|
||||||
|
void PAINT_OT_vert_select_less(struct wmOperatorType *ot);
|
||||||
|
|
||||||
bool vert_paint_poll(struct bContext *C);
|
bool vert_paint_poll(struct bContext *C);
|
||||||
bool mask_paint_poll(struct bContext *C);
|
bool mask_paint_poll(struct bContext *C);
|
||||||
|
@ -1501,6 +1501,8 @@ void ED_operatortypes_paint(void)
|
|||||||
WM_operatortype_append(PAINT_OT_vert_select_hide);
|
WM_operatortype_append(PAINT_OT_vert_select_hide);
|
||||||
WM_operatortype_append(PAINT_OT_vert_select_linked);
|
WM_operatortype_append(PAINT_OT_vert_select_linked);
|
||||||
WM_operatortype_append(PAINT_OT_vert_select_linked_pick);
|
WM_operatortype_append(PAINT_OT_vert_select_linked_pick);
|
||||||
|
WM_operatortype_append(PAINT_OT_vert_select_more);
|
||||||
|
WM_operatortype_append(PAINT_OT_vert_select_less);
|
||||||
|
|
||||||
/* vertex */
|
/* vertex */
|
||||||
WM_operatortype_append(PAINT_OT_vertex_paint_toggle);
|
WM_operatortype_append(PAINT_OT_vertex_paint_toggle);
|
||||||
|
@ -796,6 +796,72 @@ void PAINT_OT_vert_select_linked_pick(wmOperatorType *ot)
|
|||||||
"Whether to select or deselect linked vertices under the cursor");
|
"Whether to select or deselect linked vertices under the cursor");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int paintvert_select_more_exec(bContext *C, wmOperator *op)
|
||||||
|
{
|
||||||
|
Object *ob = CTX_data_active_object(C);
|
||||||
|
Mesh *mesh = BKE_mesh_from_object(ob);
|
||||||
|
if (mesh == NULL || mesh->totpoly == 0) {
|
||||||
|
return OPERATOR_CANCELLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool face_step = RNA_boolean_get(op->ptr, "face_step");
|
||||||
|
paintvert_select_more(mesh, face_step);
|
||||||
|
|
||||||
|
paintvert_flush_flags(ob);
|
||||||
|
paintvert_tag_select_update(C, ob);
|
||||||
|
ED_region_tag_redraw(CTX_wm_region(C));
|
||||||
|
|
||||||
|
return OPERATOR_FINISHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PAINT_OT_vert_select_more(wmOperatorType *ot)
|
||||||
|
{
|
||||||
|
ot->name = "Select More";
|
||||||
|
ot->description = "Select Vertices connected to existing selection";
|
||||||
|
ot->idname = "PAINT_OT_vert_select_more";
|
||||||
|
|
||||||
|
ot->exec = paintvert_select_more_exec;
|
||||||
|
ot->poll = vert_paint_poll;
|
||||||
|
|
||||||
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||||
|
|
||||||
|
RNA_def_boolean(
|
||||||
|
ot->srna, "face_step", true, "Face Step", "Also select faces that only touch on a corner");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int paintvert_select_less_exec(bContext *C, wmOperator *op)
|
||||||
|
{
|
||||||
|
Object *ob = CTX_data_active_object(C);
|
||||||
|
Mesh *mesh = BKE_mesh_from_object(ob);
|
||||||
|
if (mesh == NULL || mesh->totpoly == 0) {
|
||||||
|
return OPERATOR_CANCELLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool face_step = RNA_boolean_get(op->ptr, "face_step");
|
||||||
|
paintvert_select_less(mesh, face_step);
|
||||||
|
|
||||||
|
paintvert_flush_flags(ob);
|
||||||
|
paintvert_tag_select_update(C, ob);
|
||||||
|
ED_region_tag_redraw(CTX_wm_region(C));
|
||||||
|
|
||||||
|
return OPERATOR_FINISHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PAINT_OT_vert_select_less(wmOperatorType *ot)
|
||||||
|
{
|
||||||
|
ot->name = "Select Less";
|
||||||
|
ot->description = "Deselect Vertices connected to existing selection";
|
||||||
|
ot->idname = "PAINT_OT_vert_select_less";
|
||||||
|
|
||||||
|
ot->exec = paintvert_select_less_exec;
|
||||||
|
ot->poll = vert_paint_poll;
|
||||||
|
|
||||||
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||||
|
|
||||||
|
RNA_def_boolean(
|
||||||
|
ot->srna, "face_step", true, "Face Step", "Also deselect faces that only touch on a corner");
|
||||||
|
}
|
||||||
|
|
||||||
static int face_select_hide_exec(bContext *C, wmOperator *op)
|
static int face_select_hide_exec(bContext *C, wmOperator *op)
|
||||||
{
|
{
|
||||||
const bool unselected = RNA_boolean_get(op->ptr, "unselected");
|
const bool unselected = RNA_boolean_get(op->ptr, "unselected");
|
||||||
|
Loading…
Reference in New Issue
Block a user
You set every value of the bit vector, so there's no need to explicitly initialize it to false here.