diff options
Diffstat (limited to 'source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc')
-rw-r--r-- | source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc | 342 |
1 files changed, 240 insertions, 102 deletions
diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc index d07644f8403..1de809b30e4 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc @@ -29,63 +29,26 @@ #include "node_geometry_util.hh" -using blender::bke::CustomDataAttributes; - -/* Code from the mask modifier in MOD_mask.cc. */ -extern void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh, - Mesh &dst_mesh, - blender::Span<int> vertex_map); -extern void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, - Mesh &dst_mesh, - blender::Span<int> vertex_map, - blender::Span<int> edge_map); -extern void copy_masked_polys_to_new_mesh(const Mesh &src_mesh, - Mesh &dst_mesh, - blender::Span<int> vertex_map, - blender::Span<int> edge_map, - blender::Span<int> masked_poly_indices, - blender::Span<int> new_loop_starts); - namespace blender::nodes { -static void geo_node_delete_geometry_declare(NodeDeclarationBuilder &b) -{ - b.add_input<decl::Geometry>(N_("Geometry")); - b.add_input<decl::Bool>(N_("Selection")) - .default_value(true) - .hide_value() - .supports_field() - .description(N_("The parts of the geometry to be deleted")); - b.add_output<decl::Geometry>(N_("Geometry")); -} +using blender::bke::CustomDataAttributes; -static void geo_node_delete_geometry_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +template<typename T> +static void copy_data_based_on_mask(Span<T> data, MutableSpan<T> r_data, IndexMask mask) { - const bNode *node = static_cast<bNode *>(ptr->data); - const NodeGeometryDeleteGeometry &storage = *(const NodeGeometryDeleteGeometry *)node->storage; - const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain); - - uiItemR(layout, ptr, "domain", 0, "", ICON_NONE); - /* Only show the mode when it is relevant. */ - if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE)) { - uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); + for (const int i_out : mask.index_range()) { + r_data[i_out] = data[mask[i_out]]; } } -static void geo_node_delete_geometry_init(bNodeTree *UNUSED(tree), bNode *node) -{ - NodeGeometryDeleteGeometry *data = (NodeGeometryDeleteGeometry *)MEM_callocN( - sizeof(NodeGeometryDeleteGeometry), __func__); - data->domain = ATTR_DOMAIN_POINT; - data->mode = GEO_NODE_DELETE_GEOMETRY_MODE_ALL; - - node->storage = data; -} - -template<typename T> static void copy_data(Span<T> data, MutableSpan<T> r_data, IndexMask mask) +template<typename T> +static void copy_data_based_on_map(Span<T> src, MutableSpan<T> dst, Span<int> index_map) { - for (const int i_out : mask.index_range()) { - r_data[i_out] = data[mask[i_out]]; + for (const int i_src : index_map.index_range()) { + const int i_dst = index_map[i_src]; + if (i_dst != -1) { + dst[i_dst] = src[i_src]; + } } } @@ -102,23 +65,6 @@ static IndexMask index_mask_indices(Span<bool> mask, const bool invert, Vector<i return IndexMask(indices); } -/** Utility function for making an IndexMask from an array of integers, where the negative integers - * are seen as false. The indices vector should live at least as long as the returned IndexMask. - */ -static IndexMask index_mask_indices(Span<int> mask, - const int num_indices, - Vector<int64_t> &indices) -{ - indices.clear(); - indices.reserve(num_indices); - for (const int i : mask.index_range()) { - if (mask[i] >= 0) { - indices.append_unchecked(i); - } - } - return IndexMask(indices); -} - /** * Copies the attributes with a domain in `domains` to `result_component`. */ @@ -191,12 +137,87 @@ static void copy_attributes_based_on_mask(const Map<AttributeIDRef, AttributeKin using T = decltype(dummy); VArray_Span<T> span{attribute.varray.typed<T>()}; MutableSpan<T> out_span = result_attribute.as_span<T>(); - copy_data(span, out_span, mask); + copy_data_based_on_mask(span, out_span, mask); }); result_attribute.save(); } } +static void copy_attributes_based_on_map(const Map<AttributeIDRef, AttributeKind> &attributes, + const GeometryComponent &in_component, + GeometryComponent &result_component, + const AttributeDomain domain, + const Span<int> index_map) +{ + for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) { + const AttributeIDRef attribute_id = entry.key; + ReadAttributeLookup attribute = in_component.attribute_try_get_for_read(attribute_id); + if (!attribute) { + continue; + } + + /* Only copy if it is on a domain we want. */ + if (domain != attribute.domain) { + continue; + } + const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); + + OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only( + attribute_id, attribute.domain, data_type); + + if (!result_attribute) { + continue; + } + + attribute_math::convert_to_static_type(data_type, [&](auto dummy) { + using T = decltype(dummy); + VArray_Span<T> span{attribute.varray.typed<T>()}; + MutableSpan<T> out_span = result_attribute.as_span<T>(); + copy_data_based_on_map(span, out_span, index_map); + }); + result_attribute.save(); + } +} + +static void copy_face_corner_attributes(const Map<AttributeIDRef, AttributeKind> &attributes, + const GeometryComponent &in_component, + GeometryComponent &out_component, + const int num_selected_loops, + const Span<int> selected_poly_indices, + const Mesh &mesh_in) +{ + Vector<int64_t> indices; + indices.reserve(num_selected_loops); + for (const int src_poly_index : selected_poly_indices) { + const MPoly &src_poly = mesh_in.mpoly[src_poly_index]; + const int src_loop_start = src_poly.loopstart; + const int tot_loop = src_poly.totloop; + for (const int i : IndexRange(tot_loop)) { + indices.append_unchecked(src_loop_start + i); + } + } + copy_attributes_based_on_mask( + attributes, in_component, out_component, ATTR_DOMAIN_CORNER, IndexMask(indices)); +} + +static void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + Span<int> vertex_map) +{ + BLI_assert(src_mesh.totvert == vertex_map.size()); + for (const int i_src : vertex_map.index_range()) { + const int i_dst = vertex_map[i_src]; + if (i_dst == -1) { + continue; + } + + const MVert &v_src = src_mesh.mvert[i_src]; + MVert &v_dst = dst_mesh.mvert[i_dst]; + + v_dst = v_src; + } +} + static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, Mesh &dst_mesh, Span<int> edge_map) { BLI_assert(src_mesh.totedge == edge_map.size()); @@ -215,6 +236,28 @@ static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, Mesh &dst_mesh, } } +static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + Span<int> vertex_map, + Span<int> edge_map) +{ + BLI_assert(src_mesh.totvert == vertex_map.size()); + BLI_assert(src_mesh.totedge == edge_map.size()); + for (const int i_src : IndexRange(src_mesh.totedge)) { + const int i_dst = edge_map[i_src]; + if (i_dst == -1) { + continue; + } + + const MEdge &e_src = src_mesh.medge[i_src]; + MEdge &e_dst = dst_mesh.medge[i_dst]; + + e_dst = e_src; + e_dst.v1 = vertex_map[e_src.v1]; + e_dst.v2 = vertex_map[e_src.v2]; + } +} + /* Faces and edges changed but vertices are the same. */ static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh, Mesh &dst_mesh, @@ -268,29 +311,56 @@ static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh, } } +static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + Span<int> vertex_map, + Span<int> edge_map, + Span<int> masked_poly_indices, + Span<int> new_loop_starts) +{ + for (const int i_dst : masked_poly_indices.index_range()) { + const int i_src = masked_poly_indices[i_dst]; + + const MPoly &mp_src = src_mesh.mpoly[i_src]; + MPoly &mp_dst = dst_mesh.mpoly[i_dst]; + const int i_ml_src = mp_src.loopstart; + const int i_ml_dst = new_loop_starts[i_dst]; + + const MLoop *ml_src = src_mesh.mloop + i_ml_src; + MLoop *ml_dst = dst_mesh.mloop + i_ml_dst; + + mp_dst = mp_src; + mp_dst.loopstart = i_ml_dst; + for (int i : IndexRange(mp_src.totloop)) { + ml_dst[i].v = vertex_map[ml_src[i].v]; + ml_dst[i].e = edge_map[ml_src[i].e]; + } + } +} + static void spline_copy_builtin_attributes(const Spline &spline, Spline &r_spline, const IndexMask mask) { - copy_data(spline.positions(), r_spline.positions(), mask); - copy_data(spline.radii(), r_spline.radii(), mask); - copy_data(spline.tilts(), r_spline.tilts(), mask); + copy_data_based_on_mask(spline.positions(), r_spline.positions(), mask); + copy_data_based_on_mask(spline.radii(), r_spline.radii(), mask); + copy_data_based_on_mask(spline.tilts(), r_spline.tilts(), mask); switch (spline.type()) { case Spline::Type::Poly: break; case Spline::Type::Bezier: { const BezierSpline &src = static_cast<const BezierSpline &>(spline); BezierSpline &dst = static_cast<BezierSpline &>(r_spline); - copy_data(src.handle_positions_left(), dst.handle_positions_left(), mask); - copy_data(src.handle_positions_right(), dst.handle_positions_right(), mask); - copy_data(src.handle_types_left(), dst.handle_types_left(), mask); - copy_data(src.handle_types_right(), dst.handle_types_right(), mask); + copy_data_based_on_mask(src.handle_positions_left(), dst.handle_positions_left(), mask); + copy_data_based_on_mask(src.handle_positions_right(), dst.handle_positions_right(), mask); + copy_data_based_on_mask(src.handle_types_left(), dst.handle_types_left(), mask); + copy_data_based_on_mask(src.handle_types_right(), dst.handle_types_right(), mask); break; } case Spline::Type::NURBS: { const NURBSpline &src = static_cast<const NURBSpline &>(spline); NURBSpline &dst = static_cast<NURBSpline &>(r_spline); - copy_data(src.weights(), dst.weights(), mask); + copy_data_based_on_mask(src.weights(), dst.weights(), mask); break; } } @@ -316,7 +386,7 @@ static void copy_dynamic_attributes(const CustomDataAttributes &src, attribute_math::convert_to_static_type(new_attribute->type(), [&](auto dummy) { using T = decltype(dummy); - copy_data(src_attribute->typed<T>(), new_attribute->typed<T>(), mask); + copy_data_based_on_mask(src_attribute->typed<T>(), new_attribute->typed<T>(), mask); }); return true; }, @@ -986,6 +1056,23 @@ static void do_mesh_separation(GeometrySet &geometry_set, copy_masked_edges_to_new_mesh(mesh_in, *mesh_out, vertex_map, edge_map); copy_masked_polys_to_new_mesh( mesh_in, *mesh_out, vertex_map, edge_map, selected_poly_indices, new_loop_starts); + + /* Copy attributes. */ + copy_attributes_based_on_map( + attributes, in_component, out_component, ATTR_DOMAIN_POINT, vertex_map); + copy_attributes_based_on_map( + attributes, in_component, out_component, ATTR_DOMAIN_EDGE, edge_map); + copy_attributes_based_on_mask(attributes, + in_component, + out_component, + ATTR_DOMAIN_FACE, + IndexMask(Vector<int64_t>(selected_poly_indices.as_span()))); + copy_face_corner_attributes(attributes, + in_component, + out_component, + num_selected_loops, + selected_poly_indices, + mesh_in); break; } case GEO_NODE_DELETE_GEOMETRY_MODE_EDGE_FACE: { @@ -1041,22 +1128,25 @@ static void do_mesh_separation(GeometrySet &geometry_set, /* Copy the selected parts of the mesh over to the new mesh. */ memcpy(mesh_out->mvert, mesh_in.mvert, mesh_in.totvert * sizeof(MVert)); - copy_attributes(attributes, in_component, out_component, {ATTR_DOMAIN_POINT}); copy_masked_edges_to_new_mesh(mesh_in, *mesh_out, edge_map); copy_masked_polys_to_new_mesh( mesh_in, *mesh_out, edge_map, selected_poly_indices, new_loop_starts); - Vector<int64_t> indices; + + /* Copy attributes. */ + copy_attributes(attributes, in_component, out_component, {ATTR_DOMAIN_POINT}); + copy_attributes_based_on_map( + attributes, in_component, out_component, ATTR_DOMAIN_EDGE, edge_map); copy_attributes_based_on_mask(attributes, in_component, out_component, - ATTR_DOMAIN_EDGE, - index_mask_indices(edge_map, num_selected_edges, indices)); - copy_attributes_based_on_mask( - attributes, - in_component, - out_component, - ATTR_DOMAIN_FACE, - index_mask_indices(selected_poly_indices, num_selected_polys, indices)); + ATTR_DOMAIN_FACE, + IndexMask(Vector<int64_t>(selected_poly_indices.as_span()))); + copy_face_corner_attributes(attributes, + in_component, + out_component, + num_selected_loops, + selected_poly_indices, + mesh_in); break; } case GEO_NODE_DELETE_GEOMETRY_MODE_ONLY_FACE: { @@ -1100,14 +1190,22 @@ static void do_mesh_separation(GeometrySet &geometry_set, /* Copy the selected parts of the mesh over to the new mesh. */ memcpy(mesh_out->mvert, mesh_in.mvert, mesh_in.totvert * sizeof(MVert)); memcpy(mesh_out->medge, mesh_in.medge, mesh_in.totedge * sizeof(MEdge)); + copy_masked_polys_to_new_mesh(mesh_in, *mesh_out, selected_poly_indices, new_loop_starts); + + /* Copy attributes. */ copy_attributes( attributes, in_component, out_component, {ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE}); - copy_masked_polys_to_new_mesh(mesh_in, *mesh_out, selected_poly_indices, new_loop_starts); - Vector<int64_t> indices; - const IndexMask mask = index_mask_indices( - selected_poly_indices, num_selected_polys, indices); - copy_attributes_based_on_mask( - attributes, in_component, out_component, ATTR_DOMAIN_FACE, mask); + copy_attributes_based_on_mask(attributes, + in_component, + out_component, + ATTR_DOMAIN_FACE, + IndexMask(Vector<int64_t>(selected_poly_indices.as_span()))); + copy_face_corner_attributes(attributes, + in_component, + out_component, + num_selected_loops, + selected_poly_indices, + mesh_in); break; } } @@ -1177,17 +1275,55 @@ void separate_geometry(GeometrySet &geometry_set, r_is_error = !some_valid_domain && geometry_set.has_realized_data(); } -static void geo_node_delete_geometry_exec(GeoNodeExecParams params) +} // namespace blender::nodes + +namespace blender::nodes::node_geo_delete_geometry_cc { + +NODE_STORAGE_FUNCS(NodeGeometryDeleteGeometry) + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Geometry>(N_("Geometry")); + b.add_input<decl::Bool>(N_("Selection")) + .default_value(true) + .hide_value() + .supports_field() + .description(N_("The parts of the geometry to be deleted")); + b.add_output<decl::Geometry>(N_("Geometry")); +} + +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + const bNode *node = static_cast<bNode *>(ptr->data); + const NodeGeometryDeleteGeometry &storage = node_storage(*node); + const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain); + + uiItemR(layout, ptr, "domain", 0, "", ICON_NONE); + /* Only show the mode when it is relevant. */ + if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE)) { + uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); + } +} + +static void node_init(bNodeTree *UNUSED(tree), bNode *node) +{ + NodeGeometryDeleteGeometry *data = (NodeGeometryDeleteGeometry *)MEM_callocN( + sizeof(NodeGeometryDeleteGeometry), __func__); + data->domain = ATTR_DOMAIN_POINT; + data->mode = GEO_NODE_DELETE_GEOMETRY_MODE_ALL; + + node->storage = data; +} + +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); - const bNode &node = params.node(); - const NodeGeometryDeleteGeometry &storage = *(const NodeGeometryDeleteGeometry *)node.storage; + const NodeGeometryDeleteGeometry &storage = node_storage(params.node()); const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain); - const GeometryNodeDeleteGeometryMode mode = static_cast<GeometryNodeDeleteGeometryMode>( - storage.mode); + const GeometryNodeDeleteGeometryMode mode = (GeometryNodeDeleteGeometryMode)storage.mode; bool all_is_error = false; geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { @@ -1204,10 +1340,12 @@ static void geo_node_delete_geometry_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_delete_geometry_cc void register_node_type_geo_delete_geometry() { + namespace file_ns = blender::nodes::node_geo_delete_geometry_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_DELETE_GEOMETRY, "Delete Geometry", NODE_CLASS_GEOMETRY, 0); @@ -1217,10 +1355,10 @@ void register_node_type_geo_delete_geometry() node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_delete_geometry_init); + node_type_init(&ntype, file_ns::node_init); - ntype.declare = blender::nodes::geo_node_delete_geometry_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_delete_geometry_exec; - ntype.draw_buttons = blender::nodes::geo_node_delete_geometry_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } |