Spreadsheet: Implement selection filter for curves sculpt mode

The spreadsheet can retrieve the float selection using the same
utilities as curves sculpt brushes. Theoretically this can work in
original, evaluated, and viewer node modes, at least when the
sculpt selection attributes are able to be propagated.

Differential Revision: https://developer.blender.org/D15393
This commit is contained in:
Hans Goudey 2022-07-21 09:34:48 -05:00
parent 412d93c298
commit 396b7a6ec8
6 changed files with 168 additions and 69 deletions

View File

@ -95,8 +95,10 @@ class SPREADSHEET_HT_header(bpy.types.Header):
obj = root_context.object
if obj is None:
return False
if obj.type != 'MESH' or obj.mode != 'EDIT':
return False
if obj.type == 'MESH':
return obj.mode == 'EDIT'
if obj.type == 'CURVES':
return obj.mode == 'SCULPT_CURVES'
return True

View File

@ -10,8 +10,33 @@
extern "C" {
#endif
struct Curves;
void ED_operatortypes_sculpt_curves(void);
#ifdef __cplusplus
# include "BLI_index_mask.hh"
# include "BLI_vector.hh"
namespace blender::ed::sculpt_paint {
/**
* Find curves that have any point selected (a selection factor greater than zero),
* or curves that have their own selection factor greater than zero.
*/
IndexMask retrieve_selected_curves(const Curves &curves_id, Vector<int64_t> &r_indices);
/**
* Find points that are selected (a selection factor greater than zero),
* or points in curves with a selection factor greater than zero).
*/
IndexMask retrieve_selected_points(const Curves &curves_id, Vector<int64_t> &r_indices);
} // namespace blender::ed::sculpt_paint
#endif
#ifdef __cplusplus
}
#endif

View File

@ -14,6 +14,8 @@
#include "BKE_attribute.h"
#include "BKE_curves.hh"
#include "ED_curves_sculpt.h"
struct ARegion;
struct RegionView3D;
struct Depsgraph;
@ -98,12 +100,6 @@ VArray<float> get_curves_selection(const Curves &curves_id);
*/
VArray<float> get_point_selection(const Curves &curves_id);
/**
* Find curves that have any point selected (a selection factor greater than zero),
* or curves that have their own selection factor greater than zero.
*/
IndexMask retrieve_selected_curves(const Curves &curves_id, Vector<int64_t> &r_indices);
void move_last_point_and_resample(MutableSpan<float3> positions, const float3 &new_last_position);
class CurvesSculptCommonContext {

View File

@ -6,6 +6,8 @@
#include "curves_sculpt_intern.hh"
#include "ED_curves_sculpt.h"
namespace blender::ed::sculpt_paint {
static VArray<float> get_curves_selection(const CurvesGeometry &curves, const eAttrDomain domain)
@ -62,7 +64,7 @@ static IndexMask retrieve_selected_curves(const CurvesGeometry &curves,
case ATTR_DOMAIN_POINT: {
const VArray<float> selection = curves.selection_point_float();
if (selection.is_single()) {
return selection.get_internal_single() == 0.0f ? IndexMask(0) :
return selection.get_internal_single() <= 0.0f ? IndexMask(0) :
IndexMask(curves.curves_num());
}
return index_mask_ops::find_indices_based_on_predicate(
@ -78,7 +80,7 @@ static IndexMask retrieve_selected_curves(const CurvesGeometry &curves,
case ATTR_DOMAIN_CURVE: {
const VArray<float> selection = curves.selection_curve_float();
if (selection.is_single()) {
return selection.get_internal_single() == 0.0f ? IndexMask(0) :
return selection.get_internal_single() <= 0.0f ? IndexMask(0) :
IndexMask(curves.curves_num());
}
return index_mask_ops::find_indices_based_on_predicate(
@ -102,4 +104,49 @@ IndexMask retrieve_selected_curves(const Curves &curves_id, Vector<int64_t> &r_i
r_indices);
}
static IndexMask retrieve_selected_points(const CurvesGeometry &curves,
const eAttrDomain domain,
Vector<int64_t> &r_indices)
{
switch (domain) {
case ATTR_DOMAIN_POINT: {
const VArray<float> selection = curves.selection_point_float();
if (selection.is_single()) {
return selection.get_internal_single() <= 0.0f ? IndexMask(0) :
IndexMask(curves.points_num());
}
return index_mask_ops::find_indices_based_on_predicate(
curves.points_range(), 2048, r_indices, [&](const int i) {
return selection[i] > 0.0f;
});
}
case ATTR_DOMAIN_CURVE: {
const VArray<float> selection = curves.selection_curve_float();
if (selection.is_single()) {
return selection.get_internal_single() <= 0.0f ? IndexMask(0) :
IndexMask(curves.points_num());
}
const VArray<float> point_selection = curves.adapt_domain(
selection, ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
return index_mask_ops::find_indices_based_on_predicate(
curves.points_range(), 2048, r_indices, [&](const int i) {
return point_selection[i] > 0.0f;
});
}
default:
BLI_assert_unreachable();
return {};
}
}
IndexMask retrieve_selected_points(const Curves &curves_id, Vector<int64_t> &r_indices)
{
if (!(curves_id.flag & CV_SCULPT_SELECTION_ENABLED)) {
return CurvesGeometry::wrap(curves_id.geometry).points_range();
}
return retrieve_selected_points(CurvesGeometry::wrap(curves_id.geometry),
eAttrDomain(curves_id.selection_domain),
r_indices);
}
} // namespace blender::ed::sculpt_paint

View File

@ -5,6 +5,7 @@
#include "BKE_attribute.hh"
#include "BKE_context.h"
#include "BKE_curves.hh"
#include "BKE_editmesh.h"
#include "BKE_geometry_fields.hh"
#include "BKE_global.h"
@ -22,6 +23,7 @@
#include "DEG_depsgraph_query.h"
#include "ED_curves_sculpt.h"
#include "ED_spreadsheet.h"
#include "NOD_geometry_nodes_eval_log.hh"
@ -232,23 +234,31 @@ int GeometryDataSource::tot_rows() const
return attributes.domain_size(domain_);
}
/**
* Only data sets corresponding to mesh objects in edit mode currently support selection filtering.
*/
bool GeometryDataSource::has_selection_filter() const
{
Object *object_orig = DEG_get_original_object(object_eval_);
if (object_orig->type != OB_MESH) {
return false;
switch (component_->type()) {
case GEO_COMPONENT_TYPE_MESH: {
if (object_orig->type != OB_MESH) {
return false;
}
if (object_orig->mode != OB_MODE_EDIT) {
return false;
}
return true;
}
case GEO_COMPONENT_TYPE_CURVE: {
if (object_orig->type != OB_CURVES) {
return false;
}
if (object_orig->mode != OB_MODE_SCULPT_CURVES) {
return false;
}
return true;
}
default:
return false;
}
if (object_orig->mode != OB_MODE_EDIT) {
return false;
}
if (component_->type() != GEO_COMPONENT_TYPE_MESH) {
return false;
}
return true;
}
IndexMask GeometryDataSource::apply_selection_filter(Vector<int64_t> &indices) const
@ -256,50 +266,73 @@ IndexMask GeometryDataSource::apply_selection_filter(Vector<int64_t> &indices) c
std::lock_guard lock{mutex_};
const IndexMask full_range(this->tot_rows());
BLI_assert(object_eval_->mode == OB_MODE_EDIT);
BLI_assert(component_->type() == GEO_COMPONENT_TYPE_MESH);
Object *object_orig = DEG_get_original_object(object_eval_);
const MeshComponent *mesh_component = static_cast<const MeshComponent *>(component_);
const Mesh *mesh_eval = mesh_component->get_for_read();
Mesh *mesh_orig = (Mesh *)object_orig->data;
BMesh *bm = mesh_orig->edit_mesh->bm;
BM_mesh_elem_table_ensure(bm, BM_VERT);
switch (component_->type()) {
case GEO_COMPONENT_TYPE_MESH: {
BLI_assert(object_eval_->type == OB_MESH);
BLI_assert(object_eval_->mode == OB_MODE_EDIT);
Object *object_orig = DEG_get_original_object(object_eval_);
const Mesh *mesh_eval = geometry_set_.get_mesh_for_read();
const bke::AttributeAccessor attributes_eval = bke::mesh_attributes(*mesh_eval);
Mesh *mesh_orig = (Mesh *)object_orig->data;
BMesh *bm = mesh_orig->edit_mesh->bm;
BM_mesh_elem_table_ensure(bm, BM_VERT);
const int *orig_indices = (int *)CustomData_get_layer(&mesh_eval->vdata, CD_ORIGINDEX);
if (orig_indices != nullptr) {
/* Use CD_ORIGINDEX layer if it exists. */
VArray<bool> selection = mesh_component->attributes()->adapt_domain<bool>(
VArray<bool>::ForFunc(mesh_eval->totvert,
[bm, orig_indices](int vertex_index) -> bool {
const int i_orig = orig_indices[vertex_index];
if (i_orig < 0) {
return false;
}
if (i_orig >= bm->totvert) {
return false;
}
BMVert *vert = bm->vtable[i_orig];
return BM_elem_flag_test(vert, BM_ELEM_SELECT);
}),
ATTR_DOMAIN_POINT,
domain_);
return index_mask_ops::find_indices_from_virtual_array(full_range, selection, 1024, indices);
const int *orig_indices = (int *)CustomData_get_layer(&mesh_eval->vdata, CD_ORIGINDEX);
if (orig_indices != nullptr) {
/* Use CD_ORIGINDEX layer if it exists. */
VArray<bool> selection = attributes_eval.adapt_domain<bool>(
VArray<bool>::ForFunc(mesh_eval->totvert,
[bm, orig_indices](int vertex_index) -> bool {
const int i_orig = orig_indices[vertex_index];
if (i_orig < 0) {
return false;
}
if (i_orig >= bm->totvert) {
return false;
}
const BMVert *vert = BM_vert_at_index(bm, i_orig);
return BM_elem_flag_test(vert, BM_ELEM_SELECT);
}),
ATTR_DOMAIN_POINT,
domain_);
return index_mask_ops::find_indices_from_virtual_array(
full_range, selection, 1024, indices);
}
if (mesh_eval->totvert == bm->totvert) {
/* Use a simple heuristic to match original vertices to evaluated ones. */
VArray<bool> selection = attributes_eval.adapt_domain<bool>(
VArray<bool>::ForFunc(mesh_eval->totvert,
[bm](int vertex_index) -> bool {
const BMVert *vert = BM_vert_at_index(bm, vertex_index);
return BM_elem_flag_test(vert, BM_ELEM_SELECT);
}),
ATTR_DOMAIN_POINT,
domain_);
return index_mask_ops::find_indices_from_virtual_array(
full_range, selection, 2048, indices);
}
return full_range;
}
case GEO_COMPONENT_TYPE_CURVE: {
BLI_assert(object_eval_->type == OB_CURVES);
BLI_assert(object_eval_->mode == OB_MODE_SCULPT_CURVES);
const CurveComponent &component = static_cast<const CurveComponent &>(*component_);
const Curves &curves_id = *component.get_for_read();
switch (domain_) {
case ATTR_DOMAIN_POINT:
return sculpt_paint::retrieve_selected_points(curves_id, indices);
case ATTR_DOMAIN_CURVE:
return sculpt_paint::retrieve_selected_curves(curves_id, indices);
default:
BLI_assert_unreachable();
}
return full_range;
}
default:
return full_range;
}
if (mesh_eval->totvert == bm->totvert) {
/* Use a simple heuristic to match original vertices to evaluated ones. */
VArray<bool> selection = mesh_component->attributes()->adapt_domain<bool>(
VArray<bool>::ForFunc(mesh_eval->totvert,
[bm](int vertex_index) -> bool {
BMVert *vert = bm->vtable[vertex_index];
return BM_elem_flag_test(vert, BM_ELEM_SELECT);
}),
ATTR_DOMAIN_POINT,
domain_);
return index_mask_ops::find_indices_from_virtual_array(full_range, selection, 2048, indices);
}
return full_range;
}
void VolumeDataSource::foreach_default_column_ids(

View File

@ -68,10 +68,6 @@ class GeometryDataSource : public DataSource {
return object_eval_;
}
/**
* Only data sets corresponding to mesh objects in edit mode currently support selection
* filtering.
*/
bool has_selection_filter() const override;
IndexMask apply_selection_filter(Vector<int64_t> &indices) const;