Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/nodes/geometry')
-rw-r--r--source/blender/nodes/geometry/CMakeLists.txt33
-rw-r--r--source/blender/nodes/geometry/node_geometry_exec.cc1
-rw-r--r--source/blender/nodes/geometry/node_geometry_tree.cc18
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.cc6
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.hh34
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc66
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc45
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_boolean.cc13
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_collection_info.cc26
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc20
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc35
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc11
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc28
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc11
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc47
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_set_handle_type.cc41
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc68
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc9
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc7
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc403
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_topology_curve_of_point.cc121
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_topology_points_of_curve.cc182
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc492
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc71
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc398
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc285
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc126
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc191
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc155
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_curves.cc13
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_selection.cc50
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_edge_split.cc23
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc210
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc126
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc28
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_image_texture.cc60
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc25
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc27
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc27
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_material.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc92
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc35
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc109
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc39
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc54
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc80
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc67
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc72
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_shortest_edge_paths.cc89
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc25
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc27
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc46
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_interpolate_domain.cc38
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc45
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_material_selection.cc44
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc46
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_face_set_boundaries.cc94
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc59
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc21
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc7
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc52
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_volume.cc21
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_face.cc189
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc209
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc136
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc211
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_topology_face_of_corner.cc121
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc113
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_topology_vertex_of_corner.cc79
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_object_info.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_offset_point_in_curve.cc169
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc25
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc15
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_proximity.cc11
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_raycast.cc26
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc19
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_sample_index.cc337
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_sample_nearest.cc342
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc278
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_sample_uv_surface.cc294
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc172
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_self_object.cc29
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc47
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_normal.cc73
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc23
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc24
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_id.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_material.cc13
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc20
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc20
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_position.cc11
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc29
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc24
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc28
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc73
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_string_join.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc42
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc26
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_switch.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc826
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transform.cc97
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc20
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_triangulate.cc19
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc51
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc58
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_viewer.cc20
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc30
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc17
132 files changed, 5546 insertions, 3785 deletions
diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt
index 31c00cc6b82..2b8de906a77 100644
--- a/source/blender/nodes/geometry/CMakeLists.txt
+++ b/source/blender/nodes/geometry/CMakeLists.txt
@@ -56,9 +56,12 @@ set(SRC
nodes/node_geo_curve_subdivide.cc
nodes/node_geo_curve_to_mesh.cc
nodes/node_geo_curve_to_points.cc
+ nodes/node_geo_curve_topology_curve_of_point.cc
+ nodes/node_geo_curve_topology_points_of_curve.cc
nodes/node_geo_curve_trim.cc
nodes/node_geo_deform_curves_on_surface.cc
nodes/node_geo_delete_geometry.cc
+ nodes/node_geo_distribute_points_in_volume.cc
nodes/node_geo_distribute_points_on_faces.cc
nodes/node_geo_dual_mesh.cc
nodes/node_geo_duplicate_elements.cc
@@ -105,6 +108,7 @@ set(SRC
nodes/node_geo_material_replace.cc
nodes/node_geo_material_selection.cc
nodes/node_geo_merge_by_distance.cc
+ nodes/node_geo_mesh_face_set_boundaries.cc
nodes/node_geo_mesh_primitive_circle.cc
nodes/node_geo_mesh_primitive_cone.cc
nodes/node_geo_mesh_primitive_cube.cc
@@ -117,7 +121,15 @@ set(SRC
nodes/node_geo_mesh_to_curve.cc
nodes/node_geo_mesh_to_points.cc
nodes/node_geo_mesh_to_volume.cc
+ nodes/node_geo_mesh_topology_corners_of_face.cc
+ nodes/node_geo_mesh_topology_corners_of_vertex.cc
+ nodes/node_geo_mesh_topology_edges_of_corner.cc
+ nodes/node_geo_mesh_topology_edges_of_vertex.cc
+ nodes/node_geo_mesh_topology_face_of_corner.cc
+ nodes/node_geo_mesh_topology_offset_corner_in_face.cc
+ nodes/node_geo_mesh_topology_vertex_of_corner.cc
nodes/node_geo_object_info.cc
+ nodes/node_geo_offset_point_in_curve.cc
nodes/node_geo_points.cc
nodes/node_geo_points_to_vertices.cc
nodes/node_geo_points_to_volume.cc
@@ -126,11 +138,17 @@ set(SRC
nodes/node_geo_realize_instances.cc
nodes/node_geo_remove_attribute.cc
nodes/node_geo_rotate_instances.cc
+ nodes/node_geo_sample_index.cc
+ nodes/node_geo_sample_nearest.cc
+ nodes/node_geo_sample_nearest_surface.cc
+ nodes/node_geo_sample_uv_surface.cc
nodes/node_geo_scale_elements.cc
nodes/node_geo_scale_instances.cc
+ nodes/node_geo_self_object.cc
nodes/node_geo_separate_components.cc
nodes/node_geo_separate_geometry.cc
nodes/node_geo_set_curve_handles.cc
+ nodes/node_geo_set_curve_normal.cc
nodes/node_geo_set_curve_radius.cc
nodes/node_geo_set_curve_tilt.cc
nodes/node_geo_set_id.cc
@@ -146,7 +164,6 @@ set(SRC
nodes/node_geo_string_to_curves.cc
nodes/node_geo_subdivision_surface.cc
nodes/node_geo_switch.cc
- nodes/node_geo_transfer_attribute.cc
nodes/node_geo_transform.cc
nodes/node_geo_translate_instances.cc
nodes/node_geo_triangulate.cc
@@ -187,20 +204,6 @@ if(WITH_BULLET)
add_definitions(-DWITH_BULLET)
endif()
-if(WITH_PYTHON)
- list(APPEND INC
- ../../python
- )
- list(APPEND INC_SYS
- ${PYTHON_INCLUDE_DIRS}
- )
- list(APPEND LIB
- ${PYTHON_LINKFLAGS}
- ${PYTHON_LIBRARIES}
- )
- add_definitions(-DWITH_PYTHON)
-endif()
-
if(WITH_TBB)
list(APPEND INC_SYS
${TBB_INCLUDE_DIRS}
diff --git a/source/blender/nodes/geometry/node_geometry_exec.cc b/source/blender/nodes/geometry/node_geometry_exec.cc
index 58ded7aadd2..ef4daf94bbe 100644
--- a/source/blender/nodes/geometry/node_geometry_exec.cc
+++ b/source/blender/nodes/geometry/node_geometry_exec.cc
@@ -4,3 +4,4 @@
#include "NOD_geometry_exec.hh"
BLI_CPP_TYPE_MAKE(GeometrySet, GeometrySet, CPPTypeFlags::Printable);
+BLI_CPP_TYPE_MAKE(GeometrySetVector, blender::Vector<GeometrySet>, CPPTypeFlags::None);
diff --git a/source/blender/nodes/geometry/node_geometry_tree.cc b/source/blender/nodes/geometry/node_geometry_tree.cc
index e3998322741..1339024b776 100644
--- a/source/blender/nodes/geometry/node_geometry_tree.cc
+++ b/source/blender/nodes/geometry/node_geometry_tree.cc
@@ -7,6 +7,7 @@
#include "NOD_geometry.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_node.h"
#include "BKE_object.h"
@@ -25,14 +26,13 @@
bNodeTreeType *ntreeType_Geometry;
-static void geometry_node_tree_get_from_context(const bContext *C,
- bNodeTreeType *UNUSED(treetype),
- bNodeTree **r_ntree,
- ID **r_id,
- ID **r_from)
+static void geometry_node_tree_get_from_context(
+ const bContext *C, bNodeTreeType * /*treetype*/, bNodeTree **r_ntree, ID **r_id, ID **r_from)
{
+ const Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
+ BKE_view_layer_synced_ensure(scene, view_layer);
+ Object *ob = BKE_view_layer_active_object_get(view_layer);
if (ob == nullptr) {
return;
@@ -45,7 +45,7 @@ static void geometry_node_tree_get_from_context(const bContext *C,
}
if (md->type == eModifierType_Nodes) {
- NodesModifierData *nmd = (NodesModifierData *)md;
+ const NodesModifierData *nmd = reinterpret_cast<const NodesModifierData *>(md);
if (nmd->node_group != nullptr) {
*r_from = &ob->id;
*r_id = &ob->id;
@@ -62,7 +62,7 @@ static void geometry_node_tree_update(bNodeTree *ntree)
ntree_update_reroute_nodes(ntree);
}
-static void foreach_nodeclass(Scene *UNUSED(scene), void *calldata, bNodeClassCallback func)
+static void foreach_nodeclass(Scene * /*scene*/, void *calldata, bNodeClassCallback func)
{
func(calldata, NODE_CLASS_INPUT, N_("Input"));
func(calldata, NODE_CLASS_GEOMETRY, N_("Geometry"));
@@ -85,7 +85,7 @@ static bool geometry_node_tree_validate_link(eNodeSocketDatatype type_a,
return type_a == type_b;
}
-static bool geometry_node_tree_socket_type_valid(bNodeTreeType *UNUSED(ntreetype),
+static bool geometry_node_tree_socket_type_valid(bNodeTreeType * /*treetype*/,
bNodeSocketType *socket_type)
{
return nodeIsStaticSocketType(socket_type) && ELEM(socket_type->type,
diff --git a/source/blender/nodes/geometry/node_geometry_util.cc b/source/blender/nodes/geometry/node_geometry_util.cc
index 8f673d2264e..8b962d39b3c 100644
--- a/source/blender/nodes/geometry/node_geometry_util.cc
+++ b/source/blender/nodes/geometry/node_geometry_util.cc
@@ -36,14 +36,12 @@ std::optional<eCustomDataType> node_data_type_to_custom_data_type(const eNodeSoc
std::optional<eCustomDataType> node_socket_to_custom_data_type(const bNodeSocket &socket)
{
- return node_data_type_to_custom_data_type(static_cast<eNodeSocketDatatype>(socket.type));
+ return node_data_type_to_custom_data_type(eNodeSocketDatatype(socket.type));
}
} // namespace blender::nodes
-bool geo_node_poll_default(bNodeType *UNUSED(ntype),
- bNodeTree *ntree,
- const char **r_disabled_hint)
+bool geo_node_poll_default(bNodeType * /*ntype*/, bNodeTree *ntree, const char **r_disabled_hint)
{
if (!STREQ(ntree->idname, "GeometryNodeTree")) {
*r_disabled_hint = TIP_("Not a geometry node tree");
diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh
index efb7efaf1cc..adcf47f57fe 100644
--- a/source/blender/nodes/geometry/node_geometry_util.hh
+++ b/source/blender/nodes/geometry/node_geometry_util.hh
@@ -20,8 +20,12 @@
#include "NOD_socket_declarations.hh"
#include "NOD_socket_declarations_geometry.hh"
+#include "RNA_access.h"
+
#include "node_util.h"
+struct BVHTreeFromMesh;
+
void geo_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass);
bool geo_node_poll_default(struct bNodeType *ntype,
struct bNodeTree *ntree,
@@ -34,7 +38,8 @@ void transform_mesh(Mesh &mesh,
const float3 rotation,
const float3 scale);
-void transform_geometry_set(GeometrySet &geometry,
+void transform_geometry_set(GeoNodeExecParams &params,
+ GeometrySet &geometry,
const float4x4 &transform,
const Depsgraph &depsgraph);
@@ -75,7 +80,34 @@ void separate_geometry(GeometrySet &geometry_set,
const Field<bool> &selection_field,
bool &r_is_error);
+void get_closest_in_bvhtree(BVHTreeFromMesh &tree_data,
+ const VArray<float3> &positions,
+ const IndexMask mask,
+ const MutableSpan<int> r_indices,
+ const MutableSpan<float> r_distances_sq,
+ const MutableSpan<float3> r_positions);
+
+int apply_offset_in_cyclic_range(IndexRange range, int start_index, int offset);
+
std::optional<eCustomDataType> node_data_type_to_custom_data_type(eNodeSocketDatatype type);
std::optional<eCustomDataType> node_socket_to_custom_data_type(const bNodeSocket &socket);
+class FieldAtIndexInput final : public bke::GeometryFieldInput {
+ private:
+ Field<int> index_field_;
+ GField value_field_;
+ eAttrDomain value_field_domain_;
+
+ public:
+ FieldAtIndexInput(Field<int> index_field, GField value_field, eAttrDomain value_field_domain);
+
+ GVArray get_varray_for_context(const bke::GeometryFieldContext &context,
+ const IndexMask mask) const final;
+
+ std::optional<eAttrDomain> preferred_domain(const GeometryComponent & /*component*/) const final
+ {
+ return value_field_domain_;
+ }
+};
+
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc b/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc
index 58fbfb5a000..9af445090e9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc
@@ -70,13 +70,13 @@ static void node_declare(NodeDeclarationBuilder &b)
.description(N_(total_out_description));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeAccumulateField *data = MEM_cnew<NodeAccumulateField>(__func__);
data->data_type = CD_PROP_FLOAT;
@@ -87,13 +87,13 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeAccumulateField &storage = node_storage(*node);
- const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
+ const eCustomDataType data_type = eCustomDataType(storage.data_type);
- bNodeSocket *sock_in_vector = (bNodeSocket *)node->inputs.first;
+ bNodeSocket *sock_in_vector = static_cast<bNodeSocket *>(node->inputs.first);
bNodeSocket *sock_in_float = sock_in_vector->next;
bNodeSocket *sock_in_int = sock_in_float->next;
- bNodeSocket *sock_out_vector = (bNodeSocket *)node->outputs.first;
+ bNodeSocket *sock_out_vector = static_cast<bNodeSocket *>(node->outputs.first);
bNodeSocket *sock_out_float = sock_out_vector->next;
bNodeSocket *sock_out_int = sock_out_float->next;
@@ -192,7 +192,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
}
}
-template<typename T> class AccumulateFieldInput final : public GeometryFieldInput {
+template<typename T> class AccumulateFieldInput final : public bke::GeometryFieldInput {
private:
Field<T> input_;
Field<int> group_index_;
@@ -204,7 +204,7 @@ template<typename T> class AccumulateFieldInput final : public GeometryFieldInpu
Field<T> input,
Field<int> group_index,
AccumulationMode accumulation_mode)
- : GeometryFieldInput(CPPType::get<T>(), "Accumulation"),
+ : bke::GeometryFieldInput(CPPType::get<T>(), "Accumulation"),
input_(input),
group_index_(group_index),
source_domain_(source_domain),
@@ -212,18 +212,18 @@ template<typename T> class AccumulateFieldInput final : public GeometryFieldInpu
{
}
- GVArray get_varray_for_context(const GeometryComponent &component,
- const eAttrDomain domain,
- IndexMask UNUSED(mask)) const final
+ GVArray get_varray_for_context(const bke::GeometryFieldContext &context,
+ const IndexMask /*mask*/) const final
{
- const GeometryComponentFieldContext field_context{component, source_domain_};
- const int domain_size = component.attribute_domain_size(field_context.domain());
+ const AttributeAccessor attributes = *context.attributes();
+ const int domain_size = attributes.domain_size(source_domain_);
if (domain_size == 0) {
return {};
}
- const AttributeAccessor attributes = *component.attributes();
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ const bke::GeometryFieldContext source_context{
+ context.geometry(), context.type(), source_domain_};
+ fn::FieldEvaluator evaluator{source_context, domain_size};
evaluator.add(input_);
evaluator.add(group_index_);
evaluator.evaluate();
@@ -266,7 +266,7 @@ template<typename T> class AccumulateFieldInput final : public GeometryFieldInpu
}
return attributes.adapt_domain<T>(
- VArray<T>::ForContainer(std::move(accumulations_out)), source_domain_, domain);
+ VArray<T>::ForContainer(std::move(accumulations_out)), source_domain_, context.domain());
}
uint64_t hash() const override
@@ -285,9 +285,15 @@ template<typename T> class AccumulateFieldInput final : public GeometryFieldInpu
}
return false;
}
+
+ std::optional<eAttrDomain> preferred_domain(
+ const GeometryComponent & /*component*/) const override
+ {
+ return source_domain_;
+ }
};
-template<typename T> class TotalFieldInput final : public GeometryFieldInput {
+template<typename T> class TotalFieldInput final : public bke::GeometryFieldInput {
private:
Field<T> input_;
Field<int> group_index_;
@@ -295,25 +301,25 @@ template<typename T> class TotalFieldInput final : public GeometryFieldInput {
public:
TotalFieldInput(const eAttrDomain source_domain, Field<T> input, Field<int> group_index)
- : GeometryFieldInput(CPPType::get<T>(), "Total Value"),
+ : bke::GeometryFieldInput(CPPType::get<T>(), "Total Value"),
input_(input),
group_index_(group_index),
source_domain_(source_domain)
{
}
- GVArray get_varray_for_context(const GeometryComponent &component,
- const eAttrDomain domain,
- IndexMask UNUSED(mask)) const final
+ GVArray get_varray_for_context(const bke::GeometryFieldContext &context,
+ IndexMask /*mask*/) const final
{
- const GeometryComponentFieldContext field_context{component, source_domain_};
- const int domain_size = component.attribute_domain_size(field_context.domain());
+ const AttributeAccessor attributes = *context.attributes();
+ const int domain_size = attributes.domain_size(source_domain_);
if (domain_size == 0) {
return {};
}
- const AttributeAccessor attributes = *component.attributes();
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ const bke::GeometryFieldContext source_context{
+ context.geometry(), context.type(), source_domain_};
+ fn::FieldEvaluator evaluator{source_context, domain_size};
evaluator.add(input_);
evaluator.add(group_index_);
evaluator.evaluate();
@@ -339,7 +345,7 @@ template<typename T> class TotalFieldInput final : public GeometryFieldInput {
}
return attributes.adapt_domain<T>(
- VArray<T>::ForContainer(std::move(accumulations_out)), source_domain_, domain);
+ VArray<T>::ForContainer(std::move(accumulations_out)), source_domain_, context.domain());
}
uint64_t hash() const override
@@ -355,6 +361,12 @@ template<typename T> class TotalFieldInput final : public GeometryFieldInput {
}
return false;
}
+
+ std::optional<eAttrDomain> preferred_domain(
+ const GeometryComponent & /*component*/) const override
+ {
+ return source_domain_;
+ }
};
template<typename T> std::string identifier_suffix()
@@ -373,8 +385,8 @@ template<typename T> std::string identifier_suffix()
static void node_geo_exec(GeoNodeExecParams params)
{
const NodeAccumulateField &storage = node_storage(params.node());
- const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
- const eAttrDomain source_domain = static_cast<eAttrDomain>(storage.domain);
+ const eCustomDataType data_type = eCustomDataType(storage.data_type);
+ const eAttrDomain source_domain = eAttrDomain(storage.domain);
Field<int> group_index_field = params.extract_input<Field<int>>("Group Index");
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
index 9f317075bb5..1aea129bd53 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
@@ -30,7 +30,7 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Int>(N_("Attribute"), "Attribute_004").field_source();
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -38,7 +38,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryAttributeCapture *data = MEM_cnew<NodeGeometryAttributeCapture>(__func__);
data->data_type = CD_PROP_FLOAT;
@@ -50,9 +50,9 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeGeometryAttributeCapture &storage = node_storage(*node);
- const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
+ const eCustomDataType data_type = eCustomDataType(storage.data_type);
- bNodeSocket *socket_value_geometry = (bNodeSocket *)node->inputs.first;
+ bNodeSocket *socket_value_geometry = static_cast<bNodeSocket *>(node->inputs.first);
bNodeSocket *socket_value_vector = socket_value_geometry->next;
bNodeSocket *socket_value_float = socket_value_vector->next;
bNodeSocket *socket_value_color4f = socket_value_float->next;
@@ -65,7 +65,7 @@ static void node_update(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, socket_value_boolean, data_type == CD_PROP_BOOL);
nodeSetSocketAvailability(ntree, socket_value_int32, data_type == CD_PROP_INT32);
- bNodeSocket *out_socket_value_geometry = (bNodeSocket *)node->outputs.first;
+ bNodeSocket *out_socket_value_geometry = static_cast<bNodeSocket *>(node->outputs.first);
bNodeSocket *out_socket_value_vector = out_socket_value_geometry->next;
bNodeSocket *out_socket_value_float = out_socket_value_vector->next;
bNodeSocket *out_socket_value_color4f = out_socket_value_float->next;
@@ -106,33 +106,6 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
}
}
-static void try_capture_field_on_geometry(GeometryComponent &component,
- const AttributeIDRef &attribute_id,
- const eAttrDomain domain,
- const GField &field)
-{
- const int domain_size = component.attribute_domain_size(domain);
- if (domain_size == 0) {
- return;
- }
- GeometryComponentFieldContext field_context{component, domain};
- MutableAttributeAccessor attributes = *component.attributes_for_write();
- const IndexMask mask{IndexMask(domain_size)};
-
- const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(field.cpp_type());
- GAttributeWriter output_attribute = attributes.lookup_or_add_for_write(
- attribute_id, domain, data_type);
- if (!output_attribute) {
- return;
- }
-
- fn::FieldEvaluator evaluator{field_context, &mask};
- evaluator.add_with_destination(field, output_attribute.varray);
- evaluator.evaluate();
-
- output_attribute.finish();
-}
-
static StringRefNull identifier_suffix(eCustomDataType data_type)
{
switch (data_type) {
@@ -165,8 +138,8 @@ static void node_geo_exec(GeoNodeExecParams params)
}
const NodeGeometryAttributeCapture &storage = node_storage(params.node());
- const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
- const eAttrDomain domain = static_cast<eAttrDomain>(storage.domain);
+ const eCustomDataType data_type = eCustomDataType(storage.data_type);
+ const eAttrDomain domain = eAttrDomain(storage.domain);
const std::string output_identifier = "Attribute" + identifier_suffix(data_type);
@@ -206,7 +179,7 @@ static void node_geo_exec(GeoNodeExecParams params)
if (geometry_set.has_instances()) {
GeometryComponent &component = geometry_set.get_component_for_write(
GEO_COMPONENT_TYPE_INSTANCES);
- try_capture_field_on_geometry(component, anonymous_id.get(), domain, field);
+ bke::try_capture_field_on_geometry(component, anonymous_id.get(), domain, field);
}
}
else {
@@ -217,7 +190,7 @@ static void node_geo_exec(GeoNodeExecParams params)
for (const GeometryComponentType type : types) {
if (geometry_set.has(type)) {
GeometryComponent &component = geometry_set.get_component_for_write(type);
- try_capture_field_on_geometry(component, anonymous_id.get(), domain, field);
+ bke::try_capture_field_on_geometry(component, anonymous_id.get(), domain, field);
}
}
});
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc
index f6ea6073459..af55ef3f7ed 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc
@@ -30,19 +30,19 @@ static void node_declare(NodeDeclarationBuilder &b)
});
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "component", 0, "", ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
node->custom1 = GEO_COMPONENT_TYPE_MESH;
}
static void node_update(bNodeTree *ntree, bNode *node)
{
- bNodeSocket *point_socket = (bNodeSocket *)node->outputs.first;
+ bNodeSocket *point_socket = static_cast<bNodeSocket *>(node->outputs.first);
bNodeSocket *edge_socket = point_socket->next;
bNodeSocket *face_socket = edge_socket->next;
bNodeSocket *face_corner_socket = face_socket->next;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
index 34e28e50c81..3023c7bd751 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
@@ -40,13 +40,13 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Vector>(N_("Variance"), "Variance_001");
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
node->custom1 = CD_PROP_FLOAT;
node->custom2 = ATTR_DOMAIN_POINT;
@@ -54,12 +54,12 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
{
- bNodeSocket *socket_geo = (bNodeSocket *)node->inputs.first;
+ bNodeSocket *socket_geo = static_cast<bNodeSocket *>(node->inputs.first);
bNodeSocket *socket_selection = socket_geo->next;
bNodeSocket *socket_float_attr = socket_selection->next;
bNodeSocket *socket_float3_attr = socket_float_attr->next;
- bNodeSocket *socket_float_mean = (bNodeSocket *)node->outputs.first;
+ bNodeSocket *socket_float_mean = static_cast<bNodeSocket *>(node->outputs.first);
bNodeSocket *socket_float_median = socket_float_mean->next;
bNodeSocket *socket_float_sum = socket_float_median->next;
bNodeSocket *socket_float_min = socket_float_sum->next;
@@ -77,7 +77,7 @@ static void node_update(bNodeTree *ntree, bNode *node)
bNodeSocket *socket_vector_std = socket_vector_range->next;
bNodeSocket *socket_vector_variance = socket_vector_std->next;
- const eCustomDataType data_type = static_cast<eCustomDataType>(node->custom1);
+ const eCustomDataType data_type = eCustomDataType(node->custom1);
nodeSetSocketAvailability(ntree, socket_float_attr, data_type == CD_PROP_FLOAT);
nodeSetSocketAvailability(ntree, socket_float_mean, data_type == CD_PROP_FLOAT);
@@ -184,8 +184,8 @@ static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.get_input<GeometrySet>("Geometry");
const bNode &node = params.node();
- const eCustomDataType data_type = static_cast<eCustomDataType>(node.custom1);
- const eAttrDomain domain = static_cast<eAttrDomain>(node.custom2);
+ const eCustomDataType data_type = eCustomDataType(node.custom1);
+ const eAttrDomain domain = eAttrDomain(node.custom2);
Vector<const GeometryComponent *> components = geometry_set.get_components_for_read();
const Field<bool> selection_field = params.get_input<Field<bool>>("Selection");
@@ -200,7 +200,7 @@ static void node_geo_exec(GeoNodeExecParams params)
continue;
}
if (attributes->domain_supported(domain)) {
- GeometryComponentFieldContext field_context{*component, domain};
+ bke::GeometryFieldContext field_context{*component, domain};
const int domain_num = attributes->domain_size(domain);
fn::FieldEvaluator data_evaluator{field_context, domain_num};
@@ -282,7 +282,7 @@ static void node_geo_exec(GeoNodeExecParams params)
continue;
}
if (attributes->domain_supported(domain)) {
- GeometryComponentFieldContext field_context{*component, domain};
+ bke::GeometryFieldContext field_context{*component, domain};
const int domain_num = attributes->domain_size(domain);
fn::FieldEvaluator data_evaluator{field_context, domain_num};
diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
index 69938f3e447..094aab65653 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
@@ -24,7 +24,7 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Bool>(N_("Intersecting Edges")).field_source();
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
}
@@ -37,7 +37,7 @@ static void node_update(bNodeTree *ntree, bNode *node)
{
GeometryNodeBooleanOperation operation = (GeometryNodeBooleanOperation)node->custom1;
- bNodeSocket *geometry_1_socket = (bNodeSocket *)node->inputs.first;
+ bNodeSocket *geometry_1_socket = static_cast<bNodeSocket *>(node->inputs.first);
bNodeSocket *geometry_2_socket = geometry_1_socket->next;
switch (operation) {
@@ -55,7 +55,7 @@ static void node_update(bNodeTree *ntree, bNode *node)
}
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
node->custom1 = GEO_NODE_BOOLEAN_DIFFERENCE;
}
@@ -93,7 +93,7 @@ static void node_geo_exec(GeoNodeExecParams params)
/* The instance transform matrices are owned by the instance group, so we have to
* keep all of them around for use during the boolean operation. */
Vector<bke::GeometryInstanceGroup> set_groups;
- Vector<GeometrySet> geometry_sets = params.extract_multi_input<GeometrySet>("Mesh 2");
+ Vector<GeometrySet> geometry_sets = params.extract_input<Vector<GeometrySet>>("Mesh 2");
for (const GeometrySet &geometry_set : geometry_sets) {
bke::geometry_set_gather_instances(geometry_set, set_groups);
}
@@ -148,13 +148,14 @@ static void node_geo_exec(GeoNodeExecParams params)
}
MEM_SAFE_FREE(result->mat);
- result->mat = (Material **)MEM_malloc_arrayN(materials.size(), sizeof(Material *), __func__);
+ result->mat = static_cast<Material **>(
+ MEM_malloc_arrayN(materials.size(), sizeof(Material *), __func__));
result->totcol = materials.size();
MutableSpan(result->mat, result->totcol).copy_from(materials);
/* Store intersecting edges in attribute. */
if (attribute_outputs.intersecting_edges_id) {
- MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*result);
+ MutableAttributeAccessor attributes = result->attributes_for_write();
SpanAttributeWriter<bool> selection = attributes.lookup_or_add_for_write_only_span<bool>(
attribute_outputs.intersecting_edges_id.get(), ATTR_DOMAIN_EDGE);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
index 54a061993a3..df677e1c399 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
@@ -8,6 +8,7 @@
#include "UI_resources.h"
#include "BKE_collection.h"
+#include "BKE_instances.hh"
#include "node_geometry_util.hh"
@@ -30,12 +31,12 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "transform_space", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void node_node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryCollectionInfo *data = MEM_cnew<NodeGeometryCollectionInfo>(__func__);
data->transform_space = GEO_NODE_TRANSFORM_SPACE_ORIGINAL;
@@ -57,8 +58,8 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
const Object *self_object = params.self_object();
- const bool is_recursive = BKE_collection_has_object_recursive_instanced(collection,
- (Object *)self_object);
+ const bool is_recursive = BKE_collection_has_object_recursive_instanced(
+ collection, const_cast<Object *>(self_object));
if (is_recursive) {
params.error_message_add(NodeWarningType::Error, "Collection contains current object");
params.set_default_remaining_outputs();
@@ -69,8 +70,7 @@ static void node_geo_exec(GeoNodeExecParams params)
const bool use_relative_transform = (storage.transform_space ==
GEO_NODE_TRANSFORM_SPACE_RELATIVE);
- GeometrySet geometry_set_out;
- InstancesComponent &instances = geometry_set_out.get_component_for_write<InstancesComponent>();
+ std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>();
const bool separate_children = params.get_input<bool>("Separate Children");
if (separate_children) {
@@ -84,7 +84,7 @@ static void node_geo_exec(GeoNodeExecParams params)
children_objects.append(collection_object->ob);
}
- instances.reserve(children_collections.size() + children_objects.size());
+ instances->reserve(children_collections.size() + children_objects.size());
Vector<InstanceListEntry> entries;
entries.reserve(children_collections.size() + children_objects.size());
@@ -99,11 +99,11 @@ static void node_geo_exec(GeoNodeExecParams params)
sub_v3_v3(transform.values[3], collection->instance_offset);
}
}
- const int handle = instances.add_reference(*child_collection);
+ const int handle = instances->add_reference(*child_collection);
entries.append({handle, &(child_collection->id.name[2]), transform});
}
for (Object *child_object : children_objects) {
- const int handle = instances.add_reference(*child_object);
+ const int handle = instances->add_reference(*child_object);
float4x4 transform = float4x4::identity();
if (!reset_children) {
if (use_relative_transform) {
@@ -123,7 +123,7 @@ static void node_geo_exec(GeoNodeExecParams params)
return BLI_strcasecmp_natural(a.name, b.name) < 0;
});
for (const InstanceListEntry &entry : entries) {
- instances.add_instance(entry.handle, entry.transform);
+ instances->add_instance(entry.handle, entry.transform);
}
}
else {
@@ -133,11 +133,11 @@ static void node_geo_exec(GeoNodeExecParams params)
mul_m4_m4_pre(transform.values, self_object->imat);
}
- const int handle = instances.add_reference(*collection);
- instances.add_instance(handle, transform);
+ const int handle = instances->add_reference(*collection);
+ instances->add_instance(handle, transform);
}
- params.set_output("Geometry", geometry_set_out);
+ params.set_output("Geometry", GeometrySet::create_with_instances(instances.release()));
}
} // namespace blender::nodes::node_geo_collection_info_cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
index 03892501c89..038309785fb 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
@@ -46,6 +46,7 @@ static Mesh *hull_from_bullet(const Mesh *mesh, Span<float3> coords)
}
/* Copy vertices. */
+ MutableSpan<MVert> dst_verts = result->verts_for_write();
for (const int i : IndexRange(verts_num)) {
float co[3];
int original_index;
@@ -55,11 +56,11 @@ static Mesh *hull_from_bullet(const Mesh *mesh, Span<float3> coords)
# if 0 /* Disabled because it only works for meshes, not predictable enough. */
/* Copy custom data on vertices, like vertex groups etc. */
if (mesh && original_index < mesh->totvert) {
- CustomData_copy_data(&mesh->vdata, &result->vdata, (int)original_index, (int)i, 1);
+ CustomData_copy_data(&mesh->vdata, &result->vdata, int(original_index), int(i), 1);
}
# endif
/* Copy the position of the original point. */
- copy_v3_v3(result->mvert[i].co, co);
+ copy_v3_v3(dst_verts[i].co, co);
}
else {
BLI_assert_msg(0, "Unexpected new vertex in hull output");
@@ -73,15 +74,17 @@ static Mesh *hull_from_bullet(const Mesh *mesh, Span<float3> coords)
* to a loop and edges need to be created from that. */
Array<MLoop> mloop_src(loops_num);
uint edge_index = 0;
+ MutableSpan<MEdge> edges = result->edges_for_write();
+
for (const int i : IndexRange(loops_num)) {
int v_from;
int v_to;
plConvexHullGetLoop(hull, i, &v_from, &v_to);
- mloop_src[i].v = (uint)v_from;
+ mloop_src[i].v = uint(v_from);
/* Add edges for ascending order loops only. */
if (v_from < v_to) {
- MEdge &edge = result->medge[edge_index];
+ MEdge &edge = edges[edge_index];
edge.v1 = v_from;
edge.v2 = v_to;
edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
@@ -95,7 +98,7 @@ static Mesh *hull_from_bullet(const Mesh *mesh, Span<float3> coords)
}
if (edges_num == 1) {
/* In this case there are no loops. */
- MEdge &edge = result->medge[0];
+ MEdge &edge = edges[0];
edge.v1 = 0;
edge.v2 = 1;
edge.flag |= ME_EDGEDRAW | ME_EDGERENDER | ME_LOOSEEDGE;
@@ -106,7 +109,10 @@ static Mesh *hull_from_bullet(const Mesh *mesh, Span<float3> coords)
/* Copy faces. */
Array<int> loops;
int j = 0;
- MLoop *loop = result->mloop;
+ MutableSpan<MPoly> polys = result->polys_for_write();
+ MutableSpan<MLoop> mesh_loops = result->loops_for_write();
+ MLoop *loop = mesh_loops.data();
+
for (const int i : IndexRange(faces_num)) {
const int len = plConvexHullGetFaceSize(hull, i);
@@ -116,7 +122,7 @@ static Mesh *hull_from_bullet(const Mesh *mesh, Span<float3> coords)
loops.reinitialize(len);
plConvexHullGetFaceLoops(hull, i, loops.data());
- MPoly &face = result->mpoly[i];
+ MPoly &face = polys[i];
face.loopstart = j;
face.totloop = len;
for (const int k : IndexRange(len)) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
index db3f108aad5..4161ec7e7ad 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
@@ -27,39 +27,31 @@ static void node_declare(NodeDeclarationBuilder &b)
N_("The selection from the start and end of the splines based on the input sizes"));
}
-class EndpointFieldInput final : public GeometryFieldInput {
+class EndpointFieldInput final : public bke::CurvesFieldInput {
Field<int> start_size_;
Field<int> end_size_;
public:
EndpointFieldInput(Field<int> start_size, Field<int> end_size)
- : GeometryFieldInput(CPPType::get<bool>(), "Endpoint Selection node"),
+ : bke::CurvesFieldInput(CPPType::get<bool>(), "Endpoint Selection node"),
start_size_(start_size),
end_size_(end_size)
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
+ GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
const eAttrDomain domain,
- IndexMask UNUSED(mask)) const final
+ const IndexMask /*mask*/) const final
{
- if (component.type() != GEO_COMPONENT_TYPE_CURVE || domain != ATTR_DOMAIN_POINT) {
- return nullptr;
+ if (domain != ATTR_DOMAIN_POINT) {
+ return {};
}
-
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- if (!curve_component.has_curves()) {
- return nullptr;
- }
-
- const Curves &curves_id = *curve_component.get_for_read();
- const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
if (curves.points_num() == 0) {
- return nullptr;
+ return {};
}
- GeometryComponentFieldContext size_context{curve_component, ATTR_DOMAIN_CURVE};
+ bke::CurvesFieldContext size_context{curves, ATTR_DOMAIN_CURVE};
fn::FieldEvaluator evaluator{size_context, curves.curves_num()};
evaluator.add(start_size_);
evaluator.add(end_size_);
@@ -72,12 +64,12 @@ class EndpointFieldInput final : public GeometryFieldInput {
devirtualize_varray2(start_size, end_size, [&](const auto &start_size, const auto &end_size) {
threading::parallel_for(curves.curves_range(), 1024, [&](IndexRange curves_range) {
for (const int i : curves_range) {
- const IndexRange range = curves.points_for_curve(i);
+ const IndexRange points = curves.points_for_curve(i);
const int start = std::max(start_size[i], 0);
const int end = std::max(end_size[i], 0);
- selection_span.slice(range.take_front(start)).fill(true);
- selection_span.slice(range.take_back(end)).fill(true);
+ selection_span.slice(points.take_front(start)).fill(true);
+ selection_span.slice(points.take_back(end)).fill(true);
}
});
});
@@ -98,6 +90,11 @@ class EndpointFieldInput final : public GeometryFieldInput {
}
return false;
}
+
+ std::optional<eAttrDomain> preferred_domain(const CurvesGeometry & /*curves*/) const
+ {
+ return ATTR_DOMAIN_POINT;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
index c9a8dba55b2..6eaa40bff03 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
@@ -27,12 +27,12 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryCurveFill *data = MEM_cnew<NodeGeometryCurveFill>(__func__);
@@ -79,13 +79,13 @@ static Mesh *cdt_to_mesh(const meshintersect::CDT_result<double> &result)
}
Mesh *mesh = BKE_mesh_new_nomain(vert_len, edge_len, 0, loop_len, poly_len);
- MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
- MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
- MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop};
- MutableSpan<MPoly> polys{mesh->mpoly, mesh->totpoly};
+ MutableSpan<MVert> verts = mesh->verts_for_write();
+ MutableSpan<MEdge> edges = mesh->edges_for_write();
+ MutableSpan<MPoly> polys = mesh->polys_for_write();
+ MutableSpan<MLoop> loops = mesh->loops_for_write();
for (const int i : IndexRange(result.vert.size())) {
- copy_v3_v3(verts[i].co, float3((float)result.vert[i].x, (float)result.vert[i].y, 0.0f));
+ copy_v3_v3(verts[i].co, float3(float(result.vert[i].x), float(result.vert[i].y), 0.0f));
}
for (const int i : IndexRange(result.edge.size())) {
edges[i].v1 = result.edge[i].first;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
index ab1f8269c39..2b24b6cbf42 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
@@ -32,12 +32,12 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryCurveFillet *data = MEM_cnew<NodeGeometryCurveFillet>(__func__);
data->mode = GEO_NODE_CURVE_FILLET_BEZIER;
@@ -48,7 +48,7 @@ static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeGeometryCurveFillet &storage = node_storage(*node);
const GeometryNodeCurveFilletMode mode = (GeometryNodeCurveFilletMode)storage.mode;
- bNodeSocket *poly_socket = ((bNodeSocket *)node->inputs.first)->next;
+ bNodeSocket *poly_socket = static_cast<bNodeSocket *>(node->inputs.first)->next;
nodeSetSocketAvailability(ntree, poly_socket, mode == GEO_NODE_CURVE_FILLET_POLY);
}
@@ -72,10 +72,9 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
- const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
- const Curves &curves_id = *component.get_for_read();
+ const Curves &curves_id = *geometry_set.get_curves_for_read();
const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
- GeometryComponentFieldContext context{component, ATTR_DOMAIN_POINT};
+ bke::CurvesFieldContext context{curves, ATTR_DOMAIN_POINT};
fn::FieldEvaluator evaluator{context, curves.points_num()};
evaluator.add(radius_field);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
index 5ef20f03f28..252f66c308f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
@@ -16,13 +16,13 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Bool>(N_("Selection")).field_source();
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryCurveSelectHandles *data = MEM_cnew<NodeGeometryCurveSelectHandles>(__func__);
@@ -70,41 +70,34 @@ static void select_by_handle_type(const bke::CurvesGeometry &curves,
}
}
-class HandleTypeFieldInput final : public GeometryFieldInput {
+class HandleTypeFieldInput final : public bke::CurvesFieldInput {
HandleType type_;
GeometryNodeCurveHandleMode mode_;
public:
HandleTypeFieldInput(HandleType type, GeometryNodeCurveHandleMode mode)
- : GeometryFieldInput(CPPType::get<bool>(), "Handle Type Selection node"),
+ : bke::CurvesFieldInput(CPPType::get<bool>(), "Handle Type Selection node"),
type_(type),
mode_(mode)
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
+ GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
const eAttrDomain domain,
IndexMask mask) const final
{
- if (component.type() != GEO_COMPONENT_TYPE_CURVE || domain != ATTR_DOMAIN_POINT) {
+ if (domain != ATTR_DOMAIN_POINT) {
return {};
}
-
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- const Curves *curves_id = curve_component.get_for_read();
- if (curves_id == nullptr) {
- return {};
- }
-
Array<bool> selection(mask.min_array_size());
- select_by_handle_type(bke::CurvesGeometry::wrap(curves_id->geometry), type_, mode_, selection);
+ select_by_handle_type(curves, type_, mode_, selection);
return VArray<bool>::ForContainer(std::move(selection));
}
uint64_t hash() const override
{
- return get_default_hash_2((int)mode_, (int)type_);
+ return get_default_hash_2(int(mode_), int(type_));
}
bool is_equal_to(const fn::FieldNode &other) const override
@@ -115,6 +108,11 @@ class HandleTypeFieldInput final : public GeometryFieldInput {
}
return false;
}
+
+ std::optional<eAttrDomain> preferred_domain(const CurvesGeometry & /*curves*/) const
+ {
+ return ATTR_DOMAIN_POINT;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc
index ba8c9a893c2..cc32c8f5efc 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc
@@ -88,12 +88,12 @@ static void node_declare(NodeDeclarationBuilder &b)
.make_available(enable_points);
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryCurvePrimitiveArc *data = MEM_cnew<NodeGeometryCurvePrimitiveArc>(__func__);
@@ -106,7 +106,7 @@ static void node_update(bNodeTree *ntree, bNode *node)
const NodeGeometryCurvePrimitiveArc &storage = node_storage(*node);
const GeometryNodeCurvePrimitiveArcMode mode = (GeometryNodeCurvePrimitiveArcMode)storage.mode;
- bNodeSocket *start_socket = ((bNodeSocket *)node->inputs.first)->next;
+ bNodeSocket *start_socket = static_cast<bNodeSocket *>(node->inputs.first)->next;
bNodeSocket *middle_socket = start_socket->next;
bNodeSocket *end_socket = middle_socket->next;
@@ -116,7 +116,7 @@ static void node_update(bNodeTree *ntree, bNode *node)
bNodeSocket *offset_angle_socket = sweep_angle_socket->next;
- bNodeSocket *center_out_socket = ((bNodeSocket *)node->outputs.first)->next;
+ bNodeSocket *center_out_socket = static_cast<bNodeSocket *>(node->outputs.first)->next;
bNodeSocket *normal_out_socket = center_out_socket->next;
bNodeSocket *radius_out_socket = normal_out_socket->next;
@@ -151,7 +151,7 @@ static bool colinear_f3_f3_f3(const float3 p1, const float3 p2, const float3 p3)
{
const float3 a = math::normalize(p2 - p1);
const float3 b = math::normalize(p3 - p1);
- return (ELEM(a, b, b * -1.0f));
+ return ELEM(a, b, b * -1.0f);
}
static Curves *create_arc_curve_from_points(const int resolution,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
index 875664c41fa..b407ac47dc9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
@@ -41,12 +41,12 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryCurvePrimitiveBezierSegment *data =
MEM_cnew<NodeGeometryCurvePrimitiveBezierSegment>(__func__);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
index c33ba3e2a4c..35fdd6754cc 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
@@ -56,12 +56,12 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Vector>(N_("Center")).make_available(endable_points);
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryCurvePrimitiveCircle *data = MEM_cnew<NodeGeometryCurvePrimitiveCircle>(__func__);
@@ -75,12 +75,12 @@ static void node_update(bNodeTree *ntree, bNode *node)
const GeometryNodeCurvePrimitiveCircleMode mode = (GeometryNodeCurvePrimitiveCircleMode)
storage.mode;
- bNodeSocket *start_socket = ((bNodeSocket *)node->inputs.first)->next;
+ bNodeSocket *start_socket = static_cast<bNodeSocket *>(node->inputs.first)->next;
bNodeSocket *middle_socket = start_socket->next;
bNodeSocket *end_socket = middle_socket->next;
bNodeSocket *radius_socket = end_socket->next;
- bNodeSocket *center_socket = ((bNodeSocket *)node->outputs.first)->next;
+ bNodeSocket *center_socket = static_cast<bNodeSocket *>(node->outputs.first)->next;
nodeSetSocketAvailability(
ntree, start_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS);
@@ -98,7 +98,7 @@ static bool colinear_f3_f3_f3(const float3 p1, const float3 p2, const float3 p3)
{
const float3 a = math::normalize(p2 - p1);
const float3 b = math::normalize(p3 - p1);
- return (ELEM(a, b, b * -1.0f));
+ return ELEM(a, b, b * -1.0f);
}
static Curves *create_point_circle_curve(
@@ -144,7 +144,7 @@ static Curves *create_point_circle_curve(
/* Get the radius from the center-point to p1. */
const float r = math::distance(p1, center);
- const float theta_step = ((2 * M_PI) / (float)resolution);
+ const float theta_step = ((2 * M_PI) / float(resolution));
for (const int i : IndexRange(resolution)) {
/* Formula for a circle around a point and 2 unit vectors perpendicular
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
index 4cfa606d8eb..6b402a67450 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
@@ -39,12 +39,12 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryCurvePrimitiveLine *data = MEM_cnew<NodeGeometryCurvePrimitiveLine>(__func__);
@@ -57,7 +57,7 @@ static void node_update(bNodeTree *ntree, bNode *node)
const NodeGeometryCurvePrimitiveLine &storage = node_storage(*node);
const GeometryNodeCurvePrimitiveLineMode mode = (GeometryNodeCurvePrimitiveLineMode)storage.mode;
- bNodeSocket *p2_socket = ((bNodeSocket *)node->inputs.first)->next;
+ bNodeSocket *p2_socket = static_cast<bNodeSocket *>(node->inputs.first)->next;
bNodeSocket *direction_socket = p2_socket->next;
bNodeSocket *length_socket = direction_socket->next;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
index fec4e31701f..44c2a078cb6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
@@ -68,12 +68,12 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryCurvePrimitiveQuad *data = MEM_cnew<NodeGeometryCurvePrimitiveQuad>(__func__);
data->mode = GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE;
@@ -83,10 +83,9 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeGeometryCurvePrimitiveQuad &storage = node_storage(*node);
- GeometryNodeCurvePrimitiveQuadMode mode = static_cast<GeometryNodeCurvePrimitiveQuadMode>(
- storage.mode);
+ GeometryNodeCurvePrimitiveQuadMode mode = GeometryNodeCurvePrimitiveQuadMode(storage.mode);
- bNodeSocket *width = ((bNodeSocket *)node->inputs.first);
+ bNodeSocket *width = static_cast<bNodeSocket *>(node->inputs.first);
bNodeSocket *height = width->next;
bNodeSocket *bottom = height->next;
bNodeSocket *top = bottom->next;
@@ -140,7 +139,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
search_link_ops_for_declarations(params, declaration.outputs());
}
else if (params.node_tree().typeinfo->validate_link(
- static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_FLOAT)) {
+ eNodeSocketDatatype(params.other_socket().type), SOCK_FLOAT)) {
params.add_item(IFACE_("Width"),
SocketSearchOp{"Width", GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE});
params.add_item(IFACE_("Height"),
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
index 4aaf57d57cb..66284fe77db 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
@@ -43,9 +43,9 @@ static Curves *create_spiral_curve(const float rotations,
const bool direction)
{
const int totalpoints = std::max(int(resolution * rotations), 1);
- const float delta_radius = (end_radius - start_radius) / (float)totalpoints;
- const float delta_height = height / (float)totalpoints;
- const float delta_theta = (M_PI * 2 * rotations) / (float)totalpoints *
+ const float delta_radius = (end_radius - start_radius) / float(totalpoints);
+ const float delta_height = height / float(totalpoints);
+ const float delta_theta = (M_PI * 2 * rotations) / float(totalpoints) *
(direction ? 1.0f : -1.0f);
Curves *curves_id = bke::curves_new_nomain_single(totalpoints + 1, CURVE_TYPE_POLY);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
index 37fc6823b9a..8b6a7064362 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
@@ -26,12 +26,12 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryCurveResample *data = MEM_cnew<NodeGeometryCurveResample>(__func__);
@@ -44,7 +44,7 @@ static void node_update(bNodeTree *ntree, bNode *node)
const NodeGeometryCurveResample &storage = node_storage(*node);
const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)storage.mode;
- bNodeSocket *count_socket = ((bNodeSocket *)node->inputs.first)->next->next;
+ bNodeSocket *count_socket = static_cast<bNodeSocket *>(node->inputs.first)->next->next;
bNodeSocket *length_socket = count_socket->next;
nodeSetSocketAvailability(ntree, count_socket, mode == GEO_NODE_CURVE_RESAMPLE_COUNT);
@@ -66,12 +66,14 @@ static void node_geo_exec(GeoNodeExecParams params)
case GEO_NODE_CURVE_RESAMPLE_COUNT: {
Field<int> count = params.extract_input<Field<int>>("Count");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
- if (const CurveComponent *component = geometry.get_component_for_read<CurveComponent>()) {
- if (const Curves *src_curves = component->get_for_read()) {
- Curves *dst_curves = geometry::resample_to_count(*component, selection, count);
- bke::curves_copy_parameters(*src_curves, *dst_curves);
- geometry.replace_curves(dst_curves);
- }
+ if (const Curves *src_curves_id = geometry.get_curves_for_read()) {
+ const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(
+ src_curves_id->geometry);
+ bke::CurvesGeometry dst_curves = geometry::resample_to_count(
+ src_curves, selection, count);
+ Curves *dst_curves_id = bke::curves_new_nomain(std::move(dst_curves));
+ bke::curves_copy_parameters(*src_curves_id, *dst_curves_id);
+ geometry.replace_curves(dst_curves_id);
}
});
break;
@@ -79,24 +81,27 @@ static void node_geo_exec(GeoNodeExecParams params)
case GEO_NODE_CURVE_RESAMPLE_LENGTH: {
Field<float> length = params.extract_input<Field<float>>("Length");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
- if (const CurveComponent *component = geometry.get_component_for_read<CurveComponent>()) {
- if (const Curves *src_curves = component->get_for_read()) {
- Curves *dst_curves = geometry::resample_to_length(*component, selection, length);
- bke::curves_copy_parameters(*src_curves, *dst_curves);
- geometry.replace_curves(dst_curves);
- }
+ if (const Curves *src_curves_id = geometry.get_curves_for_read()) {
+ const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(
+ src_curves_id->geometry);
+ bke::CurvesGeometry dst_curves = geometry::resample_to_length(
+ src_curves, selection, length);
+ Curves *dst_curves_id = bke::curves_new_nomain(std::move(dst_curves));
+ bke::curves_copy_parameters(*src_curves_id, *dst_curves_id);
+ geometry.replace_curves(dst_curves_id);
}
});
break;
}
case GEO_NODE_CURVE_RESAMPLE_EVALUATED:
geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
- if (const CurveComponent *component = geometry.get_component_for_read<CurveComponent>()) {
- if (const Curves *src_curves = component->get_for_read()) {
- Curves *dst_curves = geometry::resample_to_evaluated(*component, selection);
- bke::curves_copy_parameters(*src_curves, *dst_curves);
- geometry.replace_curves(dst_curves);
- }
+ if (const Curves *src_curves_id = geometry.get_curves_for_read()) {
+ const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(
+ src_curves_id->geometry);
+ bke::CurvesGeometry dst_curves = geometry::resample_to_evaluated(src_curves, selection);
+ Curves *dst_curves_id = bke::curves_new_nomain(std::move(dst_curves));
+ bke::curves_copy_parameters(*src_curves_id, *dst_curves_id);
+ geometry.replace_curves(dst_curves_id);
}
});
break;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
index de29735bd2d..0169ead5bd2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
@@ -23,14 +23,12 @@ static void node_geo_exec(GeoNodeExecParams params)
if (!geometry_set.has_curves()) {
return;
}
+ const Curves &src_curves_id = *geometry_set.get_curves_for_read();
+ const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(src_curves_id.geometry);
- Field<bool> selection_field = params.get_input<Field<bool>>("Selection");
- const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
-
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
+ bke::CurvesFieldContext field_context{src_curves, ATTR_DOMAIN_CURVE};
+ fn::FieldEvaluator selection_evaluator{field_context, src_curves.curves_num()};
+ selection_evaluator.add(params.get_input<Field<bool>>("Selection"));
selection_evaluator.evaluate();
const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
if (selection.is_empty()) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
index e80b600a740..27e111822bf 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
@@ -35,12 +35,12 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Vector>(N_("Normal")).dependent_field();
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void node_type_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_type_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryCurveSample *data = MEM_cnew<NodeGeometryCurveSample>(__func__);
data->mode = GEO_NODE_CURVE_SAMPLE_LENGTH;
@@ -52,7 +52,7 @@ static void node_update(bNodeTree *ntree, bNode *node)
const NodeGeometryCurveSample &storage = node_storage(*node);
const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)storage.mode;
- bNodeSocket *factor = ((bNodeSocket *)node->inputs.first)->next;
+ bNodeSocket *factor = static_cast<bNodeSocket *>(node->inputs.first)->next;
bNodeSocket *length = factor->next;
nodeSetSocketAvailability(ntree, factor, mode == GEO_NODE_CURVE_SAMPLE_FACTOR);
@@ -134,7 +134,7 @@ class SampleFloatSegmentsFunction : public fn::MultiFunction {
return signature.build();
}
- void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext /*context*/) const override
{
const VArraySpan<float> lengths = params.readonly_single_input<float>(0, "Length");
MutableSpan<int> indices = params.uninitialized_single_output<int>(1, "Curve Index");
@@ -172,7 +172,7 @@ class SampleCurveFunction : public fn::MultiFunction {
return signature.build();
}
- void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext /*context*/) const override
{
MutableSpan<float3> sampled_positions = params.uninitialized_single_output_if_required<float3>(
2, "Position");
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handle_type.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handle_type.cc
index f7ba724c377..d37af6e5fe8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handle_type.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handle_type.cc
@@ -20,13 +20,13 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryCurveSetHandles *data = MEM_cnew<NodeGeometryCurveSetHandles>(__func__);
@@ -51,15 +51,12 @@ static HandleType handle_type_from_input_type(GeometryNodeCurveHandleType type)
return BEZIER_HANDLE_AUTO;
}
-static void set_type_in_component(CurveComponent &component,
- const GeometryNodeCurveHandleMode mode,
- const HandleType new_handle_type,
- const Field<bool> &selection_field)
+static void set_handle_type(bke::CurvesGeometry &curves,
+ const GeometryNodeCurveHandleMode mode,
+ const HandleType new_handle_type,
+ const Field<bool> &selection_field)
{
- Curves &curves_id = *component.get_for_write();
- bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
-
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
+ bke::CurvesFieldContext field_context{curves, ATTR_DOMAIN_POINT};
fn::FieldEvaluator evaluator{field_context, curves.points_num()};
evaluator.set_selection(selection_field);
evaluator.evaluate();
@@ -93,21 +90,17 @@ static void node_geo_exec(GeoNodeExecParams params)
std::atomic<bool> has_bezier = false;
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (!geometry_set.has_curves()) {
- return;
- }
- has_curves = true;
- const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
- const AttributeAccessor attributes = *component.attributes();
- if (!attributes.contains("handle_type_left") || !attributes.contains("handle_type_right")) {
- return;
+ if (Curves *curves_id = geometry_set.get_curves_for_write()) {
+ bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
+ has_curves = true;
+ const AttributeAccessor attributes = curves.attributes();
+ if (!attributes.contains("handle_type_left") || !attributes.contains("handle_type_right")) {
+ return;
+ }
+ has_bezier = true;
+
+ set_handle_type(curves, mode, new_handle_type, selection_field);
}
- has_bezier = true;
-
- set_type_in_component(geometry_set.get_component_for_write<CurveComponent>(),
- mode,
- new_handle_type,
- selection_field);
});
if (has_curves && !has_bezier) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
index b98541e3446..3dc89a9058e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
@@ -106,7 +106,7 @@ static Array<float> curve_length_point_domain(const bke::CurvesGeometry &curves)
}
static VArray<float> construct_curve_parameter_varray(const bke::CurvesGeometry &curves,
- const IndexMask UNUSED(mask),
+ const IndexMask /*mask*/,
const eAttrDomain domain)
{
VArray<bool> cyclic = curves.cyclic();
@@ -126,6 +126,10 @@ static VArray<float> construct_curve_parameter_varray(const bke::CurvesGeometry
value *= factor;
}
}
+ else if (curve_lengths.size() == 1) {
+ /* The curve is a single point. */
+ curve_lengths[0] = 0.0f;
+ }
else {
/* It is arbitrary what to do in those rare cases when all the points are
* in the same position. In this case we are just arbitrarily giving a valid
@@ -143,8 +147,8 @@ static VArray<float> construct_curve_parameter_varray(const bke::CurvesGeometry
Array<float> lengths = accumulated_lengths_curve_domain(curves);
const int last_index = curves.curves_num() - 1;
- const int total_length = lengths.last() + curves.evaluated_length_total_for_curve(
- last_index, cyclic[last_index]);
+ const float total_length = lengths.last() + curves.evaluated_length_total_for_curve(
+ last_index, cyclic[last_index]);
if (total_length > 0.0f) {
const float factor = 1.0f / total_length;
for (float &value : lengths) {
@@ -165,7 +169,7 @@ static VArray<float> construct_curve_parameter_varray(const bke::CurvesGeometry
}
static VArray<float> construct_curve_length_parameter_varray(const bke::CurvesGeometry &curves,
- const IndexMask UNUSED(mask),
+ const IndexMask /*mask*/,
const eAttrDomain domain)
{
curves.ensure_evaluated_lengths();
@@ -184,7 +188,7 @@ static VArray<float> construct_curve_length_parameter_varray(const bke::CurvesGe
}
static VArray<int> construct_index_on_spline_varray(const bke::CurvesGeometry &curves,
- const IndexMask UNUSED(mask),
+ const IndexMask /*mask*/,
const eAttrDomain domain)
{
if (domain == ATTR_DOMAIN_POINT) {
@@ -203,26 +207,18 @@ static VArray<int> construct_index_on_spline_varray(const bke::CurvesGeometry &c
return {};
}
-class CurveParameterFieldInput final : public GeometryFieldInput {
+class CurveParameterFieldInput final : public bke::CurvesFieldInput {
public:
- CurveParameterFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Curve Parameter node")
+ CurveParameterFieldInput() : bke::CurvesFieldInput(CPPType::get<float>(), "Curve Parameter node")
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
+ GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
const eAttrDomain domain,
IndexMask mask) const final
{
- if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- if (curve_component.has_curves()) {
- const Curves &curves_id = *curve_component.get_for_read();
- const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
- return construct_curve_parameter_varray(curves, mask, domain);
- }
- }
- return {};
+ return construct_curve_parameter_varray(curves, mask, domain);
}
uint64_t hash() const override
@@ -237,26 +233,19 @@ class CurveParameterFieldInput final : public GeometryFieldInput {
}
};
-class CurveLengthParameterFieldInput final : public GeometryFieldInput {
+class CurveLengthParameterFieldInput final : public bke::CurvesFieldInput {
public:
- CurveLengthParameterFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Curve Length node")
+ CurveLengthParameterFieldInput()
+ : bke::CurvesFieldInput(CPPType::get<float>(), "Curve Length node")
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
+ GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
const eAttrDomain domain,
IndexMask mask) const final
{
- if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- if (curve_component.has_curves()) {
- const Curves &curves_id = *curve_component.get_for_read();
- const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
- return construct_curve_length_parameter_varray(curves, mask, domain);
- }
- }
- return {};
+ return construct_curve_length_parameter_varray(curves, mask, domain);
}
uint64_t hash() const override
@@ -271,26 +260,18 @@ class CurveLengthParameterFieldInput final : public GeometryFieldInput {
}
};
-class IndexOnSplineFieldInput final : public GeometryFieldInput {
+class IndexOnSplineFieldInput final : public bke::CurvesFieldInput {
public:
- IndexOnSplineFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Spline Index")
+ IndexOnSplineFieldInput() : bke::CurvesFieldInput(CPPType::get<int>(), "Spline Index")
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
+ GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
const eAttrDomain domain,
IndexMask mask) const final
{
- if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- if (curve_component.has_curves()) {
- const Curves &curves_id = *curve_component.get_for_read();
- const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
- return construct_index_on_spline_varray(curves, mask, domain);
- }
- }
- return {};
+ return construct_index_on_spline_varray(curves, mask, domain);
}
uint64_t hash() const override
@@ -303,6 +284,11 @@ class IndexOnSplineFieldInput final : public GeometryFieldInput {
{
return dynamic_cast<const IndexOnSplineFieldInput *>(&other) != nullptr;
}
+
+ std::optional<eAttrDomain> preferred_domain(const CurvesGeometry & /*curves*/) const
+ {
+ return ATTR_DOMAIN_POINT;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
index a92479bc5f1..9ac6516ee7b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
@@ -20,12 +20,12 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "spline_type", 0, "", ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryCurveSplineType *data = MEM_cnew<NodeGeometryCurveSplineType>(__func__);
@@ -45,14 +45,13 @@ static void node_geo_exec(GeoNodeExecParams params)
if (!geometry_set.has_curves()) {
return;
}
- const CurveComponent &src_component = *geometry_set.get_component_for_read<CurveComponent>();
- const Curves &src_curves_id = *src_component.get_for_read();
+ const Curves &src_curves_id = *geometry_set.get_curves_for_read();
const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(src_curves_id.geometry);
if (src_curves.is_single_type(dst_type)) {
return;
}
- GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_CURVE};
+ bke::CurvesFieldContext field_context{src_curves, ATTR_DOMAIN_CURVE};
fn::FieldEvaluator evaluator{field_context, src_curves.curves_num()};
evaluator.set_selection(selection_field);
evaluator.evaluate();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
index bd44adb35a2..5a1d2461c72 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
@@ -29,16 +29,17 @@ static void node_geo_exec(GeoNodeExecParams params)
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
Field<int> cuts_field = params.extract_input<Field<int>>("Cuts");
+ GeometryComponentEditData::remember_deformed_curve_positions_if_necessary(geometry_set);
+
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
if (!geometry_set.has_curves()) {
return;
}
- const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
- const Curves &src_curves_id = *component.get_for_read();
+ const Curves &src_curves_id = *geometry_set.get_curves_for_read();
const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(src_curves_id.geometry);
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
+ bke::CurvesFieldContext field_context{src_curves, ATTR_DOMAIN_POINT};
fn::FieldEvaluator evaluator{field_context, src_curves.points_num()};
evaluator.add(cuts_field);
evaluator.evaluate();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
index 0ddf06dc8c7..e9eaa00b02d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
@@ -4,8 +4,11 @@
#include "BLI_task.hh"
#include "BLI_timeit.hh"
+#include "DNA_pointcloud_types.h"
+
#include "BKE_pointcloud.h"
-#include "BKE_spline.hh"
+
+#include "GEO_resample_curves.hh"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -37,12 +40,12 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Vector>(N_("Rotation")).field_source();
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryCurveToPoints *data = MEM_cnew<NodeGeometryCurveToPoints>(__func__);
@@ -55,16 +58,16 @@ static void node_update(bNodeTree *ntree, bNode *node)
const NodeGeometryCurveToPoints &storage = node_storage(*node);
const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)storage.mode;
- bNodeSocket *count_socket = ((bNodeSocket *)node->inputs.first)->next;
+ bNodeSocket *count_socket = static_cast<bNodeSocket *>(node->inputs.first)->next;
bNodeSocket *length_socket = count_socket->next;
nodeSetSocketAvailability(ntree, count_socket, mode == GEO_NODE_CURVE_RESAMPLE_COUNT);
nodeSetSocketAvailability(ntree, length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH);
}
-static void curve_create_default_rotation_attribute(Span<float3> tangents,
- Span<float3> normals,
- MutableSpan<float3> rotations)
+static void fill_rotation_attribute(const Span<float3> tangents,
+ const Span<float3> normals,
+ MutableSpan<float3> rotations)
{
threading::parallel_for(IndexRange(rotations.size()), 512, [&](IndexRange range) {
for (const int i : range) {
@@ -74,239 +77,30 @@ static void curve_create_default_rotation_attribute(Span<float3> tangents,
});
}
-static Array<int> calculate_spline_point_offsets(GeoNodeExecParams &params,
- const GeometryNodeCurveResampleMode mode,
- const CurveEval &curve,
- const Span<SplinePtr> splines)
-{
- const int size = curve.splines().size();
- switch (mode) {
- case GEO_NODE_CURVE_RESAMPLE_COUNT: {
- const int count = params.get_input<int>("Count");
- if (count < 1) {
- return {0};
- }
- Array<int> offsets(size + 1);
- int offset = 0;
- for (const int i : IndexRange(size)) {
- offsets[i] = offset;
- if (splines[i]->evaluated_points_num() > 0) {
- offset += count;
- }
- }
- offsets.last() = offset;
- return offsets;
- }
- case GEO_NODE_CURVE_RESAMPLE_LENGTH: {
- /* Don't allow asymptotic count increase for low resolution values. */
- const float resolution = std::max(params.get_input<float>("Length"), 0.0001f);
- Array<int> offsets(size + 1);
- int offset = 0;
- for (const int i : IndexRange(size)) {
- offsets[i] = offset;
- if (splines[i]->evaluated_points_num() > 0) {
- offset += splines[i]->length() / resolution + 1;
- }
- }
- offsets.last() = offset;
- return offsets;
- }
- case GEO_NODE_CURVE_RESAMPLE_EVALUATED: {
- return curve.evaluated_point_offsets();
- }
- }
- BLI_assert_unreachable();
- return {0};
-}
-
-/**
- * \note Relies on the fact that all attributes on point clouds are stored contiguously.
- */
-static GMutableSpan ensure_point_attribute(PointCloudComponent &points,
- const AttributeIDRef &attribute_id,
- const eCustomDataType data_type)
-{
- GAttributeWriter attribute = points.attributes_for_write()->lookup_or_add_for_write(
- attribute_id, ATTR_DOMAIN_POINT, data_type);
- GMutableSpan span = attribute.varray.get_internal_span();
- attribute.finish();
- return span;
-}
-
-template<typename T>
-static MutableSpan<T> ensure_point_attribute(PointCloudComponent &points,
- const AttributeIDRef &attribute_id)
-{
- AttributeWriter<T> attribute = points.attributes_for_write()->lookup_or_add_for_write<T>(
- attribute_id, ATTR_DOMAIN_POINT);
- MutableSpan<T> span = attribute.varray.get_internal_span();
- attribute.finish();
- return span;
-}
-
-namespace {
-struct AnonymousAttributeIDs {
- StrongAnonymousAttributeID tangent_id;
- StrongAnonymousAttributeID normal_id;
- StrongAnonymousAttributeID rotation_id;
-};
-
-struct ResultAttributes {
- MutableSpan<float3> positions;
- MutableSpan<float> radii;
-
- Map<AttributeIDRef, GMutableSpan> point_attributes;
-
- MutableSpan<float3> tangents;
- MutableSpan<float3> normals;
- MutableSpan<float3> rotations;
-};
-} // namespace
-
-static ResultAttributes create_attributes_for_transfer(PointCloudComponent &points,
- const CurveEval &curve,
- const AnonymousAttributeIDs &attributes)
+static PointCloud *pointcloud_from_curves(bke::CurvesGeometry curves,
+ const AttributeIDRef &tangent_id,
+ const AttributeIDRef &normal_id,
+ const AttributeIDRef &rotation_id)
{
- ResultAttributes outputs;
-
- outputs.positions = ensure_point_attribute<float3>(points, "position");
- outputs.radii = ensure_point_attribute<float>(points, "radius");
-
- if (attributes.tangent_id) {
- outputs.tangents = ensure_point_attribute<float3>(points, attributes.tangent_id.get());
- }
- if (attributes.normal_id) {
- outputs.normals = ensure_point_attribute<float3>(points, attributes.normal_id.get());
- }
- if (attributes.rotation_id) {
- outputs.rotations = ensure_point_attribute<float3>(points, attributes.rotation_id.get());
+ PointCloud *pointcloud = BKE_pointcloud_new_nomain(0);
+ pointcloud->totpoint = curves.points_num();
+
+ if (rotation_id) {
+ MutableAttributeAccessor attributes = curves.attributes_for_write();
+ const VArraySpan<float3> tangents = attributes.lookup<float3>(tangent_id, ATTR_DOMAIN_POINT);
+ const VArraySpan<float3> normals = attributes.lookup<float3>(normal_id, ATTR_DOMAIN_POINT);
+ SpanAttributeWriter<float3> rotations = attributes.lookup_or_add_for_write_only_span<float3>(
+ rotation_id, ATTR_DOMAIN_POINT);
+ fill_rotation_attribute(tangents, normals, rotations.span);
+ rotations.finish();
}
- /* Because of the invariants of the curve component, we use the attributes of the first spline
- * as a representative for the attribute meta data all splines. Attributes from the spline domain
- * are handled separately. */
- curve.splines().first()->attributes.foreach_attribute(
- [&](const AttributeIDRef &id, const AttributeMetaData &meta_data) {
- if (id.should_be_kept()) {
- outputs.point_attributes.add_new(
- id, ensure_point_attribute(points, id, meta_data.data_type));
- }
- return true;
- },
- ATTR_DOMAIN_POINT);
-
- return outputs;
-}
-
-/**
- * TODO: For non-poly splines, this has double copies that could be avoided as part
- * of a general look at optimizing uses of #Spline::interpolate_to_evaluated.
- */
-static void copy_evaluated_point_attributes(const Span<SplinePtr> splines,
- const Span<int> offsets,
- ResultAttributes &data)
-{
- threading::parallel_for(splines.index_range(), 64, [&](IndexRange range) {
- for (const int i : range) {
- const Spline &spline = *splines[i];
- const int offset = offsets[i];
- const int size = offsets[i + 1] - offsets[i];
-
- data.positions.slice(offset, size).copy_from(spline.evaluated_positions());
- spline.interpolate_to_evaluated(spline.radii()).materialize(data.radii.slice(offset, size));
+ /* Move the curve point custom data to the pointcloud, to avoid any copying. */
+ CustomData_free(&pointcloud->pdata, pointcloud->totpoint);
+ pointcloud->pdata = curves.point_data;
+ CustomData_reset(&curves.point_data);
- for (const Map<AttributeIDRef, GMutableSpan>::Item item : data.point_attributes.items()) {
- const AttributeIDRef attribute_id = item.key;
- const GMutableSpan dst = item.value;
-
- BLI_assert(spline.attributes.get_for_read(attribute_id));
- GSpan spline_span = *spline.attributes.get_for_read(attribute_id);
-
- spline.interpolate_to_evaluated(spline_span).materialize(dst.slice(offset, size).data());
- }
-
- if (!data.tangents.is_empty()) {
- data.tangents.slice(offset, size).copy_from(spline.evaluated_tangents());
- }
- if (!data.normals.is_empty()) {
- data.normals.slice(offset, size).copy_from(spline.evaluated_normals());
- }
- }
- });
-}
-
-static void copy_uniform_sample_point_attributes(const Span<SplinePtr> splines,
- const Span<int> offsets,
- ResultAttributes &data)
-{
- threading::parallel_for(splines.index_range(), 64, [&](IndexRange range) {
- for (const int i : range) {
- const Spline &spline = *splines[i];
- const int offset = offsets[i];
- const int num = offsets[i + 1] - offsets[i];
- if (num == 0) {
- continue;
- }
-
- const Array<float> uniform_samples = spline.sample_uniform_index_factors(num);
-
- spline.sample_with_index_factors<float3>(
- spline.evaluated_positions(), uniform_samples, data.positions.slice(offset, num));
- spline.sample_with_index_factors<float>(spline.interpolate_to_evaluated(spline.radii()),
- uniform_samples,
- data.radii.slice(offset, num));
-
- for (const Map<AttributeIDRef, GMutableSpan>::Item item : data.point_attributes.items()) {
- const AttributeIDRef attribute_id = item.key;
- const GMutableSpan dst = item.value;
-
- BLI_assert(spline.attributes.get_for_read(attribute_id));
- GSpan spline_span = *spline.attributes.get_for_read(attribute_id);
-
- spline.sample_with_index_factors(
- spline.interpolate_to_evaluated(spline_span), uniform_samples, dst.slice(offset, num));
- }
-
- if (!data.tangents.is_empty()) {
- Span<float3> src_tangents = spline.evaluated_tangents();
- MutableSpan<float3> sampled_tangents = data.tangents.slice(offset, num);
- spline.sample_with_index_factors<float3>(src_tangents, uniform_samples, sampled_tangents);
- for (float3 &vector : sampled_tangents) {
- vector = math::normalize(vector);
- }
- }
-
- if (!data.normals.is_empty()) {
- Span<float3> src_normals = spline.evaluated_normals();
- MutableSpan<float3> sampled_normals = data.normals.slice(offset, num);
- spline.sample_with_index_factors<float3>(src_normals, uniform_samples, sampled_normals);
- for (float3 &vector : sampled_normals) {
- vector = math::normalize(vector);
- }
- }
- }
- });
-}
-
-static void copy_spline_domain_attributes(const CurveEval &curve,
- const Span<int> offsets,
- PointCloudComponent &points)
-{
- curve.attributes.foreach_attribute(
- [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
- const GSpan curve_attribute = *curve.attributes.get_for_read(attribute_id);
- const CPPType &type = curve_attribute.type();
- const GMutableSpan dst = ensure_point_attribute(points, attribute_id, meta_data.data_type);
-
- for (const int i : curve.splines().index_range()) {
- const int offset = offsets[i];
- const int num = offsets[i + 1] - offsets[i];
- type.fill_assign_n(curve_attribute[i], dst[offset], num);
- }
-
- return true;
- },
- ATTR_DOMAIN_CURVE);
+ return pointcloud;
}
static void node_geo_exec(GeoNodeExecParams params)
@@ -315,73 +109,96 @@ static void node_geo_exec(GeoNodeExecParams params)
const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)storage.mode;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
- AnonymousAttributeIDs attribute_outputs;
- attribute_outputs.tangent_id = StrongAnonymousAttributeID("Tangent");
- attribute_outputs.normal_id = StrongAnonymousAttributeID("Normal");
- attribute_outputs.rotation_id = StrongAnonymousAttributeID("Rotation");
-
GeometryComponentEditData::remember_deformed_curve_positions_if_necessary(geometry_set);
- geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (!geometry_set.has_curves()) {
- geometry_set.remove_geometry_during_modify();
- return;
- }
- const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
- *geometry_set.get_curves_for_read());
- const Span<SplinePtr> splines = curve->splines();
- curve->assert_valid_point_attributes();
-
- const Array<int> offsets = calculate_spline_point_offsets(params, mode, *curve, splines);
- const int total_num = offsets.last();
- if (total_num == 0) {
- geometry_set.remove_geometry_during_modify();
- return;
- }
+ StrongAnonymousAttributeID tangent_anonymous_id;
+ StrongAnonymousAttributeID normal_anonymous_id;
+ StrongAnonymousAttributeID rotation_anonymous_id;
+ const bool rotation_required = params.output_is_required("Rotation");
+ if (params.output_is_required("Tangent") || rotation_required) {
+ tangent_anonymous_id = StrongAnonymousAttributeID("Tangent");
+ }
+ if (params.output_is_required("Normal") || rotation_required) {
+ normal_anonymous_id = StrongAnonymousAttributeID("Normal");
+ }
+ if (rotation_required) {
+ rotation_anonymous_id = StrongAnonymousAttributeID("Rotation");
+ }
- geometry_set.replace_pointcloud(BKE_pointcloud_new_nomain(total_num));
- PointCloudComponent &points = geometry_set.get_component_for_write<PointCloudComponent>();
- ResultAttributes point_attributes = create_attributes_for_transfer(
- points, *curve, attribute_outputs);
+ geometry::ResampleCurvesOutputAttributeIDs resample_attributes;
+ resample_attributes.tangent_id = tangent_anonymous_id.get();
+ resample_attributes.normal_id = normal_anonymous_id.get();
- switch (mode) {
- case GEO_NODE_CURVE_RESAMPLE_COUNT:
- case GEO_NODE_CURVE_RESAMPLE_LENGTH:
- copy_uniform_sample_point_attributes(splines, offsets, point_attributes);
- break;
- case GEO_NODE_CURVE_RESAMPLE_EVALUATED:
- copy_evaluated_point_attributes(splines, offsets, point_attributes);
- break;
+ switch (mode) {
+ case GEO_NODE_CURVE_RESAMPLE_COUNT: {
+ Field<int> count = params.extract_input<Field<int>>("Count");
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
+ if (const Curves *src_curves_id = geometry.get_curves_for_read()) {
+ const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(
+ src_curves_id->geometry);
+ bke::CurvesGeometry dst_curves = geometry::resample_to_count(
+ src_curves, fn::make_constant_field<bool>(true), count, resample_attributes);
+ PointCloud *pointcloud = pointcloud_from_curves(std::move(dst_curves),
+ resample_attributes.tangent_id,
+ resample_attributes.normal_id,
+ rotation_anonymous_id.get());
+ geometry.remove_geometry_during_modify();
+ geometry.replace_pointcloud(pointcloud);
+ }
+ });
+ break;
}
-
- copy_spline_domain_attributes(*curve, offsets, points);
-
- if (!point_attributes.rotations.is_empty()) {
- curve_create_default_rotation_attribute(
- point_attributes.tangents, point_attributes.normals, point_attributes.rotations);
+ case GEO_NODE_CURVE_RESAMPLE_LENGTH: {
+ Field<float> length = params.extract_input<Field<float>>("Length");
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
+ if (const Curves *src_curves_id = geometry.get_curves_for_read()) {
+ const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(
+ src_curves_id->geometry);
+ bke::CurvesGeometry dst_curves = geometry::resample_to_length(
+ src_curves, fn::make_constant_field<bool>(true), length, resample_attributes);
+ PointCloud *pointcloud = pointcloud_from_curves(std::move(dst_curves),
+ resample_attributes.tangent_id,
+ resample_attributes.normal_id,
+ rotation_anonymous_id.get());
+ geometry.remove_geometry_during_modify();
+ geometry.replace_pointcloud(pointcloud);
+ }
+ });
+ break;
}
-
- geometry_set.keep_only_during_modify({GEO_COMPONENT_TYPE_POINT_CLOUD});
- });
+ case GEO_NODE_CURVE_RESAMPLE_EVALUATED:
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
+ if (const Curves *src_curves_id = geometry.get_curves_for_read()) {
+ const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(
+ src_curves_id->geometry);
+ bke::CurvesGeometry dst_curves = geometry::resample_to_evaluated(
+ src_curves, fn::make_constant_field<bool>(true), resample_attributes);
+ PointCloud *pointcloud = pointcloud_from_curves(std::move(dst_curves),
+ resample_attributes.tangent_id,
+ resample_attributes.normal_id,
+ rotation_anonymous_id.get());
+ geometry.remove_geometry_during_modify();
+ geometry.replace_pointcloud(pointcloud);
+ }
+ });
+ break;
+ }
params.set_output("Points", std::move(geometry_set));
- if (attribute_outputs.tangent_id) {
- params.set_output(
- "Tangent",
- AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.tangent_id),
- params.attribute_producer_name()));
+ if (tangent_anonymous_id) {
+ params.set_output("Tangent",
+ AnonymousAttributeFieldInput::Create<float3>(
+ std::move(tangent_anonymous_id), params.attribute_producer_name()));
}
- if (attribute_outputs.normal_id) {
- params.set_output(
- "Normal",
- AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.normal_id),
- params.attribute_producer_name()));
+ if (normal_anonymous_id) {
+ params.set_output("Normal",
+ AnonymousAttributeFieldInput::Create<float3>(
+ std::move(normal_anonymous_id), params.attribute_producer_name()));
}
- if (attribute_outputs.rotation_id) {
- params.set_output(
- "Rotation",
- AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.rotation_id),
- params.attribute_producer_name()));
+ if (rotation_anonymous_id) {
+ params.set_output("Rotation",
+ AnonymousAttributeFieldInput::Create<float3>(
+ std::move(rotation_anonymous_id), params.attribute_producer_name()));
}
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_topology_curve_of_point.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_topology_curve_of_point.cc
new file mode 100644
index 00000000000..4d60ab939ca
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_topology_curve_of_point.cc
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_curves.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_curve_topology_curve_of_point_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Int>(N_("Point Index"))
+ .implicit_field(implicit_field_inputs::index)
+ .description(N_("The control point to retrieve data from"));
+ b.add_output<decl::Int>(N_("Curve Index"))
+ .dependent_field()
+ .description(N_("The curve the control point is part of"));
+ b.add_output<decl::Int>(N_("Index in Curve"))
+ .dependent_field()
+ .description(N_("How far along the control point is along its curve"));
+}
+
+class CurveOfPointInput final : public bke::CurvesFieldInput {
+ public:
+ CurveOfPointInput() : bke::CurvesFieldInput(CPPType::get<int>(), "Point Curve Index")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
+ const eAttrDomain domain,
+ const IndexMask /*mask*/) const final
+ {
+ if (domain != ATTR_DOMAIN_POINT) {
+ return {};
+ }
+ return VArray<int>::ForContainer(curves.point_to_curve_map());
+ }
+
+ uint64_t hash() const override
+ {
+ return 413209687345908697;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ if (dynamic_cast<const CurveOfPointInput *>(&other)) {
+ return true;
+ }
+ return false;
+ }
+};
+
+class PointIndexInCurveInput final : public bke::CurvesFieldInput {
+ public:
+ PointIndexInCurveInput() : bke::CurvesFieldInput(CPPType::get<int>(), "Point Index in Curve")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
+ const eAttrDomain domain,
+ const IndexMask /*mask*/) const final
+ {
+ if (domain != ATTR_DOMAIN_POINT) {
+ return {};
+ }
+ const Span<int> offsets = curves.offsets();
+ Array<int> point_to_curve_map = curves.point_to_curve_map();
+ return VArray<int>::ForFunc(
+ curves.points_num(),
+ [offsets, point_to_curve_map = std::move(point_to_curve_map)](const int point_i) {
+ const int curve_i = point_to_curve_map[point_i];
+ return point_i - offsets[curve_i];
+ });
+ }
+
+ uint64_t hash() const final
+ {
+ return 9834765987345677;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const final
+ {
+ if (dynamic_cast<const PointIndexInCurveInput *>(&other)) {
+ return true;
+ }
+ return false;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const Field<int> point_index = params.extract_input<Field<int>>("Point Index");
+ if (params.output_is_required("Curve Index")) {
+ params.set_output(
+ "Curve Index",
+ Field<int>(std::make_shared<FieldAtIndexInput>(
+ point_index, Field<int>(std::make_shared<CurveOfPointInput>()), ATTR_DOMAIN_POINT)));
+ }
+ if (params.output_is_required("Index in Curve")) {
+ params.set_output("Index in Curve",
+ Field<int>(std::make_shared<FieldAtIndexInput>(
+ point_index,
+ Field<int>(std::make_shared<PointIndexInCurveInput>()),
+ ATTR_DOMAIN_POINT)));
+ }
+}
+
+} // namespace blender::nodes::node_geo_curve_topology_curve_of_point_cc
+
+void register_node_type_geo_curve_topology_curve_of_point()
+{
+ namespace file_ns = blender::nodes::node_geo_curve_topology_curve_of_point_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_CURVE_TOPOLOGY_CURVE_OF_POINT, "Curve of Point", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_topology_points_of_curve.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_topology_points_of_curve.cc
new file mode 100644
index 00000000000..9f3d3c2caf3
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_topology_points_of_curve.cc
@@ -0,0 +1,182 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_curves.hh"
+
+#include "BLI_task.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_curve_topology_points_of_curve_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Int>(N_("Curve Index"))
+ .implicit_field(implicit_field_inputs::index)
+ .description(N_("The curve to retrieve data from. Defaults to the curve from the context"));
+ b.add_input<decl::Float>(N_("Weights"))
+ .supports_field()
+ .hide_value()
+ .description(N_("Values used to sort the curve's points. Uses indices by default"));
+ b.add_input<decl::Int>(N_("Sort Index"))
+ .min(0)
+ .supports_field()
+ .description(N_("Which of the sorted points to output"));
+ b.add_output<decl::Int>(N_("Point Index"))
+ .dependent_field()
+ .description(N_("A point of the curve, chosen by the sort index"));
+ b.add_output<decl::Int>(N_("Total"))
+ .dependent_field()
+ .description(N_("The number of points in the curve"));
+}
+
+class PointsOfCurveInput final : public bke::CurvesFieldInput {
+ const Field<int> curve_index_;
+ const Field<int> sort_index_;
+ const Field<float> sort_weight_;
+
+ public:
+ PointsOfCurveInput(Field<int> curve_index, Field<int> sort_index, Field<float> sort_weight)
+ : bke::CurvesFieldInput(CPPType::get<int>(), "Point of Curve"),
+ curve_index_(std::move(curve_index)),
+ sort_index_(std::move(sort_index)),
+ sort_weight_(std::move(sort_weight))
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
+ const eAttrDomain domain,
+ const IndexMask mask) const final
+ {
+ const bke::CurvesFieldContext context{curves, domain};
+ fn::FieldEvaluator evaluator{context, &mask};
+ evaluator.add(curve_index_);
+ evaluator.add(sort_index_);
+ evaluator.evaluate();
+ const VArray<int> curve_indices = evaluator.get_evaluated<int>(0);
+ const VArray<int> indices_in_sort = evaluator.get_evaluated<int>(1);
+
+ const bke::CurvesFieldContext point_context{curves, ATTR_DOMAIN_POINT};
+ fn::FieldEvaluator point_evaluator{point_context, curves.points_num()};
+ point_evaluator.add(sort_weight_);
+ point_evaluator.evaluate();
+ const VArray<float> all_sort_weights = point_evaluator.get_evaluated<float>(0);
+
+ Array<int> point_of_curve(mask.min_array_size());
+ threading::parallel_for(mask.index_range(), 256, [&](const IndexRange range) {
+ /* Reuse arrays to avoid allocation. */
+ Array<float> sort_weights;
+ Array<int> sort_indices;
+
+ for (const int selection_i : mask.slice(range)) {
+ const int curve_i = curve_indices[selection_i];
+ const int index_in_sort = indices_in_sort[selection_i];
+ if (!curves.curves_range().contains(curve_i)) {
+ point_of_curve[selection_i] = 0;
+ continue;
+ }
+
+ const IndexRange points = curves.points_for_curve(curve_i);
+
+ /* Retrieve the weights for each point. */
+ sort_weights.reinitialize(points.size());
+ all_sort_weights.materialize_compressed(IndexMask(points), sort_weights.as_mutable_span());
+
+ /* Sort a separate array of compressed indices corresponding to the compressed weights.
+ * This allows using `materialize_compressed` to avoid virtual function call overhead
+ * when accessing values in the sort weights. However, it means a separate array of
+ * indices within the compressed array is necessary for sorting. */
+ sort_indices.reinitialize(points.size());
+ std::iota(sort_indices.begin(), sort_indices.end(), 0);
+ std::stable_sort(sort_indices.begin(), sort_indices.end(), [&](int a, int b) {
+ return sort_weights[a] < sort_weights[b];
+ });
+
+ const int index_in_sort_wrapped = mod_i(index_in_sort, points.size());
+ point_of_curve[selection_i] = points[sort_indices[index_in_sort_wrapped]];
+ }
+ });
+
+ return VArray<int>::ForContainer(std::move(point_of_curve));
+ }
+
+ uint64_t hash() const override
+ {
+ return 26978695677882;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ if (const auto *typed = dynamic_cast<const PointsOfCurveInput *>(&other)) {
+ return typed->curve_index_ == curve_index_ && typed->sort_index_ == sort_index_ &&
+ typed->sort_weight_ == sort_weight_;
+ }
+ return false;
+ }
+};
+
+class CurvePointCountInput final : public bke::CurvesFieldInput {
+ public:
+ CurvePointCountInput() : bke::CurvesFieldInput(CPPType::get<int>(), "Curve Point Count")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
+ const eAttrDomain domain,
+ const IndexMask /*mask*/) const final
+ {
+ if (domain != ATTR_DOMAIN_CURVE) {
+ return {};
+ }
+ return VArray<int>::ForFunc(curves.curves_num(), [&, curves](const int64_t curve_i) {
+ return curves.points_num_for_curve(curve_i);
+ });
+ }
+
+ uint64_t hash() const final
+ {
+ return 903847569873762;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const final
+ {
+ if (dynamic_cast<const CurvePointCountInput *>(&other)) {
+ return true;
+ }
+ return false;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const Field<int> curve_index = params.extract_input<Field<int>>("Curve Index");
+ if (params.output_is_required("Total")) {
+ params.set_output("Total",
+ Field<int>(std::make_shared<FieldAtIndexInput>(
+ curve_index,
+ Field<int>(std::make_shared<CurvePointCountInput>()),
+ ATTR_DOMAIN_CURVE)));
+ }
+ if (params.output_is_required("Point Index")) {
+ params.set_output("Point Index",
+ Field<int>(std::make_shared<PointsOfCurveInput>(
+ curve_index,
+ params.extract_input<Field<int>>("Sort Index"),
+ params.extract_input<Field<float>>("Weights"))));
+ }
+}
+
+} // namespace blender::nodes::node_geo_curve_topology_points_of_curve_cc
+
+void register_node_type_geo_curve_topology_points_of_curve()
+{
+ namespace file_ns = blender::nodes::node_geo_curve_topology_points_of_curve_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_CURVE_TOPOLOGY_POINTS_OF_CURVE, "Points of Curve", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
index 0932de237a9..15c89d78276 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BKE_curves.hh"
-#include "BKE_spline.hh"
#include "BLI_task.hh"
#include "UI_interface.h"
@@ -9,12 +8,12 @@
#include "NOD_socket_search_link.hh"
+#include "GEO_trim_curves.hh"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_curve_trim_cc {
-using blender::attribute_math::mix2;
-
NODE_STORAGE_FUNCS(NodeGeometryCurveTrim)
static void node_declare(NodeDeclarationBuilder &b)
@@ -47,12 +46,12 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryCurveTrim *data = MEM_cnew<NodeGeometryCurveTrim>(__func__);
@@ -65,7 +64,7 @@ static void node_update(bNodeTree *ntree, bNode *node)
const NodeGeometryCurveTrim &storage = node_storage(*node);
const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)storage.mode;
- bNodeSocket *start_fac = ((bNodeSocket *)node->inputs.first)->next;
+ bNodeSocket *start_fac = static_cast<bNodeSocket *>(node->inputs.first)->next;
bNodeSocket *end_fac = start_fac->next;
bNodeSocket *start_len = end_fac->next;
bNodeSocket *end_len = start_len->next;
@@ -96,8 +95,8 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
search_link_ops_for_declarations(params, declaration.inputs().take_front(1));
if (params.in_out() == SOCK_IN) {
- if (params.node_tree().typeinfo->validate_link(
- static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_FLOAT)) {
+ if (params.node_tree().typeinfo->validate_link(eNodeSocketDatatype(params.other_socket().type),
+ SOCK_FLOAT)) {
params.add_item(IFACE_("Start (Factor)"),
SocketSearchOp{"Start", GEO_NODE_CURVE_SAMPLE_FACTOR});
params.add_item(IFACE_("End (Factor)"), SocketSearchOp{"End", GEO_NODE_CURVE_SAMPLE_FACTOR});
@@ -108,394 +107,6 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
}
}
-struct TrimLocation {
- /* Control point index at the start side of the trim location. */
- int left_index;
- /* Control point index at the end of the trim location's segment. */
- int right_index;
- /* The factor between the left and right indices. */
- float factor;
-};
-
-template<typename T>
-static void shift_slice_to_start(MutableSpan<T> data, const int start_index, const int num)
-{
- BLI_assert(start_index + num - 1 <= data.size());
- memmove(data.data(), &data[start_index], sizeof(T) * num);
-}
-
-/* Shift slice to start of span and modifies start and end data. */
-template<typename T>
-static void linear_trim_data(const TrimLocation &start,
- const TrimLocation &end,
- MutableSpan<T> data)
-{
- const int num = end.right_index - start.left_index + 1;
-
- if (start.left_index > 0) {
- shift_slice_to_start<T>(data, start.left_index, num);
- }
-
- const T start_data = mix2<T>(start.factor, data.first(), data[1]);
- const T end_data = mix2<T>(end.factor, data[num - 2], data[num - 1]);
-
- data.first() = start_data;
- data[num - 1] = end_data;
-}
-
-/**
- * Identical operation as #linear_trim_data, but copy data to a new #MutableSpan rather than
- * modifying the original data.
- */
-template<typename T>
-static void linear_trim_to_output_data(const TrimLocation &start,
- const TrimLocation &end,
- Span<T> src,
- MutableSpan<T> dst)
-{
- const int num = end.right_index - start.left_index + 1;
-
- const T start_data = mix2<T>(start.factor, src[start.left_index], src[start.right_index]);
- const T end_data = mix2<T>(end.factor, src[end.left_index], src[end.right_index]);
-
- dst.copy_from(src.slice(start.left_index, num));
- dst.first() = start_data;
- dst.last() = end_data;
-}
-
-/* Look up the control points to the left and right of factor, and get the factor between them. */
-static TrimLocation lookup_control_point_position(const Spline::LookupResult &lookup,
- const BezierSpline &spline)
-{
- Span<int> offsets = spline.control_point_offsets();
-
- const int *offset = std::lower_bound(offsets.begin(), offsets.end(), lookup.evaluated_index);
- const int index = offset - offsets.begin();
-
- const int left = offsets[index] > lookup.evaluated_index ? index - 1 : index;
- const int right = left == (spline.size() - 1) ? 0 : left + 1;
-
- const float offset_in_segment = lookup.evaluated_index + lookup.factor - offsets[left];
- const int segment_eval_num = offsets[left + 1] - offsets[left];
- const float factor = std::clamp(offset_in_segment / segment_eval_num, 0.0f, 1.0f);
-
- return {left, right, factor};
-}
-
-static void trim_poly_spline(Spline &spline,
- const Spline::LookupResult &start_lookup,
- const Spline::LookupResult &end_lookup)
-{
- /* Poly splines have a 1 to 1 mapping between control points and evaluated points. */
- const TrimLocation start = {
- start_lookup.evaluated_index, start_lookup.next_evaluated_index, start_lookup.factor};
- const TrimLocation end = {
- end_lookup.evaluated_index, end_lookup.next_evaluated_index, end_lookup.factor};
-
- const int num = end.right_index - start.left_index + 1;
-
- linear_trim_data<float3>(start, end, spline.positions());
- linear_trim_data<float>(start, end, spline.radii());
- linear_trim_data<float>(start, end, spline.tilts());
-
- spline.attributes.foreach_attribute(
- [&](const AttributeIDRef &attribute_id, const AttributeMetaData &UNUSED(meta_data)) {
- std::optional<GMutableSpan> src = spline.attributes.get_for_write(attribute_id);
- BLI_assert(src);
- attribute_math::convert_to_static_type(src->type(), [&](auto dummy) {
- using T = decltype(dummy);
- linear_trim_data<T>(start, end, src->typed<T>());
- });
- return true;
- },
- ATTR_DOMAIN_POINT);
-
- spline.resize(num);
-}
-
-/**
- * Trim NURB splines by converting to a poly spline.
- */
-static PolySpline trim_nurbs_spline(const Spline &spline,
- const Spline::LookupResult &start_lookup,
- const Spline::LookupResult &end_lookup)
-{
- /* Since this outputs a poly spline, the evaluated indices are the control point indices. */
- const TrimLocation start = {
- start_lookup.evaluated_index, start_lookup.next_evaluated_index, start_lookup.factor};
- const TrimLocation end = {
- end_lookup.evaluated_index, end_lookup.next_evaluated_index, end_lookup.factor};
-
- const int num = end.right_index - start.left_index + 1;
-
- /* Create poly spline and copy trimmed data to it. */
- PolySpline new_spline;
- new_spline.resize(num);
-
- /* Copy generic attribute data. */
- spline.attributes.foreach_attribute(
- [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
- std::optional<GSpan> src = spline.attributes.get_for_read(attribute_id);
- BLI_assert(src);
- if (!new_spline.attributes.create(attribute_id, meta_data.data_type)) {
- BLI_assert_unreachable();
- return false;
- }
- std::optional<GMutableSpan> dst = new_spline.attributes.get_for_write(attribute_id);
- BLI_assert(dst);
-
- attribute_math::convert_to_static_type(src->type(), [&](auto dummy) {
- using T = decltype(dummy);
- VArray<T> eval_data = spline.interpolate_to_evaluated<T>(src->typed<T>());
- linear_trim_to_output_data<T>(
- start, end, eval_data.get_internal_span(), dst->typed<T>());
- });
- return true;
- },
- ATTR_DOMAIN_POINT);
-
- linear_trim_to_output_data<float3>(
- start, end, spline.evaluated_positions(), new_spline.positions());
-
- VArray<float> evaluated_radii = spline.interpolate_to_evaluated(spline.radii());
- linear_trim_to_output_data<float>(
- start, end, evaluated_radii.get_internal_span(), new_spline.radii());
-
- VArray<float> evaluated_tilts = spline.interpolate_to_evaluated(spline.tilts());
- linear_trim_to_output_data<float>(
- start, end, evaluated_tilts.get_internal_span(), new_spline.tilts());
-
- return new_spline;
-}
-
-/**
- * Trim Bezier splines by adjusting the first and last handles
- * and control points to maintain the original shape.
- */
-static void trim_bezier_spline(Spline &spline,
- const Spline::LookupResult &start_lookup,
- const Spline::LookupResult &end_lookup)
-{
- BezierSpline &bezier_spline = static_cast<BezierSpline &>(spline);
-
- const TrimLocation start = lookup_control_point_position(start_lookup, bezier_spline);
- TrimLocation end = lookup_control_point_position(end_lookup, bezier_spline);
-
- const Span<int> control_offsets = bezier_spline.control_point_offsets();
-
- /* The number of control points in the resulting spline. */
- const int num = end.right_index - start.left_index + 1;
-
- /* Trim the spline attributes. Done before end.factor recalculation as it needs
- * the original end.factor value. */
- linear_trim_data<float>(start, end, bezier_spline.radii());
- linear_trim_data<float>(start, end, bezier_spline.tilts());
- spline.attributes.foreach_attribute(
- [&](const AttributeIDRef &attribute_id, const AttributeMetaData &UNUSED(meta_data)) {
- std::optional<GMutableSpan> src = spline.attributes.get_for_write(attribute_id);
- BLI_assert(src);
- attribute_math::convert_to_static_type(src->type(), [&](auto dummy) {
- using T = decltype(dummy);
- linear_trim_data<T>(start, end, src->typed<T>());
- });
- return true;
- },
- ATTR_DOMAIN_POINT);
-
- /* Recalculate end.factor if the `num` is two, because the adjustment in the
- * position of the control point of the spline to the left of the new end point will change the
- * factor between them. */
- if (num == 2) {
- if (start_lookup.factor == 1.0f) {
- end.factor = 0.0f;
- }
- else {
- end.factor = (end_lookup.evaluated_index + end_lookup.factor -
- (start_lookup.evaluated_index + start_lookup.factor)) /
- (control_offsets[end.right_index] -
- (start_lookup.evaluated_index + start_lookup.factor));
- end.factor = std::clamp(end.factor, 0.0f, 1.0f);
- }
- }
-
- BezierSpline::InsertResult start_point = bezier_spline.calculate_segment_insertion(
- start.left_index, start.right_index, start.factor);
-
- /* Update the start control point parameters so they are used calculating the new end point. */
- bezier_spline.positions()[start.left_index] = start_point.position;
- bezier_spline.handle_positions_right()[start.left_index] = start_point.right_handle;
- bezier_spline.handle_positions_left()[start.right_index] = start_point.handle_next;
-
- const BezierSpline::InsertResult end_point = bezier_spline.calculate_segment_insertion(
- end.left_index, end.right_index, end.factor);
-
- /* If `num` is two, then the start point right handle needs to change to reflect the end point
- * previous handle update. */
- if (num == 2) {
- start_point.right_handle = end_point.handle_prev;
- }
-
- /* Shift control point position data to start at beginning of array. */
- if (start.left_index > 0) {
- shift_slice_to_start(bezier_spline.positions(), start.left_index, num);
- shift_slice_to_start(bezier_spline.handle_positions_left(), start.left_index, num);
- shift_slice_to_start(bezier_spline.handle_positions_right(), start.left_index, num);
- }
-
- bezier_spline.positions().first() = start_point.position;
- bezier_spline.positions()[num - 1] = end_point.position;
-
- bezier_spline.handle_positions_left().first() = start_point.left_handle;
- bezier_spline.handle_positions_left()[num - 1] = end_point.left_handle;
-
- bezier_spline.handle_positions_right().first() = start_point.right_handle;
- bezier_spline.handle_positions_right()[num - 1] = end_point.right_handle;
-
- /* If there is at least one control point between the endpoints, update the control
- * point handle to the right of the start point and to the left of the end point. */
- if (num > 2) {
- bezier_spline.handle_positions_left()[start.right_index - start.left_index] =
- start_point.handle_next;
- bezier_spline.handle_positions_right()[end.left_index - start.left_index] =
- end_point.handle_prev;
- }
-
- bezier_spline.resize(num);
-}
-
-static void trim_spline(SplinePtr &spline,
- const Spline::LookupResult start,
- const Spline::LookupResult end)
-{
- switch (spline->type()) {
- case CURVE_TYPE_BEZIER:
- trim_bezier_spline(*spline, start, end);
- break;
- case CURVE_TYPE_POLY:
- trim_poly_spline(*spline, start, end);
- break;
- case CURVE_TYPE_NURBS:
- spline = std::make_unique<PolySpline>(trim_nurbs_spline(*spline, start, end));
- break;
- case CURVE_TYPE_CATMULL_ROM:
- BLI_assert_unreachable();
- spline = {};
- }
- spline->mark_cache_invalid();
-}
-
-template<typename T>
-static void to_single_point_data(const TrimLocation &trim, MutableSpan<T> data)
-{
- data.first() = mix2<T>(trim.factor, data[trim.left_index], data[trim.right_index]);
-}
-template<typename T>
-static void to_single_point_data(const TrimLocation &trim, Span<T> src, MutableSpan<T> dst)
-{
- dst.first() = mix2<T>(trim.factor, src[trim.left_index], src[trim.right_index]);
-}
-
-static void to_single_point_bezier(Spline &spline, const Spline::LookupResult &lookup)
-{
- BezierSpline &bezier = static_cast<BezierSpline &>(spline);
-
- const TrimLocation trim = lookup_control_point_position(lookup, bezier);
-
- const BezierSpline::InsertResult new_point = bezier.calculate_segment_insertion(
- trim.left_index, trim.right_index, trim.factor);
- bezier.positions().first() = new_point.position;
- bezier.handle_types_left().first() = BEZIER_HANDLE_FREE;
- bezier.handle_types_right().first() = BEZIER_HANDLE_FREE;
- bezier.handle_positions_left().first() = new_point.left_handle;
- bezier.handle_positions_right().first() = new_point.right_handle;
-
- to_single_point_data<float>(trim, bezier.radii());
- to_single_point_data<float>(trim, bezier.tilts());
- spline.attributes.foreach_attribute(
- [&](const AttributeIDRef &attribute_id, const AttributeMetaData &UNUSED(meta_data)) {
- std::optional<GMutableSpan> data = spline.attributes.get_for_write(attribute_id);
- attribute_math::convert_to_static_type(data->type(), [&](auto dummy) {
- using T = decltype(dummy);
- to_single_point_data<T>(trim, data->typed<T>());
- });
- return true;
- },
- ATTR_DOMAIN_POINT);
- spline.resize(1);
-}
-
-static void to_single_point_poly(Spline &spline, const Spline::LookupResult &lookup)
-{
- const TrimLocation trim{lookup.evaluated_index, lookup.next_evaluated_index, lookup.factor};
-
- to_single_point_data<float3>(trim, spline.positions());
- to_single_point_data<float>(trim, spline.radii());
- to_single_point_data<float>(trim, spline.tilts());
- spline.attributes.foreach_attribute(
- [&](const AttributeIDRef &attribute_id, const AttributeMetaData &UNUSED(meta_data)) {
- std::optional<GMutableSpan> data = spline.attributes.get_for_write(attribute_id);
- attribute_math::convert_to_static_type(data->type(), [&](auto dummy) {
- using T = decltype(dummy);
- to_single_point_data<T>(trim, data->typed<T>());
- });
- return true;
- },
- ATTR_DOMAIN_POINT);
- spline.resize(1);
-}
-
-static PolySpline to_single_point_nurbs(const Spline &spline, const Spline::LookupResult &lookup)
-{
- /* Since this outputs a poly spline, the evaluated indices are the control point indices. */
- const TrimLocation trim{lookup.evaluated_index, lookup.next_evaluated_index, lookup.factor};
-
- /* Create poly spline and copy trimmed data to it. */
- PolySpline new_spline;
- new_spline.resize(1);
-
- spline.attributes.foreach_attribute(
- [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
- new_spline.attributes.create(attribute_id, meta_data.data_type);
- std::optional<GSpan> src = spline.attributes.get_for_read(attribute_id);
- std::optional<GMutableSpan> dst = new_spline.attributes.get_for_write(attribute_id);
- attribute_math::convert_to_static_type(src->type(), [&](auto dummy) {
- using T = decltype(dummy);
- VArray<T> eval_data = spline.interpolate_to_evaluated<T>(src->typed<T>());
- to_single_point_data<T>(trim, eval_data.get_internal_span(), dst->typed<T>());
- });
- return true;
- },
- ATTR_DOMAIN_POINT);
-
- to_single_point_data<float3>(trim, spline.evaluated_positions(), new_spline.positions());
-
- VArray<float> evaluated_radii = spline.interpolate_to_evaluated(spline.radii());
- to_single_point_data<float>(trim, evaluated_radii.get_internal_span(), new_spline.radii());
-
- VArray<float> evaluated_tilts = spline.interpolate_to_evaluated(spline.tilts());
- to_single_point_data<float>(trim, evaluated_tilts.get_internal_span(), new_spline.tilts());
-
- return new_spline;
-}
-
-static void to_single_point_spline(SplinePtr &spline, const Spline::LookupResult &lookup)
-{
- switch (spline->type()) {
- case CURVE_TYPE_BEZIER:
- to_single_point_bezier(*spline, lookup);
- break;
- case CURVE_TYPE_POLY:
- to_single_point_poly(*spline, lookup);
- break;
- case CURVE_TYPE_NURBS:
- spline = std::make_unique<PolySpline>(to_single_point_nurbs(*spline, lookup));
- break;
- case CURVE_TYPE_CATMULL_ROM:
- BLI_assert_unreachable();
- spline = {};
- }
-}
-
static void geometry_set_curve_trim(GeometrySet &geometry_set,
const GeometryNodeCurveSampleMode mode,
Field<float> &start_field,
@@ -504,71 +115,50 @@ static void geometry_set_curve_trim(GeometrySet &geometry_set,
if (!geometry_set.has_curves()) {
return;
}
+ const Curves &src_curves_id = *geometry_set.get_curves_for_read();
+ const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(src_curves_id.geometry);
+ if (src_curves.curves_num() == 0) {
+ return;
+ }
- CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
-
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ bke::CurvesFieldContext field_context{src_curves, ATTR_DOMAIN_CURVE};
+ fn::FieldEvaluator evaluator{field_context, src_curves.curves_num()};
evaluator.add(start_field);
evaluator.add(end_field);
evaluator.evaluate();
const VArray<float> starts = evaluator.get_evaluated<float>(0);
const VArray<float> ends = evaluator.get_evaluated<float>(1);
- const Curves &src_curves_id = *geometry_set.get_curves_for_read();
- std::unique_ptr<CurveEval> curve = curves_to_curve_eval(src_curves_id);
- MutableSpan<SplinePtr> splines = curve->splines();
-
- threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
- for (const int i : range) {
- SplinePtr &spline = splines[i];
-
- /* Currently trimming cyclic splines is not supported. It could be in the future though. */
- if (spline->is_cyclic()) {
- continue;
- }
-
- if (spline->evaluated_edges_num() == 0) {
- continue;
- }
-
- const float length = spline->length();
- if (length == 0.0f) {
- continue;
- }
-
- const float start = starts[i];
- const float end = ends[i];
-
- /* When the start and end samples are reversed, instead of implicitly reversing the spline
- * or switching the parameters, create a single point spline with the end sample point. */
- if (end <= start) {
- if (mode == GEO_NODE_CURVE_SAMPLE_LENGTH) {
- to_single_point_spline(spline,
- spline->lookup_evaluated_length(std::clamp(start, 0.0f, length)));
- }
- else {
- to_single_point_spline(spline,
- spline->lookup_evaluated_factor(std::clamp(start, 0.0f, 1.0f)));
- }
- continue;
- }
-
- if (mode == GEO_NODE_CURVE_SAMPLE_LENGTH) {
- trim_spline(spline,
- spline->lookup_evaluated_length(std::clamp(start, 0.0f, length)),
- spline->lookup_evaluated_length(std::clamp(end, 0.0f, length)));
- }
- else {
- trim_spline(spline,
- spline->lookup_evaluated_factor(std::clamp(start, 0.0f, 1.0f)),
- spline->lookup_evaluated_factor(std::clamp(end, 0.0f, 1.0f)));
- }
+ const VArray<bool> cyclic = src_curves.cyclic();
+
+ /* If node length input is on form [0, 1] instead of [0, length]*/
+ const bool normalized_length_lookup = mode == GEO_NODE_CURVE_SAMPLE_FACTOR;
+
+ /* Stack start + end field. */
+ Vector<float> length_factors(src_curves.curves_num() * 2);
+ Vector<int64_t> lookup_indices(src_curves.curves_num() * 2);
+ threading::parallel_for(src_curves.curves_range(), 512, [&](IndexRange curve_range) {
+ for (const int64_t curve_i : curve_range) {
+ const bool negative_trim = !cyclic[curve_i] && starts[curve_i] > ends[curve_i];
+ length_factors[curve_i] = starts[curve_i];
+ length_factors[curve_i + src_curves.curves_num()] = negative_trim ? starts[curve_i] :
+ ends[curve_i];
+ lookup_indices[curve_i] = curve_i;
+ lookup_indices[curve_i + src_curves.curves_num()] = curve_i;
}
});
- Curves *dst_curves_id = curve_eval_to_curves(*curve);
+ /* Create curve trim lookup table. */
+ Array<bke::curves::CurvePoint, 12> point_lookups = geometry::lookup_curve_points(
+ src_curves, length_factors, lookup_indices, normalized_length_lookup);
+
+ bke::CurvesGeometry dst_curves = geometry::trim_curves(
+ src_curves,
+ src_curves.curves_range().as_span(),
+ point_lookups.as_span().slice(0, src_curves.curves_num()),
+ point_lookups.as_span().slice(src_curves.curves_num(), src_curves.curves_num()));
+
+ Curves *dst_curves_id = bke::curves_new_nomain(std::move(dst_curves));
bke::curves_copy_parameters(src_curves_id, *dst_curves_id);
geometry_set.replace_curves(dst_curves_id);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc
index 5a40ededa96..0932624bdc3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc
@@ -66,6 +66,12 @@ static void deform_curves(const CurvesGeometry &curves,
const float4x4 curves_to_surface = surface_to_curves.inverted();
+ const Span<MVert> surface_verts_old = surface_mesh_old.verts();
+ const Span<MLoop> surface_loops_old = surface_mesh_old.loops();
+
+ const Span<MVert> surface_verts_new = surface_mesh_new.verts();
+ const Span<MLoop> surface_loops_new = surface_mesh_new.loops();
+
threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange range) {
for (const int curve_i : range) {
const ReverseUVSampler::Result &surface_sample_old = surface_samples_old[curve_i];
@@ -92,13 +98,13 @@ static void deform_curves(const CurvesGeometry &curves,
const int corner_1_new = looptri_new.tri[1];
const int corner_2_new = looptri_new.tri[2];
- const int vert_0_old = surface_mesh_old.mloop[corner_0_old].v;
- const int vert_1_old = surface_mesh_old.mloop[corner_1_old].v;
- const int vert_2_old = surface_mesh_old.mloop[corner_2_old].v;
+ const int vert_0_old = surface_loops_old[corner_0_old].v;
+ const int vert_1_old = surface_loops_old[corner_1_old].v;
+ const int vert_2_old = surface_loops_old[corner_2_old].v;
- const int vert_0_new = surface_mesh_new.mloop[corner_0_new].v;
- const int vert_1_new = surface_mesh_new.mloop[corner_1_new].v;
- const int vert_2_new = surface_mesh_new.mloop[corner_2_new].v;
+ const int vert_0_new = surface_loops_new[corner_0_new].v;
+ const int vert_1_new = surface_loops_new[corner_1_new].v;
+ const int vert_2_new = surface_loops_new[corner_2_new].v;
const float3 &normal_0_old = corner_normals_old[corner_0_old];
const float3 &normal_1_old = corner_normals_old[corner_1_old];
@@ -112,14 +118,14 @@ static void deform_curves(const CurvesGeometry &curves,
const float3 normal_new = math::normalize(
mix3(bary_weights_new, normal_0_new, normal_1_new, normal_2_new));
- const float3 &pos_0_old = surface_mesh_old.mvert[vert_0_old].co;
- const float3 &pos_1_old = surface_mesh_old.mvert[vert_1_old].co;
- const float3 &pos_2_old = surface_mesh_old.mvert[vert_2_old].co;
+ const float3 &pos_0_old = surface_verts_old[vert_0_old].co;
+ const float3 &pos_1_old = surface_verts_old[vert_1_old].co;
+ const float3 &pos_2_old = surface_verts_old[vert_2_old].co;
const float3 pos_old = mix3(bary_weights_old, pos_0_old, pos_1_old, pos_2_old);
- const float3 &pos_0_new = surface_mesh_new.mvert[vert_0_new].co;
- const float3 &pos_1_new = surface_mesh_new.mvert[vert_1_new].co;
- const float3 &pos_2_new = surface_mesh_new.mvert[vert_2_new].co;
+ const float3 &pos_0_new = surface_verts_new[vert_0_new].co;
+ const float3 &pos_1_new = surface_verts_new[vert_1_new].co;
+ const float3 &pos_2_new = surface_verts_new[vert_2_new].co;
const float3 pos_new = mix3(bary_weights_new, pos_0_new, pos_1_new, pos_2_new);
/* The translation is just the difference between the old and new position on the surface. */
@@ -249,7 +255,7 @@ static void node_geo_exec(GeoNodeExecParams params)
Mesh &surface_object_data = *static_cast<Mesh *>(surface_ob_orig->data);
if (BMEditMesh *em = surface_object_data.edit_mesh) {
- surface_mesh_orig = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL, &surface_object_data);
+ surface_mesh_orig = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, nullptr, &surface_object_data);
free_suface_mesh_orig = true;
}
else {
@@ -264,8 +270,8 @@ static void node_geo_exec(GeoNodeExecParams params)
BKE_mesh_wrapper_ensure_mdata(surface_mesh_eval);
- const AttributeAccessor mesh_attributes_eval = bke::mesh_attributes(*surface_mesh_eval);
- const AttributeAccessor mesh_attributes_orig = bke::mesh_attributes(*surface_mesh_orig);
+ const AttributeAccessor mesh_attributes_eval = surface_mesh_eval->attributes();
+ const AttributeAccessor mesh_attributes_orig = surface_mesh_orig->attributes();
Curves &curves_id = *curves_geometry.get_curves_for_write();
CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
@@ -306,10 +312,8 @@ static void node_geo_exec(GeoNodeExecParams params)
ATTR_DOMAIN_POINT);
const Span<float2> surface_uv_coords = curves.surface_uv_coords();
- const Span<MLoopTri> looptris_orig{BKE_mesh_runtime_looptri_ensure(surface_mesh_orig),
- BKE_mesh_runtime_looptri_len(surface_mesh_orig)};
- const Span<MLoopTri> looptris_eval{BKE_mesh_runtime_looptri_ensure(surface_mesh_eval),
- BKE_mesh_runtime_looptri_len(surface_mesh_eval)};
+ const Span<MLoopTri> looptris_orig = surface_mesh_orig->looptris();
+ const Span<MLoopTri> looptris_eval = surface_mesh_eval->looptris();
const ReverseUVSampler reverse_uv_sampler_orig{uv_map_orig, looptris_orig};
const ReverseUVSampler reverse_uv_sampler_eval{uv_map_eval, looptris_eval};
@@ -375,19 +379,22 @@ static void node_geo_exec(GeoNodeExecParams params)
invalid_uv_count);
/* Then also deform edit curve information for use in sculpt mode. */
const CurvesGeometry &curves_orig = CurvesGeometry::wrap(edit_hints->curves_id_orig.geometry);
- deform_curves(curves_orig,
- *surface_mesh_orig,
- *surface_mesh_eval,
- surface_uv_coords,
- reverse_uv_sampler_orig,
- reverse_uv_sampler_eval,
- corner_normals_orig,
- corner_normals_eval,
- rest_positions,
- transforms.surface_to_curves,
- edit_hint_positions,
- edit_hint_rotations,
- invalid_uv_count);
+ const Span<float2> surface_uv_coords_orig = curves_orig.surface_uv_coords();
+ if (!surface_uv_coords_orig.is_empty()) {
+ deform_curves(curves_orig,
+ *surface_mesh_orig,
+ *surface_mesh_eval,
+ surface_uv_coords_orig,
+ reverse_uv_sampler_orig,
+ reverse_uv_sampler_eval,
+ corner_normals_orig,
+ corner_normals_eval,
+ rest_positions,
+ transforms.surface_to_curves,
+ edit_hint_positions,
+ edit_hint_rotations,
+ invalid_uv_count);
+ }
}
curves.tag_positions_changed();
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 b74b4e45199..a433a0df9b0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
@@ -7,10 +7,12 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_pointcloud_types.h"
#include "BKE_attribute_math.hh"
#include "BKE_curves.hh"
#include "BKE_customdata.h"
+#include "BKE_instances.hh"
#include "BKE_mesh.h"
#include "BKE_pointcloud.h"
@@ -160,10 +162,11 @@ static void copy_face_corner_attributes(const Map<AttributeIDRef, AttributeKind>
const Span<int> selected_poly_indices,
const Mesh &mesh_in)
{
+ const Span<MPoly> polys = mesh_in.polys();
Vector<int64_t> indices;
indices.reserve(selected_loops_num);
for (const int src_poly_index : selected_poly_indices) {
- const MPoly &src_poly = mesh_in.mpoly[src_poly_index];
+ const MPoly &src_poly = polys[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)) {
@@ -174,39 +177,35 @@ static void copy_face_corner_attributes(const Map<AttributeIDRef, AttributeKind>
attributes, src_attributes, dst_attributes, ATTR_DOMAIN_CORNER, IndexMask(indices));
}
-static void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh,
- Mesh &dst_mesh,
- Span<int> vertex_map)
+static void copy_masked_verts_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ Span<int> vertex_map)
{
BLI_assert(src_mesh.totvert == vertex_map.size());
+ const Span<MVert> src_verts = src_mesh.verts();
+ MutableSpan<MVert> dst_verts = dst_mesh.verts_for_write();
+
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;
+ dst_verts[i_dst] = src_verts[i_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());
+ const Span<MEdge> src_edges = src_mesh.edges();
+ MutableSpan<MEdge> dst_edges = dst_mesh.edges_for_write();
+
for (const int i_src : IndexRange(src_mesh.totedge)) {
const int i_dst = edge_map[i_src];
if (ELEM(i_dst, -1, -2)) {
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 = e_src.v1;
- e_dst.v2 = e_src.v2;
+ dst_edges[i_dst] = src_edges[i_src];
}
}
@@ -217,14 +216,16 @@ static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh,
{
BLI_assert(src_mesh.totvert == vertex_map.size());
BLI_assert(src_mesh.totedge == edge_map.size());
+ const Span<MEdge> src_edges = src_mesh.edges();
+ MutableSpan<MEdge> dst_edges = dst_mesh.edges_for_write();
+
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];
+ const MEdge &e_src = src_edges[i_src];
+ MEdge &e_dst = dst_edges[i_dst];
e_dst = e_src;
e_dst.v1 = vertex_map[e_src.v1];
@@ -239,16 +240,21 @@ static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
Span<int> masked_poly_indices,
Span<int> new_loop_starts)
{
+ const Span<MPoly> src_polys = src_mesh.polys();
+ const Span<MLoop> src_loops = src_mesh.loops();
+ MutableSpan<MPoly> dst_polys = dst_mesh.polys_for_write();
+ MutableSpan<MLoop> dst_loops = dst_mesh.loops_for_write();
+
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 MPoly &mp_src = src_polys[i_src];
+ MPoly &mp_dst = dst_polys[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;
+ const MLoop *ml_src = &src_loops[i_ml_src];
+ MLoop *ml_dst = &dst_loops[i_ml_dst];
mp_dst = mp_src;
mp_dst.loopstart = i_ml_dst;
@@ -265,16 +271,21 @@ static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
Span<int> masked_poly_indices,
Span<int> new_loop_starts)
{
+ const Span<MPoly> src_polys = src_mesh.polys();
+ const Span<MLoop> src_loops = src_mesh.loops();
+ MutableSpan<MPoly> dst_polys = dst_mesh.polys_for_write();
+ MutableSpan<MLoop> dst_loops = dst_mesh.loops_for_write();
+
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 MPoly &mp_src = src_polys[i_src];
+ MPoly &mp_dst = dst_polys[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;
+ const MLoop *ml_src = &src_loops[i_ml_src];
+ MLoop *ml_dst = &dst_loops[i_ml_dst];
mp_dst = mp_src;
mp_dst.loopstart = i_ml_dst;
@@ -292,16 +303,21 @@ static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
Span<int> masked_poly_indices,
Span<int> new_loop_starts)
{
+ const Span<MPoly> src_polys = src_mesh.polys();
+ const Span<MLoop> src_loops = src_mesh.loops();
+ MutableSpan<MPoly> dst_polys = dst_mesh.polys_for_write();
+ MutableSpan<MLoop> dst_loops = dst_mesh.loops_for_write();
+
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 MPoly &mp_src = src_polys[i_src];
+ MPoly &mp_dst = dst_polys[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;
+ const MLoop *ml_src = &src_loops[i_ml_src];
+ MLoop *ml_dst = &dst_loops[i_ml_dst];
mp_dst = mp_src;
mp_dst.loopstart = i_ml_dst;
@@ -316,18 +332,19 @@ static void delete_curves_selection(GeometrySet &geometry_set,
const Field<bool> &selection_field,
const eAttrDomain selection_domain)
{
- const CurveComponent &src_component = *geometry_set.get_component_for_read<CurveComponent>();
- GeometryComponentFieldContext field_context{src_component, selection_domain};
+ const Curves &src_curves_id = *geometry_set.get_curves_for_read();
+ const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(src_curves_id.geometry);
- const int domain_num = src_component.attribute_domain_size(selection_domain);
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ const int domain_size = src_curves.attributes().domain_size(selection_domain);
+ bke::CurvesFieldContext field_context{src_curves, selection_domain};
+ fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.set_selection(selection_field);
evaluator.evaluate();
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
if (selection.is_empty()) {
return;
}
- if (selection.size() == domain_num) {
+ if (selection.size() == domain_size) {
geometry_set.remove<CurveComponent>();
return;
}
@@ -347,11 +364,10 @@ static void delete_curves_selection(GeometrySet &geometry_set,
static void separate_point_cloud_selection(GeometrySet &geometry_set,
const Field<bool> &selection_field)
{
- const PointCloudComponent &src_points =
- *geometry_set.get_component_for_read<PointCloudComponent>();
- GeometryComponentFieldContext field_context{src_points, ATTR_DOMAIN_POINT};
+ const PointCloud &src_pointcloud = *geometry_set.get_pointcloud_for_read();
- fn::FieldEvaluator evaluator{field_context, src_points.attribute_domain_size(ATTR_DOMAIN_POINT)};
+ bke::PointCloudFieldContext field_context{src_pointcloud};
+ fn::FieldEvaluator evaluator{field_context, src_pointcloud.totpoint};
evaluator.set_selection(selection_field);
evaluator.evaluate();
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
@@ -367,8 +383,8 @@ static void separate_point_cloud_selection(GeometrySet &geometry_set,
{GEO_COMPONENT_TYPE_POINT_CLOUD}, GEO_COMPONENT_TYPE_POINT_CLOUD, false, attributes);
copy_attributes_based_on_mask(attributes,
- bke::pointcloud_attributes(*src_points.get_for_read()),
- bke::pointcloud_attributes_for_write(*pointcloud),
+ src_pointcloud.attributes(),
+ pointcloud->attributes_for_write(),
ATTR_DOMAIN_POINT,
selection);
geometry_set.replace_pointcloud(pointcloud);
@@ -377,8 +393,8 @@ static void separate_point_cloud_selection(GeometrySet &geometry_set,
static void delete_selected_instances(GeometrySet &geometry_set,
const Field<bool> &selection_field)
{
- InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
- GeometryComponentFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE};
+ bke::Instances &instances = *geometry_set.get_instances_for_write();
+ bke::InstancesFieldContext field_context{instances};
fn::FieldEvaluator evaluator{field_context, instances.instances_num()};
evaluator.set_selection(selection_field);
@@ -389,12 +405,12 @@ static void delete_selected_instances(GeometrySet &geometry_set,
return;
}
- instances.remove_instances(selection);
+ instances.remove(selection);
}
-static void compute_selected_vertices_from_vertex_selection(const Span<bool> vertex_selection,
- MutableSpan<int> r_vertex_map,
- int *r_selected_vertices_num)
+static void compute_selected_verts_from_vertex_selection(const Span<bool> vertex_selection,
+ MutableSpan<int> r_vertex_map,
+ int *r_selected_verts_num)
{
BLI_assert(vertex_selection.size() == r_vertex_map.size());
@@ -409,7 +425,7 @@ static void compute_selected_vertices_from_vertex_selection(const Span<bool> ver
}
}
- *r_selected_vertices_num = selected_verts_num;
+ *r_selected_verts_num = selected_verts_num;
}
static void compute_selected_edges_from_vertex_selection(const Mesh &mesh,
@@ -418,10 +434,11 @@ static void compute_selected_edges_from_vertex_selection(const Mesh &mesh,
int *r_selected_edges_num)
{
BLI_assert(mesh.totedge == r_edge_map.size());
+ const Span<MEdge> edges = mesh.edges();
int selected_edges_num = 0;
for (const int i : IndexRange(mesh.totedge)) {
- const MEdge &edge = mesh.medge[i];
+ const MEdge &edge = edges[i];
/* Only add the edge if both vertices will be in the new mesh. */
if (vertex_selection[edge.v1] && vertex_selection[edge.v2]) {
@@ -436,25 +453,27 @@ static void compute_selected_edges_from_vertex_selection(const Mesh &mesh,
*r_selected_edges_num = selected_edges_num;
}
-static void compute_selected_polygons_from_vertex_selection(const Mesh &mesh,
- const Span<bool> vertex_selection,
- Vector<int> &r_selected_poly_indices,
- Vector<int> &r_loop_starts,
- int *r_selected_polys_num,
- int *r_selected_loops_num)
+static void compute_selected_polys_from_vertex_selection(const Mesh &mesh,
+ const Span<bool> vertex_selection,
+ Vector<int> &r_selected_poly_indices,
+ Vector<int> &r_loop_starts,
+ int *r_selected_polys_num,
+ int *r_selected_loops_num)
{
BLI_assert(mesh.totvert == vertex_selection.size());
+ const Span<MPoly> polys = mesh.polys();
+ const Span<MLoop> loops = mesh.loops();
r_selected_poly_indices.reserve(mesh.totpoly);
r_loop_starts.reserve(mesh.totloop);
int selected_loops_num = 0;
- for (const int i : IndexRange(mesh.totpoly)) {
- const MPoly &poly_src = mesh.mpoly[i];
+ for (const int i : polys.index_range()) {
+ const MPoly &poly_src = polys[i];
bool all_verts_in_selection = true;
- Span<MLoop> loops_src(&mesh.mloop[poly_src.loopstart], poly_src.totloop);
- for (const MLoop &loop : loops_src) {
+ const Span<MLoop> poly_loops = loops.slice(poly_src.loopstart, poly_src.totloop);
+ for (const MLoop &loop : poly_loops) {
if (!vertex_selection[loop.v]) {
all_verts_in_selection = false;
break;
@@ -476,20 +495,20 @@ static void compute_selected_polygons_from_vertex_selection(const Mesh &mesh,
* Checks for every edge if it is in `edge_selection`. If it is, then the two vertices of the
* edge are kept along with the edge.
*/
-static void compute_selected_vertices_and_edges_from_edge_selection(
- const Mesh &mesh,
- const Span<bool> edge_selection,
- MutableSpan<int> r_vertex_map,
- MutableSpan<int> r_edge_map,
- int *r_selected_vertices_num,
- int *r_selected_edges_num)
+static void compute_selected_verts_and_edges_from_edge_selection(const Mesh &mesh,
+ const Span<bool> edge_selection,
+ MutableSpan<int> r_vertex_map,
+ MutableSpan<int> r_edge_map,
+ int *r_selected_verts_num,
+ int *r_selected_edges_num)
{
BLI_assert(mesh.totedge == edge_selection.size());
+ const Span<MEdge> edges = mesh.edges();
int selected_edges_num = 0;
int selected_verts_num = 0;
for (const int i : IndexRange(mesh.totedge)) {
- const MEdge &edge = mesh.medge[i];
+ const MEdge &edge = edges[i];
if (edge_selection[i]) {
r_edge_map[i] = selected_edges_num;
selected_edges_num++;
@@ -507,7 +526,7 @@ static void compute_selected_vertices_and_edges_from_edge_selection(
}
}
- *r_selected_vertices_num = selected_verts_num;
+ *r_selected_verts_num = selected_verts_num;
*r_selected_edges_num = selected_edges_num;
}
@@ -539,23 +558,26 @@ static void compute_selected_edges_from_edge_selection(const Mesh &mesh,
* Checks for every polygon if all the edges are in `edge_selection`. If they are, then that
* polygon is kept.
*/
-static void compute_selected_polygons_from_edge_selection(const Mesh &mesh,
- const Span<bool> edge_selection,
- Vector<int> &r_selected_poly_indices,
- Vector<int> &r_loop_starts,
- int *r_selected_polys_num,
- int *r_selected_loops_num)
+static void compute_selected_polys_from_edge_selection(const Mesh &mesh,
+ const Span<bool> edge_selection,
+ Vector<int> &r_selected_poly_indices,
+ Vector<int> &r_loop_starts,
+ int *r_selected_polys_num,
+ int *r_selected_loops_num)
{
+ const Span<MPoly> polys = mesh.polys();
+ const Span<MLoop> loops = mesh.loops();
+
r_selected_poly_indices.reserve(mesh.totpoly);
r_loop_starts.reserve(mesh.totloop);
int selected_loops_num = 0;
- for (const int i : IndexRange(mesh.totpoly)) {
- const MPoly &poly_src = mesh.mpoly[i];
+ for (const int i : polys.index_range()) {
+ const MPoly &poly_src = polys[i];
bool all_edges_in_selection = true;
- Span<MLoop> loops_src(&mesh.mloop[poly_src.loopstart], poly_src.totloop);
- for (const MLoop &loop : loops_src) {
+ const Span<MLoop> poly_loops = loops.slice(poly_src.loopstart, poly_src.totloop);
+ for (const MLoop &loop : poly_loops) {
if (!edge_selection[loop.e]) {
all_edges_in_selection = false;
break;
@@ -590,12 +612,12 @@ static void compute_selected_mesh_data_from_vertex_selection_edge_face(
compute_selected_edges_from_vertex_selection(
mesh, vertex_selection, r_edge_map, r_selected_edges_num);
- compute_selected_polygons_from_vertex_selection(mesh,
- vertex_selection,
- r_selected_poly_indices,
- r_loop_starts,
- r_selected_polys_num,
- r_selected_loops_num);
+ compute_selected_polys_from_vertex_selection(mesh,
+ vertex_selection,
+ r_selected_poly_indices,
+ r_loop_starts,
+ r_selected_polys_num,
+ r_selected_loops_num);
}
/**
@@ -608,23 +630,23 @@ static void compute_selected_mesh_data_from_vertex_selection(const Mesh &mesh,
MutableSpan<int> r_edge_map,
Vector<int> &r_selected_poly_indices,
Vector<int> &r_loop_starts,
- int *r_selected_vertices_num,
+ int *r_selected_verts_num,
int *r_selected_edges_num,
int *r_selected_polys_num,
int *r_selected_loops_num)
{
- compute_selected_vertices_from_vertex_selection(
- vertex_selection, r_vertex_map, r_selected_vertices_num);
+ compute_selected_verts_from_vertex_selection(
+ vertex_selection, r_vertex_map, r_selected_verts_num);
compute_selected_edges_from_vertex_selection(
mesh, vertex_selection, r_edge_map, r_selected_edges_num);
- compute_selected_polygons_from_vertex_selection(mesh,
- vertex_selection,
- r_selected_poly_indices,
- r_loop_starts,
- r_selected_polys_num,
- r_selected_loops_num);
+ compute_selected_polys_from_vertex_selection(mesh,
+ vertex_selection,
+ r_selected_poly_indices,
+ r_loop_starts,
+ r_selected_polys_num,
+ r_selected_loops_num);
}
/**
@@ -643,17 +665,17 @@ static void compute_selected_mesh_data_from_edge_selection_edge_face(
{
compute_selected_edges_from_edge_selection(
mesh, edge_selection, r_edge_map, r_selected_edges_num);
- compute_selected_polygons_from_edge_selection(mesh,
- edge_selection,
- r_selected_poly_indices,
- r_loop_starts,
- r_selected_polys_num,
- r_selected_loops_num);
+ compute_selected_polys_from_edge_selection(mesh,
+ edge_selection,
+ r_selected_poly_indices,
+ r_loop_starts,
+ r_selected_polys_num,
+ r_selected_loops_num);
}
/**
* Checks for every edge if it is in `edge_selection`. If it is, the vertices belonging to
- * that edge are kept as well. The polygons are kept if all edges are in the selection.
+ * that edge are kept as well. The polys are kept if all edges are in the selection.
*/
static void compute_selected_mesh_data_from_edge_selection(const Mesh &mesh,
const Span<bool> edge_selection,
@@ -661,44 +683,41 @@ static void compute_selected_mesh_data_from_edge_selection(const Mesh &mesh,
MutableSpan<int> r_edge_map,
Vector<int> &r_selected_poly_indices,
Vector<int> &r_loop_starts,
- int *r_selected_vertices_num,
+ int *r_selected_verts_num,
int *r_selected_edges_num,
int *r_selected_polys_num,
int *r_selected_loops_num)
{
r_vertex_map.fill(-1);
- compute_selected_vertices_and_edges_from_edge_selection(mesh,
- edge_selection,
- r_vertex_map,
- r_edge_map,
- r_selected_vertices_num,
- r_selected_edges_num);
- compute_selected_polygons_from_edge_selection(mesh,
- edge_selection,
- r_selected_poly_indices,
- r_loop_starts,
- r_selected_polys_num,
- r_selected_loops_num);
+ compute_selected_verts_and_edges_from_edge_selection(
+ mesh, edge_selection, r_vertex_map, r_edge_map, r_selected_verts_num, r_selected_edges_num);
+ compute_selected_polys_from_edge_selection(mesh,
+ edge_selection,
+ r_selected_poly_indices,
+ r_loop_starts,
+ r_selected_polys_num,
+ r_selected_loops_num);
}
/**
* Checks for every polygon if it is in `poly_selection`.
*/
-static void compute_selected_polygons_from_poly_selection(const Mesh &mesh,
- const Span<bool> poly_selection,
- Vector<int> &r_selected_poly_indices,
- Vector<int> &r_loop_starts,
- int *r_selected_polys_num,
- int *r_selected_loops_num)
+static void compute_selected_polys_from_poly_selection(const Mesh &mesh,
+ const Span<bool> poly_selection,
+ Vector<int> &r_selected_poly_indices,
+ Vector<int> &r_loop_starts,
+ int *r_selected_polys_num,
+ int *r_selected_loops_num)
{
BLI_assert(mesh.totpoly == poly_selection.size());
+ const Span<MPoly> polys = mesh.polys();
r_selected_poly_indices.reserve(mesh.totpoly);
r_loop_starts.reserve(mesh.totloop);
int selected_loops_num = 0;
- for (const int i : IndexRange(mesh.totpoly)) {
- const MPoly &poly_src = mesh.mpoly[i];
+ for (const int i : polys.index_range()) {
+ const MPoly &poly_src = polys[i];
/* We keep this one. */
if (poly_selection[i]) {
r_selected_poly_indices.append_unchecked(i);
@@ -725,6 +744,9 @@ static void compute_selected_mesh_data_from_poly_selection_edge_face(
{
BLI_assert(mesh.totpoly == poly_selection.size());
BLI_assert(mesh.totedge == r_edge_map.size());
+ const Span<MPoly> polys = mesh.polys();
+ const Span<MLoop> loops = mesh.loops();
+
r_edge_map.fill(-1);
r_selected_poly_indices.reserve(mesh.totpoly);
@@ -732,8 +754,8 @@ static void compute_selected_mesh_data_from_poly_selection_edge_face(
int selected_loops_num = 0;
int selected_edges_num = 0;
- for (const int i : IndexRange(mesh.totpoly)) {
- const MPoly &poly_src = mesh.mpoly[i];
+ for (const int i : polys.index_range()) {
+ const MPoly &poly_src = polys[i];
/* We keep this one. */
if (poly_selection[i]) {
r_selected_poly_indices.append_unchecked(i);
@@ -741,8 +763,8 @@ static void compute_selected_mesh_data_from_poly_selection_edge_face(
selected_loops_num += poly_src.totloop;
/* Add the vertices and the edges. */
- Span<MLoop> loops_src(&mesh.mloop[poly_src.loopstart], poly_src.totloop);
- for (const MLoop &loop : loops_src) {
+ const Span<MLoop> poly_loops = loops.slice(poly_src.loopstart, poly_src.totloop);
+ for (const MLoop &loop : poly_loops) {
/* Check first if it has not yet been added. */
if (r_edge_map[loop.e] == -1) {
r_edge_map[loop.e] = selected_edges_num;
@@ -766,13 +788,16 @@ static void compute_selected_mesh_data_from_poly_selection(const Mesh &mesh,
MutableSpan<int> r_edge_map,
Vector<int> &r_selected_poly_indices,
Vector<int> &r_loop_starts,
- int *r_selected_vertices_num,
+ int *r_selected_verts_num,
int *r_selected_edges_num,
int *r_selected_polys_num,
int *r_selected_loops_num)
{
BLI_assert(mesh.totpoly == poly_selection.size());
BLI_assert(mesh.totedge == r_edge_map.size());
+ const Span<MPoly> polys = mesh.polys();
+ const Span<MLoop> loops = mesh.loops();
+
r_vertex_map.fill(-1);
r_edge_map.fill(-1);
@@ -782,8 +807,8 @@ static void compute_selected_mesh_data_from_poly_selection(const Mesh &mesh,
int selected_loops_num = 0;
int selected_verts_num = 0;
int selected_edges_num = 0;
- for (const int i : IndexRange(mesh.totpoly)) {
- const MPoly &poly_src = mesh.mpoly[i];
+ for (const int i : polys.index_range()) {
+ const MPoly &poly_src = polys[i];
/* We keep this one. */
if (poly_selection[i]) {
r_selected_poly_indices.append_unchecked(i);
@@ -791,8 +816,8 @@ static void compute_selected_mesh_data_from_poly_selection(const Mesh &mesh,
selected_loops_num += poly_src.totloop;
/* Add the vertices and the edges. */
- Span<MLoop> loops_src(&mesh.mloop[poly_src.loopstart], poly_src.totloop);
- for (const MLoop &loop : loops_src) {
+ const Span<MLoop> poly_loops = loops.slice(poly_src.loopstart, poly_src.totloop);
+ for (const MLoop &loop : poly_loops) {
/* Check first if it has not yet been added. */
if (r_vertex_map[loop.v] == -1) {
r_vertex_map[loop.v] = selected_verts_num;
@@ -805,7 +830,7 @@ static void compute_selected_mesh_data_from_poly_selection(const Mesh &mesh,
}
}
}
- *r_selected_vertices_num = selected_verts_num;
+ *r_selected_verts_num = selected_verts_num;
*r_selected_edges_num = selected_edges_num;
*r_selected_polys_num = r_selected_poly_indices.size();
*r_selected_loops_num = selected_loops_num;
@@ -890,30 +915,30 @@ static void do_mesh_separation(GeometrySet &geometry_set,
selected_polys_num);
/* Copy the selected parts of the mesh over to the new mesh. */
- copy_masked_vertices_to_new_mesh(mesh_in, *mesh_out, vertex_map);
+ copy_masked_verts_to_new_mesh(mesh_in, *mesh_out, vertex_map);
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,
- bke::mesh_attributes(mesh_in),
- bke::mesh_attributes_for_write(*mesh_out),
+ mesh_in.attributes(),
+ mesh_out->attributes_for_write(),
ATTR_DOMAIN_POINT,
vertex_map);
copy_attributes_based_on_map(attributes,
- bke::mesh_attributes(mesh_in),
- bke::mesh_attributes_for_write(*mesh_out),
+ mesh_in.attributes(),
+ mesh_out->attributes_for_write(),
ATTR_DOMAIN_EDGE,
edge_map);
copy_attributes_based_on_mask(attributes,
- bke::mesh_attributes(mesh_in),
- bke::mesh_attributes_for_write(*mesh_out),
+ mesh_in.attributes(),
+ mesh_out->attributes_for_write(),
ATTR_DOMAIN_FACE,
IndexMask(Vector<int64_t>(selected_poly_indices.as_span())));
copy_face_corner_attributes(attributes,
- bke::mesh_attributes(mesh_in),
- bke::mesh_attributes_for_write(*mesh_out),
+ mesh_in.attributes(),
+ mesh_out->attributes_for_write(),
selected_loops_num,
selected_poly_indices,
mesh_in);
@@ -967,29 +992,27 @@ static void do_mesh_separation(GeometrySet &geometry_set,
selected_polys_num);
/* Copy the selected parts of the mesh over to the new mesh. */
- memcpy(mesh_out->mvert, mesh_in.mvert, mesh_in.totvert * sizeof(MVert));
+ mesh_out->verts_for_write().copy_from(mesh_in.verts());
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);
/* Copy attributes. */
- copy_attributes(attributes,
- bke::mesh_attributes(mesh_in),
- bke::mesh_attributes_for_write(*mesh_out),
- {ATTR_DOMAIN_POINT});
+ copy_attributes(
+ attributes, mesh_in.attributes(), mesh_out->attributes_for_write(), {ATTR_DOMAIN_POINT});
copy_attributes_based_on_map(attributes,
- bke::mesh_attributes(mesh_in),
- bke::mesh_attributes_for_write(*mesh_out),
+ mesh_in.attributes(),
+ mesh_out->attributes_for_write(),
ATTR_DOMAIN_EDGE,
edge_map);
copy_attributes_based_on_mask(attributes,
- bke::mesh_attributes(mesh_in),
- bke::mesh_attributes_for_write(*mesh_out),
+ mesh_in.attributes(),
+ mesh_out->attributes_for_write(),
ATTR_DOMAIN_FACE,
IndexMask(Vector<int64_t>(selected_poly_indices.as_span())));
copy_face_corner_attributes(attributes,
- bke::mesh_attributes(mesh_in),
- bke::mesh_attributes_for_write(*mesh_out),
+ mesh_in.attributes(),
+ mesh_out->attributes_for_write(),
selected_loops_num,
selected_poly_indices,
mesh_in);
@@ -999,28 +1022,28 @@ static void do_mesh_separation(GeometrySet &geometry_set,
/* Fill all the maps based on the selection. */
switch (domain) {
case ATTR_DOMAIN_POINT:
- compute_selected_polygons_from_vertex_selection(mesh_in,
- selection,
- selected_poly_indices,
- new_loop_starts,
- &selected_polys_num,
- &selected_loops_num);
+ compute_selected_polys_from_vertex_selection(mesh_in,
+ selection,
+ selected_poly_indices,
+ new_loop_starts,
+ &selected_polys_num,
+ &selected_loops_num);
break;
case ATTR_DOMAIN_EDGE:
- compute_selected_polygons_from_edge_selection(mesh_in,
- selection,
- selected_poly_indices,
- new_loop_starts,
- &selected_polys_num,
- &selected_loops_num);
+ compute_selected_polys_from_edge_selection(mesh_in,
+ selection,
+ selected_poly_indices,
+ new_loop_starts,
+ &selected_polys_num,
+ &selected_loops_num);
break;
case ATTR_DOMAIN_FACE:
- compute_selected_polygons_from_poly_selection(mesh_in,
- selection,
- selected_poly_indices,
- new_loop_starts,
- &selected_polys_num,
- &selected_loops_num);
+ compute_selected_polys_from_poly_selection(mesh_in,
+ selection,
+ selected_poly_indices,
+ new_loop_starts,
+ &selected_polys_num,
+ &selected_loops_num);
break;
default:
BLI_assert_unreachable();
@@ -1030,23 +1053,23 @@ static void do_mesh_separation(GeometrySet &geometry_set,
&mesh_in, mesh_in.totvert, mesh_in.totedge, 0, selected_loops_num, selected_polys_num);
/* 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));
+ mesh_out->verts_for_write().copy_from(mesh_in.verts());
+ mesh_out->edges_for_write().copy_from(mesh_in.edges());
copy_masked_polys_to_new_mesh(mesh_in, *mesh_out, selected_poly_indices, new_loop_starts);
/* Copy attributes. */
copy_attributes(attributes,
- bke::mesh_attributes(mesh_in),
- bke::mesh_attributes_for_write(*mesh_out),
+ mesh_in.attributes(),
+ mesh_out->attributes_for_write(),
{ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE});
copy_attributes_based_on_mask(attributes,
- bke::mesh_attributes(mesh_in),
- bke::mesh_attributes_for_write(*mesh_out),
+ mesh_in.attributes(),
+ mesh_out->attributes_for_write(),
ATTR_DOMAIN_FACE,
IndexMask(Vector<int64_t>(selected_poly_indices.as_span())));
copy_face_corner_attributes(attributes,
- bke::mesh_attributes(mesh_in),
- bke::mesh_attributes_for_write(*mesh_out),
+ mesh_in.attributes(),
+ mesh_out->attributes_for_write(),
selected_loops_num,
selected_poly_indices,
mesh_in);
@@ -1063,11 +1086,9 @@ static void separate_mesh_selection(GeometrySet &geometry_set,
const eAttrDomain selection_domain,
const GeometryNodeDeleteGeometryMode mode)
{
- const MeshComponent &src_component = *geometry_set.get_component_for_read<MeshComponent>();
- GeometryComponentFieldContext field_context{src_component, selection_domain};
-
- fn::FieldEvaluator evaluator{field_context,
- src_component.attribute_domain_size(selection_domain)};
+ const Mesh &src_mesh = *geometry_set.get_mesh_for_read();
+ bke::MeshFieldContext field_context{src_mesh, selection_domain};
+ fn::FieldEvaluator evaluator{field_context, src_mesh.attributes().domain_size(selection_domain)};
evaluator.add(selection_field);
evaluator.evaluate();
const VArray<bool> selection = evaluator.get_evaluated<bool>(0);
@@ -1078,8 +1099,7 @@ static void separate_mesh_selection(GeometrySet &geometry_set,
const VArraySpan<bool> selection_span{selection};
- do_mesh_separation(
- geometry_set, *src_component.get_for_read(), selection_span, selection_domain, mode);
+ do_mesh_separation(geometry_set, src_mesh, selection_span, selection_domain, mode);
}
} // namespace blender::nodes::node_geo_delete_geometry_cc
@@ -1140,11 +1160,11 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
const bNode *node = static_cast<bNode *>(ptr->data);
const NodeGeometryDeleteGeometry &storage = node_storage(*node);
- const eAttrDomain domain = static_cast<eAttrDomain>(storage.domain);
+ const eAttrDomain domain = eAttrDomain(storage.domain);
uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
/* Only show the mode when it is relevant. */
@@ -1153,7 +1173,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
}
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryDeleteGeometry *data = MEM_cnew<NodeGeometryDeleteGeometry>(__func__);
data->domain = ATTR_DOMAIN_POINT;
@@ -1173,7 +1193,7 @@ static void node_geo_exec(GeoNodeExecParams params)
params.extract_input<Field<bool>>("Selection"));
const NodeGeometryDeleteGeometry &storage = node_storage(params.node());
- const eAttrDomain domain = static_cast<eAttrDomain>(storage.domain);
+ const eAttrDomain domain = eAttrDomain(storage.domain);
const GeometryNodeDeleteGeometryMode mode = (GeometryNodeDeleteGeometryMode)storage.mode;
if (domain == ATTR_DOMAIN_INSTANCE) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc
new file mode 100644
index 00000000000..091337c28cf
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc
@@ -0,0 +1,285 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifdef WITH_OPENVDB
+# include <openvdb/openvdb.h>
+# include <openvdb/tools/Interpolation.h>
+# include <openvdb/tools/PointScatter.h>
+#endif
+
+#include "DNA_node_types.h"
+#include "DNA_pointcloud_types.h"
+
+#include "BKE_pointcloud.h"
+#include "BKE_volume.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes {
+
+NODE_STORAGE_FUNCS(NodeGeometryDistributePointsInVolume)
+
+static void geo_node_distribute_points_in_volume_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Volume")).supported_type(GEO_COMPONENT_TYPE_VOLUME);
+ b.add_input<decl::Float>(N_("Density"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(100000.0f)
+ .subtype(PROP_NONE)
+ .description(N_("Number of points to sample per unit volume"));
+ b.add_input<decl::Int>(N_("Seed"))
+ .min(-10000)
+ .max(10000)
+ .description(N_("Seed used by the random number generator to generate random points"));
+ b.add_input<decl::Vector>(N_("Spacing"))
+ .default_value({0.3, 0.3, 0.3})
+ .min(0.0001f)
+ .subtype(PROP_XYZ)
+ .description(N_("Spacing between grid points"));
+ b.add_input<decl::Float>(N_("Threshold"))
+ .default_value(0.1f)
+ .min(0.0f)
+ .max(FLT_MAX)
+ .description(N_("Minimum density of a volume cell to contain a grid point"));
+ b.add_output<decl::Geometry>(N_("Points"));
+}
+
+static void geo_node_distribute_points_in_volume_layout(uiLayout *layout,
+ bContext * /*C*/,
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
+}
+
+static void node_distribute_points_in_volume_init(bNodeTree * /*tree*/, bNode *node)
+{
+ NodeGeometryDistributePointsInVolume *data = MEM_cnew<NodeGeometryDistributePointsInVolume>(
+ __func__);
+ data->mode = GEO_NODE_DISTRIBUTE_POINTS_IN_VOLUME_DENSITY_RANDOM;
+ node->storage = data;
+}
+
+static void node_distribute_points_in_volume_update(bNodeTree *ntree, bNode *node)
+{
+ const NodeGeometryDistributePointsInVolume &storage = node_storage(*node);
+ GeometryNodeDistributePointsInVolumeMode mode = GeometryNodeDistributePointsInVolumeMode(
+ storage.mode);
+
+ bNodeSocket *sock_density = static_cast<bNodeSocket *>(node->inputs.first)->next;
+ bNodeSocket *sock_seed = sock_density->next;
+ bNodeSocket *sock_spacing = sock_seed->next;
+ bNodeSocket *sock_threshold = sock_spacing->next;
+
+ nodeSetSocketAvailability(
+ ntree, sock_density, mode == GEO_NODE_DISTRIBUTE_POINTS_IN_VOLUME_DENSITY_RANDOM);
+ nodeSetSocketAvailability(
+ ntree, sock_seed, mode == GEO_NODE_DISTRIBUTE_POINTS_IN_VOLUME_DENSITY_RANDOM);
+ nodeSetSocketAvailability(
+ ntree, sock_spacing, mode == GEO_NODE_DISTRIBUTE_POINTS_IN_VOLUME_DENSITY_GRID);
+ nodeSetSocketAvailability(
+ ntree, sock_threshold, mode == GEO_NODE_DISTRIBUTE_POINTS_IN_VOLUME_DENSITY_GRID);
+}
+
+#ifdef WITH_OPENVDB
+/* Implements the interface required by #openvdb::tools::NonUniformPointScatter. */
+class PositionsVDBWrapper {
+ private:
+ float3 offset_fix_;
+ Vector<float3> &vector_;
+
+ public:
+ PositionsVDBWrapper(Vector<float3> &vector, const float3 offset_fix)
+ : offset_fix_(offset_fix), vector_(vector)
+ {
+ }
+ PositionsVDBWrapper(const PositionsVDBWrapper &wrapper) = default;
+
+ void add(const openvdb::Vec3R &pos)
+ {
+ vector_.append(float3(float(pos[0]), float(pos[1]), float(pos[2])) + offset_fix_);
+ }
+};
+
+/* Use #std::mt19937 as a random number generator,
+ * it has a very long period and thus there should be no visible patterns in the generated points.
+ */
+using RNGType = std::mt19937;
+/* Non-uniform scatter allows the amount of points to be scaled with the volume's density. */
+using NonUniformPointScatterVDB =
+ openvdb::tools::NonUniformPointScatter<PositionsVDBWrapper, RNGType>;
+
+static void point_scatter_density_random(const openvdb::FloatGrid &grid,
+ const float density,
+ const int seed,
+ Vector<float3> &r_positions)
+{
+ /* Offset points by half a voxel so that grid points are aligned with world grid points. */
+ const float3 offset_fix = {0.5f * float(grid.voxelSize().x()),
+ 0.5f * float(grid.voxelSize().y()),
+ 0.5f * float(grid.voxelSize().z())};
+ /* Setup and call into OpenVDB's point scatter API. */
+ PositionsVDBWrapper vdb_position_wrapper = PositionsVDBWrapper(r_positions, offset_fix);
+ RNGType random_generator(seed);
+ NonUniformPointScatterVDB point_scatter(vdb_position_wrapper, density, random_generator);
+ point_scatter(grid);
+}
+
+static void point_scatter_density_grid(const openvdb::FloatGrid &grid,
+ const float3 spacing,
+ const float threshold,
+ Vector<float3> &r_positions)
+{
+ const openvdb::Vec3d half_voxel(0.5, 0.5, 0.5);
+ const openvdb::Vec3d voxel_spacing(double(spacing.x) / grid.voxelSize().x(),
+ double(spacing.y) / grid.voxelSize().y(),
+ double(spacing.z) / grid.voxelSize().z());
+
+ /* Abort if spacing is zero. */
+ const double min_spacing = std::min(voxel_spacing.x(),
+ std::min(voxel_spacing.y(), voxel_spacing.z()));
+ if (std::abs(min_spacing) < 0.0001) {
+ return;
+ }
+
+ /* Iterate through tiles and voxels on the grid. */
+ for (openvdb::FloatGrid::ValueOnCIter cell = grid.cbeginValueOn(); cell; ++cell) {
+ /* Check if the cell's value meets the minimum threshold. */
+ if (cell.getValue() < threshold) {
+ continue;
+ }
+ /* Compute the bounding box of each tile/voxel. */
+ const openvdb::CoordBBox bbox = cell.getBoundingBox();
+ const openvdb::Vec3d box_min = bbox.min().asVec3d() - half_voxel;
+ const openvdb::Vec3d box_max = bbox.max().asVec3d() + half_voxel;
+
+ /* Pick a starting point rounded up to the nearest possible point. */
+ double abs_spacing_x = std::abs(voxel_spacing.x());
+ double abs_spacing_y = std::abs(voxel_spacing.y());
+ double abs_spacing_z = std::abs(voxel_spacing.z());
+ const openvdb::Vec3d start(ceil(box_min.x() / abs_spacing_x) * abs_spacing_x,
+ ceil(box_min.y() / abs_spacing_y) * abs_spacing_y,
+ ceil(box_min.z() / abs_spacing_z) * abs_spacing_z);
+
+ /* Iterate through all possible points in box. */
+ for (double x = start.x(); x < box_max.x(); x += abs_spacing_x) {
+ for (double y = start.y(); y < box_max.y(); y += abs_spacing_y) {
+ for (double z = start.z(); z < box_max.z(); z += abs_spacing_z) {
+ /* Transform with grid matrix and add point. */
+ const openvdb::Vec3d idx_pos(x, y, z);
+ const openvdb::Vec3d local_pos = grid.indexToWorld(idx_pos + half_voxel);
+ r_positions.append({float(local_pos.x()), float(local_pos.y()), float(local_pos.z())});
+ }
+ }
+ }
+ }
+}
+
+#endif /* WITH_OPENVDB */
+
+static void geo_node_distribute_points_in_volume_exec(GeoNodeExecParams params)
+{
+#ifdef WITH_OPENVDB
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Volume");
+
+ const NodeGeometryDistributePointsInVolume &storage = node_storage(params.node());
+ const GeometryNodeDistributePointsInVolumeMode mode = GeometryNodeDistributePointsInVolumeMode(
+ storage.mode);
+
+ float density;
+ int seed;
+ float3 spacing{0, 0, 0};
+ float threshold;
+ if (mode == GEO_NODE_DISTRIBUTE_POINTS_IN_VOLUME_DENSITY_RANDOM) {
+ density = params.extract_input<float>("Density");
+ seed = params.extract_input<int>("Seed");
+ }
+ else if (mode == GEO_NODE_DISTRIBUTE_POINTS_IN_VOLUME_DENSITY_GRID) {
+ spacing = params.extract_input<float3>("Spacing");
+ threshold = params.extract_input<float>("Threshold");
+ }
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (!geometry_set.has_volume()) {
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_INSTANCES});
+ return;
+ }
+ const VolumeComponent *component = geometry_set.get_component_for_read<VolumeComponent>();
+ const Volume *volume = component->get_for_read();
+
+ Vector<float3> positions;
+
+ for (const int i : IndexRange(BKE_volume_num_grids(volume))) {
+ const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, i);
+ if (volume_grid == nullptr) {
+ continue;
+ }
+
+ openvdb::GridBase::ConstPtr base_grid = BKE_volume_grid_openvdb_for_read(volume,
+ volume_grid);
+ if (!base_grid) {
+ continue;
+ }
+
+ if (!base_grid->isType<openvdb::FloatGrid>()) {
+ continue;
+ }
+
+ const openvdb::FloatGrid::ConstPtr grid = openvdb::gridConstPtrCast<openvdb::FloatGrid>(
+ base_grid);
+
+ if (mode == GEO_NODE_DISTRIBUTE_POINTS_IN_VOLUME_DENSITY_RANDOM) {
+ point_scatter_density_random(*grid, density, seed, positions);
+ }
+ else if (mode == GEO_NODE_DISTRIBUTE_POINTS_IN_VOLUME_DENSITY_GRID) {
+ point_scatter_density_grid(*grid, spacing, threshold, positions);
+ }
+ }
+
+ PointCloud *pointcloud = BKE_pointcloud_new_nomain(positions.size());
+ bke::MutableAttributeAccessor point_attributes = pointcloud->attributes_for_write();
+ bke::SpanAttributeWriter<float3> point_positions =
+ point_attributes.lookup_or_add_for_write_only_span<float3>("position", ATTR_DOMAIN_POINT);
+ bke::SpanAttributeWriter<float> point_radii =
+ point_attributes.lookup_or_add_for_write_only_span<float>("radius", ATTR_DOMAIN_POINT);
+
+ point_positions.span.copy_from(positions);
+ point_radii.span.fill(0.05f);
+ point_positions.finish();
+ point_radii.finish();
+
+ geometry_set.replace_pointcloud(pointcloud);
+ geometry_set.keep_only_during_modify({GEO_COMPONENT_TYPE_POINT_CLOUD});
+ });
+
+ params.set_output("Points", std::move(geometry_set));
+
+#else
+ params.set_default_remaining_outputs();
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("Disabled, Blender was compiled without OpenVDB"));
+#endif
+}
+} // namespace blender::nodes
+
+void register_node_type_geo_distribute_points_in_volume()
+{
+ static bNodeType ntype;
+ geo_node_type_base(&ntype,
+ GEO_NODE_DISTRIBUTE_POINTS_IN_VOLUME,
+ "Distribute Points in Volume",
+ NODE_CLASS_GEOMETRY);
+ node_type_storage(&ntype,
+ "NodeGeometryDistributePointsInVolume",
+ node_free_standard_storage,
+ node_copy_standard_storage);
+ node_type_init(&ntype, blender::nodes::node_distribute_points_in_volume_init);
+ node_type_update(&ntype, blender::nodes::node_distribute_points_in_volume_update);
+ node_type_size(&ntype, 170, 100, 320);
+ ntype.declare = blender::nodes::geo_node_distribute_points_in_volume_declare;
+ ntype.geometry_node_execute = blender::nodes::geo_node_distribute_points_in_volume_exec;
+ ntype.draw_buttons = blender::nodes::geo_node_distribute_points_in_volume_layout;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
index a6c67cac916..c2cc70296ed 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
@@ -62,15 +62,15 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Vector>(N_("Rotation")).subtype(PROP_EULER).field_source();
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "distribute_method", 0, "", ICON_NONE);
}
static void node_point_distribute_points_on_faces_update(bNodeTree *ntree, bNode *node)
{
- bNodeSocket *sock_distance_min = (bNodeSocket *)BLI_findlink(&node->inputs, 2);
- bNodeSocket *sock_density_max = (bNodeSocket *)sock_distance_min->next;
+ bNodeSocket *sock_distance_min = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 2));
+ bNodeSocket *sock_density_max = static_cast<bNodeSocket *>(sock_distance_min->next);
bNodeSocket *sock_density = sock_density_max->next;
bNodeSocket *sock_density_factor = sock_density->next;
nodeSetSocketAvailability(ntree,
@@ -105,20 +105,21 @@ static void sample_mesh_surface(const Mesh &mesh,
Vector<float3> &r_bary_coords,
Vector<int> &r_looptri_indices)
{
- const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
- BKE_mesh_runtime_looptri_len(&mesh)};
+ const Span<MVert> verts = mesh.verts();
+ const Span<MLoop> loops = mesh.loops();
+ const Span<MLoopTri> looptris = mesh.looptris();
for (const int looptri_index : looptris.index_range()) {
const MLoopTri &looptri = looptris[looptri_index];
const int v0_loop = looptri.tri[0];
const int v1_loop = looptri.tri[1];
const int v2_loop = looptri.tri[2];
- const int v0_index = mesh.mloop[v0_loop].v;
- const int v1_index = mesh.mloop[v1_loop].v;
- const int v2_index = mesh.mloop[v2_loop].v;
- const float3 v0_pos = float3(mesh.mvert[v0_index].co);
- const float3 v1_pos = float3(mesh.mvert[v1_index].co);
- const float3 v2_pos = float3(mesh.mvert[v2_index].co);
+ const int v0_index = loops[v0_loop].v;
+ const int v1_index = loops[v1_loop].v;
+ const int v2_index = loops[v2_loop].v;
+ const float3 v0_pos = verts[v0_index].co;
+ const float3 v1_pos = verts[v1_index].co;
+ const float3 v2_pos = verts[v2_index].co;
float looptri_density_factor = 1.0f;
if (!density_factors.is_empty()) {
@@ -184,7 +185,7 @@ BLI_NOINLINE static void update_elimination_mask_for_close_points(
kdtree,
positions[i],
minimum_distance,
- [](void *user_data, int index, const float *UNUSED(co), float UNUSED(dist_sq)) {
+ [](void *user_data, int index, const float * /*co*/, float /*dist_sq*/) {
CallbackData &callback_data = *static_cast<CallbackData *>(user_data);
if (index != callback_data.index) {
callback_data.elimination_mask[index] = true;
@@ -202,8 +203,7 @@ BLI_NOINLINE static void update_elimination_mask_based_on_density_factors(
const Span<int> looptri_indices,
const MutableSpan<bool> elimination_mask)
{
- const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
- BKE_mesh_runtime_looptri_len(&mesh)};
+ const Span<MLoopTri> looptris = mesh.looptris();
for (const int i : bary_coords.index_range()) {
if (elimination_mask[i]) {
continue;
@@ -283,15 +283,14 @@ BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh,
}
BLI_NOINLINE static void propagate_existing_attributes(
- const MeshComponent &mesh_component,
+ const Mesh &mesh,
const Map<AttributeIDRef, AttributeKind> &attributes,
- GeometryComponent &point_component,
+ PointCloud &points,
const Span<float3> bary_coords,
const Span<int> looptri_indices)
{
- const Mesh &mesh = *mesh_component.get_for_read();
- const AttributeAccessor mesh_attributes = *mesh_component.attributes();
- MutableAttributeAccessor point_attributes = *point_component.attributes_for_write();
+ const AttributeAccessor mesh_attributes = mesh.attributes();
+ MutableAttributeAccessor point_attributes = points.attributes_for_write();
for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
const AttributeIDRef attribute_id = entry.key;
@@ -326,44 +325,44 @@ struct AttributeOutputs {
};
} // namespace
-BLI_NOINLINE static void compute_attribute_outputs(const MeshComponent &mesh_component,
- PointCloudComponent &point_component,
+BLI_NOINLINE static void compute_attribute_outputs(const Mesh &mesh,
+ PointCloud &points,
const Span<float3> bary_coords,
const Span<int> looptri_indices,
const AttributeOutputs &attribute_outputs)
{
- MutableAttributeAccessor pointcloud_attributes = *point_component.attributes_for_write();
+ MutableAttributeAccessor point_attributes = points.attributes_for_write();
- SpanAttributeWriter<int> ids = pointcloud_attributes.lookup_or_add_for_write_only_span<int>(
+ SpanAttributeWriter<int> ids = point_attributes.lookup_or_add_for_write_only_span<int>(
"id", ATTR_DOMAIN_POINT);
SpanAttributeWriter<float3> normals;
SpanAttributeWriter<float3> rotations;
if (attribute_outputs.normal_id) {
- normals = pointcloud_attributes.lookup_or_add_for_write_only_span<float3>(
+ normals = point_attributes.lookup_or_add_for_write_only_span<float3>(
attribute_outputs.normal_id.get(), ATTR_DOMAIN_POINT);
}
if (attribute_outputs.rotation_id) {
- rotations = pointcloud_attributes.lookup_or_add_for_write_only_span<float3>(
+ rotations = point_attributes.lookup_or_add_for_write_only_span<float3>(
attribute_outputs.rotation_id.get(), ATTR_DOMAIN_POINT);
}
- const Mesh &mesh = *mesh_component.get_for_read();
- const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
- BKE_mesh_runtime_looptri_len(&mesh)};
+ const Span<MVert> verts = mesh.verts();
+ const Span<MLoop> loops = mesh.loops();
+ const Span<MLoopTri> looptris = mesh.looptris();
for (const int i : bary_coords.index_range()) {
const int looptri_index = looptri_indices[i];
const MLoopTri &looptri = looptris[looptri_index];
const float3 &bary_coord = bary_coords[i];
- const int v0_index = mesh.mloop[looptri.tri[0]].v;
- const int v1_index = mesh.mloop[looptri.tri[1]].v;
- const int v2_index = mesh.mloop[looptri.tri[2]].v;
- const float3 v0_pos = float3(mesh.mvert[v0_index].co);
- const float3 v1_pos = float3(mesh.mvert[v1_index].co);
- const float3 v2_pos = float3(mesh.mvert[v2_index].co);
+ const int v0_index = loops[looptri.tri[0]].v;
+ const int v1_index = loops[looptri.tri[1]].v;
+ const int v2_index = loops[looptri.tri[2]].v;
+ const float3 v0_pos = verts[v0_index].co;
+ const float3 v1_pos = verts[v1_index].co;
+ const float3 v2_pos = verts[v2_index].co;
ids.span[i] = noise::hash(noise::hash_float(bary_coord), looptri_index);
@@ -380,25 +379,19 @@ BLI_NOINLINE static void compute_attribute_outputs(const MeshComponent &mesh_com
}
ids.finish();
-
- if (normals) {
- normals.finish();
- }
- if (rotations) {
- rotations.finish();
- }
+ normals.finish();
+ rotations.finish();
}
-static Array<float> calc_full_density_factors_with_selection(const MeshComponent &component,
+static Array<float> calc_full_density_factors_with_selection(const Mesh &mesh,
const Field<float> &density_field,
const Field<bool> &selection_field)
{
- const eAttrDomain attribute_domain = ATTR_DOMAIN_CORNER;
- GeometryComponentFieldContext field_context{component, attribute_domain};
- const int domain_size = component.attribute_domain_size(attribute_domain);
-
+ const eAttrDomain domain = ATTR_DOMAIN_CORNER;
+ const int domain_size = mesh.attributes().domain_size(domain);
Array<float> densities(domain_size, 0.0f);
+ bke::MeshFieldContext field_context{mesh, domain};
fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.set_selection(selection_field);
evaluator.add_with_destination(density_field, densities.as_mutable_span());
@@ -406,7 +399,7 @@ static Array<float> calc_full_density_factors_with_selection(const MeshComponent
return densities;
}
-static void distribute_points_random(const MeshComponent &component,
+static void distribute_points_random(const Mesh &mesh,
const Field<float> &density_field,
const Field<bool> &selection_field,
const int seed,
@@ -415,12 +408,11 @@ static void distribute_points_random(const MeshComponent &component,
Vector<int> &looptri_indices)
{
const Array<float> densities = calc_full_density_factors_with_selection(
- component, density_field, selection_field);
- const Mesh &mesh = *component.get_for_read();
+ mesh, density_field, selection_field);
sample_mesh_surface(mesh, 1.0f, densities, seed, positions, bary_coords, looptri_indices);
}
-static void distribute_points_poisson_disk(const MeshComponent &mesh_component,
+static void distribute_points_poisson_disk(const Mesh &mesh,
const float minimum_distance,
const float max_density,
const Field<float> &density_factor_field,
@@ -430,14 +422,13 @@ static void distribute_points_poisson_disk(const MeshComponent &mesh_component,
Vector<float3> &bary_coords,
Vector<int> &looptri_indices)
{
- const Mesh &mesh = *mesh_component.get_for_read();
sample_mesh_surface(mesh, max_density, {}, seed, positions, bary_coords, looptri_indices);
Array<bool> elimination_mask(positions.size(), false);
update_elimination_mask_for_close_points(positions, minimum_distance, elimination_mask);
const Array<float> density_factors = calc_full_density_factors_with_selection(
- mesh_component, density_factor_field, selection_field);
+ mesh, density_factor_field, selection_field);
update_elimination_mask_based_on_density_factors(
mesh, density_factors, bary_coords, looptri_indices, elimination_mask.as_mutable_span());
@@ -457,7 +448,7 @@ static void point_distribution_calculate(GeometrySet &geometry_set,
return;
}
- const MeshComponent &mesh_component = *geometry_set.get_component_for_read<MeshComponent>();
+ const Mesh &mesh = *geometry_set.get_mesh_for_read();
Vector<float3> positions;
Vector<float3> bary_coords;
@@ -466,20 +457,15 @@ static void point_distribution_calculate(GeometrySet &geometry_set,
switch (method) {
case GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_RANDOM: {
const Field<float> density_field = params.get_input<Field<float>>("Density");
- distribute_points_random(mesh_component,
- density_field,
- selection_field,
- seed,
- positions,
- bary_coords,
- looptri_indices);
+ distribute_points_random(
+ mesh, density_field, selection_field, seed, positions, bary_coords, looptri_indices);
break;
}
case GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON: {
const float minimum_distance = params.get_input<float>("Distance Min");
const float density_max = params.get_input<float>("Density Max");
const Field<float> density_factors_field = params.get_input<Field<float>>("Density Factor");
- distribute_points_poisson_disk(mesh_component,
+ distribute_points_poisson_disk(mesh,
minimum_distance,
density_max,
density_factors_field,
@@ -497,8 +483,7 @@ static void point_distribution_calculate(GeometrySet &geometry_set,
}
PointCloud *pointcloud = BKE_pointcloud_new_nomain(positions.size());
- bke::MutableAttributeAccessor point_attributes = bke::pointcloud_attributes_for_write(
- *pointcloud);
+ bke::MutableAttributeAccessor point_attributes = pointcloud->attributes_for_write();
bke::SpanAttributeWriter<float3> point_positions =
point_attributes.lookup_or_add_for_write_only_span<float3>("position", ATTR_DOMAIN_POINT);
bke::SpanAttributeWriter<float> point_radii =
@@ -510,9 +495,6 @@ static void point_distribution_calculate(GeometrySet &geometry_set,
geometry_set.replace_pointcloud(pointcloud);
- PointCloudComponent &point_component =
- geometry_set.get_component_for_write<PointCloudComponent>();
-
Map<AttributeIDRef, AttributeKind> attributes;
geometry_set.gather_attributes_for_propagation(
{GEO_COMPONENT_TYPE_MESH}, GEO_COMPONENT_TYPE_POINT_CLOUD, false, attributes);
@@ -520,19 +502,17 @@ static void point_distribution_calculate(GeometrySet &geometry_set,
/* Position is set separately. */
attributes.remove("position");
- propagate_existing_attributes(
- mesh_component, attributes, point_component, bary_coords, looptri_indices);
+ propagate_existing_attributes(mesh, attributes, *pointcloud, bary_coords, looptri_indices);
- compute_attribute_outputs(
- mesh_component, point_component, bary_coords, looptri_indices, attribute_outputs);
+ compute_attribute_outputs(mesh, *pointcloud, bary_coords, looptri_indices, attribute_outputs);
}
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
- const GeometryNodeDistributePointsOnFacesMode method =
- static_cast<GeometryNodeDistributePointsOnFacesMode>(params.node().custom1);
+ const GeometryNodeDistributePointsOnFacesMode method = GeometryNodeDistributePointsOnFacesMode(
+ params.node().custom1);
const int seed = params.get_input<int>("Seed") * 5383843;
const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -545,6 +525,8 @@ static void node_geo_exec(GeoNodeExecParams params)
attribute_outputs.rotation_id = StrongAnonymousAttributeID("Rotation");
}
+ lazy_threading::send_hint();
+
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
point_distribution_calculate(
geometry_set, selection_field, method, seed, attribute_outputs, params);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
index 76eeee95239..84e63845b84 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
@@ -209,13 +209,18 @@ static void calc_boundaries(const Mesh &mesh,
{
BLI_assert(r_vertex_types.size() == mesh.totvert);
BLI_assert(r_edge_types.size() == mesh.totedge);
+ const Span<MEdge> edges = mesh.edges();
+ const Span<MPoly> polys = mesh.polys();
+ const Span<MLoop> loops = mesh.loops();
+
r_vertex_types.fill(VertexType::Loose);
r_edge_types.fill(EdgeType::Loose);
/* Add up the number of polys connected to each edge. */
for (const int i : IndexRange(mesh.totpoly)) {
- const MPoly &poly = mesh.mpoly[i];
- for (const MLoop &loop : Span<MLoop>(&mesh.mloop[poly.loopstart], poly.totloop)) {
+ const MPoly &poly = polys[i];
+ const Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
+ for (const MLoop &loop : poly_loops) {
r_edge_types[loop.e] = get_edge_type_with_added_neighbor(r_edge_types[loop.e]);
}
}
@@ -226,7 +231,7 @@ static void calc_boundaries(const Mesh &mesh,
if (edge_type == EdgeType::Loose) {
continue;
}
- const MEdge &edge = mesh.medge[i];
+ const MEdge &edge = edges[i];
if (edge_type == EdgeType::Boundary) {
r_vertex_types[edge.v1] = get_vertex_type_with_added_neighbor(r_vertex_types[edge.v1]);
r_vertex_types[edge.v2] = get_vertex_type_with_added_neighbor(r_vertex_types[edge.v2]);
@@ -241,7 +246,7 @@ static void calc_boundaries(const Mesh &mesh,
for (const int i : IndexRange(mesh.totedge)) {
const EdgeType edge_type = r_edge_types[i];
if (edge_type == EdgeType::Normal) {
- const MEdge &edge = mesh.medge[i];
+ const MEdge &edge = edges[i];
if (r_vertex_types[edge.v1] == VertexType::Loose) {
r_vertex_types[edge.v1] = VertexType::Normal;
}
@@ -258,9 +263,12 @@ static void calc_boundaries(const Mesh &mesh,
static void create_vertex_poly_map(const Mesh &mesh,
MutableSpan<Vector<int>> r_vertex_poly_indices)
{
- for (const int i : IndexRange(mesh.totpoly)) {
- const MPoly &poly = mesh.mpoly[i];
- for (const MLoop &loop : Span<MLoop>(&mesh.mloop[poly.loopstart], poly.totloop)) {
+ const Span<MPoly> polys = mesh.polys();
+ const Span<MLoop> loops = mesh.loops();
+ for (const int i : polys.index_range()) {
+ const MPoly &poly = polys[i];
+ const Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
+ for (const MLoop &loop : poly_loops) {
r_vertex_poly_indices[loop.v].append(i);
}
}
@@ -321,26 +329,28 @@ static void create_vertex_poly_map(const Mesh &mesh,
* - Finally if we are in the normal case we also need to add the last "shared edge" to close the
* loop.
*/
-static bool sort_vertex_polys(const Mesh &mesh,
+static bool sort_vertex_polys(const Span<MEdge> edges,
+ const Span<MPoly> polys,
+ const Span<MLoop> loops,
const int vertex_index,
const bool boundary_vertex,
const Span<EdgeType> edge_types,
- MutableSpan<int> connected_polygons,
+ MutableSpan<int> connected_polys,
MutableSpan<int> r_shared_edges,
MutableSpan<int> r_sorted_corners)
{
- if (connected_polygons.size() <= 2 && (!boundary_vertex || connected_polygons.size() == 0)) {
+ if (connected_polys.size() <= 2 && (!boundary_vertex || connected_polys.size() == 0)) {
return true;
}
/* For each polygon store the two corners whose edge contains the vertex. */
- Array<std::pair<int, int>> poly_vertex_corners(connected_polygons.size());
- for (const int i : connected_polygons.index_range()) {
- const MPoly &poly = mesh.mpoly[connected_polygons[i]];
+ Array<std::pair<int, int>> poly_vertex_corners(connected_polys.size());
+ for (const int i : connected_polys.index_range()) {
+ const MPoly &poly = polys[connected_polys[i]];
bool first_edge_done = false;
for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- const MLoop &loop = mesh.mloop[loop_index];
- if (mesh.medge[loop.e].v1 == vertex_index || mesh.medge[loop.e].v2 == vertex_index) {
+ const MLoop &loop = loops[loop_index];
+ if (edges[loop.e].v1 == vertex_index || edges[loop.e].v2 == vertex_index) {
if (!first_edge_done) {
poly_vertex_corners[i].first = loop_index;
first_edge_done = true;
@@ -359,20 +369,20 @@ static bool sort_vertex_polys(const Mesh &mesh,
* the loop to determine the 'average' orientation. */
if (boundary_vertex) {
/* Our first polygon needs to be one which has a boundary edge. */
- for (const int i : connected_polygons.index_range()) {
- const MLoop &first_loop = mesh.mloop[poly_vertex_corners[i].first];
- const MLoop &second_loop = mesh.mloop[poly_vertex_corners[i].second];
+ for (const int i : connected_polys.index_range()) {
+ const MLoop &first_loop = loops[poly_vertex_corners[i].first];
+ const MLoop &second_loop = loops[poly_vertex_corners[i].second];
if (edge_types[first_loop.e] == EdgeType::Boundary && first_loop.v == vertex_index) {
shared_edge_i = second_loop.e;
r_sorted_corners[0] = poly_vertex_corners[i].first;
- std::swap(connected_polygons[i], connected_polygons[0]);
+ std::swap(connected_polys[i], connected_polys[0]);
std::swap(poly_vertex_corners[i], poly_vertex_corners[0]);
break;
}
if (edge_types[second_loop.e] == EdgeType::Boundary && second_loop.v == vertex_index) {
shared_edge_i = first_loop.e;
r_sorted_corners[0] = poly_vertex_corners[i].second;
- std::swap(connected_polygons[i], connected_polygons[0]);
+ std::swap(connected_polys[i], connected_polys[0]);
std::swap(poly_vertex_corners[i], poly_vertex_corners[0]);
break;
}
@@ -380,20 +390,20 @@ static bool sort_vertex_polys(const Mesh &mesh,
if (shared_edge_i == -1) {
/* The rotation is inconsistent between the two polygons on the boundary. Just choose one
* of the polygon's orientation. */
- for (const int i : connected_polygons.index_range()) {
- const MLoop &first_loop = mesh.mloop[poly_vertex_corners[i].first];
- const MLoop &second_loop = mesh.mloop[poly_vertex_corners[i].second];
+ for (const int i : connected_polys.index_range()) {
+ const MLoop &first_loop = loops[poly_vertex_corners[i].first];
+ const MLoop &second_loop = loops[poly_vertex_corners[i].second];
if (edge_types[first_loop.e] == EdgeType::Boundary) {
shared_edge_i = second_loop.e;
r_sorted_corners[0] = poly_vertex_corners[i].first;
- std::swap(connected_polygons[i], connected_polygons[0]);
+ std::swap(connected_polys[i], connected_polys[0]);
std::swap(poly_vertex_corners[i], poly_vertex_corners[0]);
break;
}
if (edge_types[second_loop.e] == EdgeType::Boundary) {
shared_edge_i = first_loop.e;
r_sorted_corners[0] = poly_vertex_corners[i].second;
- std::swap(connected_polygons[i], connected_polygons[0]);
+ std::swap(connected_polys[i], connected_polys[0]);
std::swap(poly_vertex_corners[i], poly_vertex_corners[0]);
break;
}
@@ -402,8 +412,8 @@ static bool sort_vertex_polys(const Mesh &mesh,
}
else {
/* Any polygon can be the first. Just need to check the orientation. */
- const MLoop &first_loop = mesh.mloop[poly_vertex_corners[0].first];
- const MLoop &second_loop = mesh.mloop[poly_vertex_corners[0].second];
+ const MLoop &first_loop = loops[poly_vertex_corners[0].first];
+ const MLoop &second_loop = loops[poly_vertex_corners[0].second];
if (first_loop.v == vertex_index) {
shared_edge_i = second_loop.e;
r_sorted_corners[0] = poly_vertex_corners[0].first;
@@ -415,14 +425,14 @@ static bool sort_vertex_polys(const Mesh &mesh,
}
BLI_assert(shared_edge_i != -1);
- for (const int i : IndexRange(connected_polygons.size() - 1)) {
+ for (const int i : IndexRange(connected_polys.size() - 1)) {
r_shared_edges[i] = shared_edge_i;
/* Look at the other polys to see if it has this shared edge. */
int j = i + 1;
- for (; j < connected_polygons.size(); ++j) {
- const MLoop &first_loop = mesh.mloop[poly_vertex_corners[j].first];
- const MLoop &second_loop = mesh.mloop[poly_vertex_corners[j].second];
+ for (; j < connected_polys.size(); ++j) {
+ const MLoop &first_loop = loops[poly_vertex_corners[j].first];
+ const MLoop &second_loop = loops[poly_vertex_corners[j].second];
if (first_loop.e == shared_edge_i) {
r_sorted_corners[i + 1] = poly_vertex_corners[j].first;
shared_edge_i = second_loop.e;
@@ -434,13 +444,13 @@ static bool sort_vertex_polys(const Mesh &mesh,
break;
}
}
- if (j == connected_polygons.size()) {
+ if (j == connected_polys.size()) {
/* The vertex is not manifold because the polygons around the vertex don't form a loop, and
* hence can't be sorted. */
return false;
}
- std::swap(connected_polygons[i + 1], connected_polygons[j]);
+ std::swap(connected_polys[i + 1], connected_polys[j]);
std::swap(poly_vertex_corners[i + 1], poly_vertex_corners[j]);
}
@@ -455,14 +465,16 @@ static bool sort_vertex_polys(const Mesh &mesh,
* Get the edge on the poly that contains the given vertex and is a boundary edge.
*/
static void boundary_edge_on_poly(const MPoly &poly,
- const Mesh &mesh,
+ const Span<MEdge> edges,
+ const Span<MLoop> loops,
const int vertex_index,
const Span<EdgeType> edge_types,
int &r_edge)
{
- for (const MLoop &loop : Span<MLoop>(&mesh.mloop[poly.loopstart], poly.totloop)) {
+ const Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
+ for (const MLoop &loop : poly_loops) {
if (edge_types[loop.e] == EdgeType::Boundary) {
- const MEdge &edge = mesh.medge[loop.e];
+ const MEdge &edge = edges[loop.e];
if (edge.v1 == vertex_index || edge.v2 == vertex_index) {
r_edge = loop.e;
return;
@@ -476,7 +488,8 @@ static void boundary_edge_on_poly(const MPoly &poly,
* orientation of the poly is taken into account.
*/
static void boundary_edges_on_poly(const MPoly &poly,
- const Mesh &mesh,
+ const Span<MEdge> edges,
+ const Span<MLoop> loops,
const int vertex_index,
const Span<EdgeType> edge_types,
int &r_edge1,
@@ -486,9 +499,10 @@ static void boundary_edges_on_poly(const MPoly &poly,
/* This is set to true if the order in which we encounter the two edges is inconsistent with the
* orientation of the polygon. */
bool needs_swap = false;
- for (const MLoop &loop : Span<MLoop>(&mesh.mloop[poly.loopstart], poly.totloop)) {
+ const Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
+ for (const MLoop &loop : poly_loops) {
if (edge_types[loop.e] == EdgeType::Boundary) {
- const MEdge &edge = mesh.medge[loop.e];
+ const MEdge &edge = edges[loop.e];
if (edge.v1 == vertex_index || edge.v2 == vertex_index) {
if (edge1_done) {
if (needs_swap) {
@@ -510,7 +524,7 @@ static void boundary_edges_on_poly(const MPoly &poly,
}
}
-static void add_edge(const Mesh &mesh,
+static void add_edge(const Span<MEdge> src_edges,
const int old_edge_i,
const int v1,
const int v2,
@@ -518,7 +532,7 @@ static void add_edge(const Mesh &mesh,
Vector<MEdge> &new_edges,
Vector<int> &loop_edges)
{
- MEdge new_edge = MEdge(mesh.medge[old_edge_i]);
+ MEdge new_edge = src_edges[old_edge_i];
new_edge.v1 = v1;
new_edge.v2 = v2;
const int new_edge_i = new_edges.size();
@@ -549,14 +563,17 @@ static bool vertex_needs_dissolving(const int vertex,
* edges in the input mesh which contain such a vertex are marked as 'done' to prevent duplicate
* edges being created. (See T94144)
*/
-static void dissolve_redundant_verts(const Mesh &mesh,
+static void dissolve_redundant_verts(const Span<MEdge> edges,
+ const Span<MPoly> polys,
+ const Span<MLoop> loops,
const Span<Vector<int>> vertex_poly_indices,
MutableSpan<VertexType> vertex_types,
MutableSpan<int> old_to_new_edges_map,
Vector<MEdge> &new_edges,
Vector<int> &new_to_old_edges_map)
{
- for (const int vert_i : IndexRange(mesh.totvert)) {
+ const int vertex_num = vertex_types.size();
+ for (const int vert_i : IndexRange(vertex_num)) {
if (vertex_poly_indices[vert_i].size() != 2 || vertex_types[vert_i] != VertexType::Normal) {
continue;
}
@@ -564,9 +581,10 @@ static void dissolve_redundant_verts(const Mesh &mesh,
const int second_poly_index = vertex_poly_indices[vert_i][1];
const int new_edge_index = new_edges.size();
bool edge_created = false;
- const MPoly &poly = mesh.mpoly[first_poly_index];
- for (const MLoop &loop : Span<MLoop>(&mesh.mloop[poly.loopstart], poly.totloop)) {
- const MEdge &edge = mesh.medge[loop.e];
+ const MPoly &poly = polys[first_poly_index];
+ const Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
+ for (const MLoop &loop : poly_loops) {
+ const MEdge &edge = edges[loop.e];
const int v1 = edge.v1;
const int v2 = edge.v2;
bool mark_edge = false;
@@ -617,6 +635,10 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
const bool keep_boundaries)
{
const Mesh &mesh_in = *in_component.get_for_read();
+ const Span<MVert> src_verts = mesh_in.verts();
+ const Span<MEdge> src_edges = mesh_in.edges();
+ const Span<MPoly> src_polys = mesh_in.polys();
+ const Span<MLoop> src_loops = mesh_in.loops();
Map<AttributeIDRef, AttributeKind> attributes;
geometry_set.gather_attributes_for_propagation(
@@ -644,14 +666,28 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
bool vertex_ok = true;
if (vertex_types[i] == VertexType::Normal) {
Array<int> shared_edges(loop_indices.size());
- vertex_ok = sort_vertex_polys(
- mesh_in, i, false, edge_types, loop_indices, shared_edges, sorted_corners);
+ vertex_ok = sort_vertex_polys(src_edges,
+ src_polys,
+ src_loops,
+ i,
+ false,
+ edge_types,
+ loop_indices,
+ shared_edges,
+ sorted_corners);
vertex_shared_edges[i] = std::move(shared_edges);
}
else {
Array<int> shared_edges(loop_indices.size() - 1);
- vertex_ok = sort_vertex_polys(
- mesh_in, i, true, edge_types, loop_indices, shared_edges, sorted_corners);
+ vertex_ok = sort_vertex_polys(src_edges,
+ src_polys,
+ src_loops,
+ i,
+ true,
+ edge_types,
+ loop_indices,
+ shared_edges,
+ sorted_corners);
vertex_shared_edges[i] = std::move(shared_edges);
}
if (!vertex_ok) {
@@ -666,9 +702,9 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
Vector<float3> vertex_positions(mesh_in.totpoly);
for (const int i : IndexRange(mesh_in.totpoly)) {
- const MPoly poly = mesh_in.mpoly[i];
+ const MPoly &poly = src_polys[i];
BKE_mesh_calc_poly_center(
- &poly, &mesh_in.mloop[poly.loopstart], mesh_in.mvert, vertex_positions[i]);
+ &poly, &src_loops[poly.loopstart], src_verts.data(), vertex_positions[i]);
}
Array<int> boundary_edge_midpoint_index;
@@ -679,8 +715,8 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
for (const int i : IndexRange(mesh_in.totedge)) {
if (edge_types[i] == EdgeType::Boundary) {
float3 mid;
- const MEdge &edge = mesh_in.medge[i];
- mid_v3_v3v3(mid, mesh_in.mvert[edge.v1].co, mesh_in.mvert[edge.v2].co);
+ const MEdge &edge = src_edges[i];
+ mid_v3_v3v3(mid, src_verts[edge.v1].co, src_verts[edge.v2].co);
boundary_edge_midpoint_index[i] = vertex_positions.size();
vertex_positions.append(mid);
}
@@ -706,7 +742,9 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
/* This is necessary to prevent duplicate edges from being created, but will likely not do
* anything for most meshes. */
- dissolve_redundant_verts(mesh_in,
+ dissolve_redundant_verts(src_edges,
+ src_polys,
+ src_loops,
vertex_poly_indices,
vertex_types,
old_to_new_edges_map,
@@ -734,7 +772,7 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
const int old_edge_i = shared_edges[i];
if (old_to_new_edges_map[old_edge_i] == -1) {
/* This edge has not been created yet. */
- MEdge new_edge = MEdge(mesh_in.medge[old_edge_i]);
+ MEdge new_edge = src_edges[old_edge_i];
new_edge.v1 = loop_indices[i];
new_edge.v2 = loop_indices[(i + 1) % loop_indices.size()];
new_to_old_edges_map.append(old_edge_i);
@@ -776,7 +814,7 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
const int old_edge_i = shared_edges[i];
if (old_to_new_edges_map[old_edge_i] == -1) {
/* This edge has not been created yet. */
- MEdge new_edge = MEdge(mesh_in.medge[old_edge_i]);
+ MEdge new_edge = src_edges[old_edge_i];
new_edge.v1 = loop_indices[i];
new_edge.v2 = loop_indices[i + 1];
new_to_old_edges_map.append(old_edge_i);
@@ -795,13 +833,15 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
int edge2;
if (loop_indices.size() >= 2) {
/* The first boundary edge is at the end of the chain of polygons. */
- boundary_edge_on_poly(mesh_in.mpoly[loop_indices.last()], mesh_in, i, edge_types, edge1);
- boundary_edge_on_poly(mesh_in.mpoly[loop_indices.first()], mesh_in, i, edge_types, edge2);
+ boundary_edge_on_poly(
+ src_polys[loop_indices.last()], src_edges, src_loops, i, edge_types, edge1);
+ boundary_edge_on_poly(
+ src_polys[loop_indices.first()], src_edges, src_loops, i, edge_types, edge2);
}
else {
/* If there is only one polygon both edges are in that polygon. */
boundary_edges_on_poly(
- mesh_in.mpoly[loop_indices[0]], mesh_in, i, edge_types, edge1, edge2);
+ src_polys[loop_indices[0]], src_edges, src_loops, i, edge_types, edge1, edge2);
}
const int last_face_center = loop_indices.last();
@@ -809,7 +849,7 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
new_to_old_face_corners_map.append(sorted_corners.last());
const int first_midpoint = loop_indices.last();
if (old_to_new_edges_map[edge1] == -1) {
- add_edge(mesh_in,
+ add_edge(src_edges,
edge1,
last_face_center,
first_midpoint,
@@ -827,9 +867,9 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
new_to_old_face_corners_map.append(sorted_corners.first());
boundary_vertex_to_relevant_face_map.append(
std::pair(loop_indices.last(), last_face_center));
- vertex_positions.append(mesh_in.mvert[i].co);
+ vertex_positions.append(src_verts[i].co);
const int boundary_vertex = loop_indices.last();
- add_edge(mesh_in,
+ add_edge(src_edges,
edge1,
first_midpoint,
boundary_vertex,
@@ -840,7 +880,7 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
loop_indices.append(boundary_edge_midpoint_index[edge2]);
new_to_old_face_corners_map.append(sorted_corners.first());
const int second_midpoint = loop_indices.last();
- add_edge(mesh_in,
+ add_edge(src_edges,
edge2,
boundary_vertex,
second_midpoint,
@@ -850,7 +890,7 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
if (old_to_new_edges_map[edge2] == -1) {
const int first_face_center = loop_indices.first();
- add_edge(mesh_in,
+ add_edge(src_edges,
edge2,
second_midpoint,
first_face_center,
@@ -878,23 +918,28 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
new_to_old_edges_map,
new_to_old_face_corners_map,
boundary_vertex_to_relevant_face_map,
- bke::mesh_attributes(mesh_in),
- bke::mesh_attributes_for_write(*mesh_out));
+ mesh_in.attributes(),
+ mesh_out->attributes_for_write());
+
+ MutableSpan<MVert> dst_verts = mesh_out->verts_for_write();
+ MutableSpan<MEdge> dst_edges = mesh_out->edges_for_write();
+ MutableSpan<MPoly> dst_polys = mesh_out->polys_for_write();
+ MutableSpan<MLoop> dst_loops = mesh_out->loops_for_write();
int loop_start = 0;
for (const int i : IndexRange(mesh_out->totpoly)) {
- mesh_out->mpoly[i].loopstart = loop_start;
- mesh_out->mpoly[i].totloop = loop_lengths[i];
+ dst_polys[i].loopstart = loop_start;
+ dst_polys[i].totloop = loop_lengths[i];
loop_start += loop_lengths[i];
}
for (const int i : IndexRange(mesh_out->totloop)) {
- mesh_out->mloop[i].v = loops[i];
- mesh_out->mloop[i].e = loop_edges[i];
+ dst_loops[i].v = loops[i];
+ dst_loops[i].e = loop_edges[i];
}
for (const int i : IndexRange(mesh_out->totvert)) {
- copy_v3_v3(mesh_out->mvert[i].co, vertex_positions[i]);
+ copy_v3_v3(dst_verts[i].co, vertex_positions[i]);
}
- memcpy(mesh_out->medge, new_edges.data(), sizeof(MEdge) * new_edges.size());
+ dst_edges.copy_from(new_edges);
geometry_set.replace_mesh(mesh_out);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
index c6b0fb4c068..70583625a7a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
@@ -11,6 +11,7 @@
#include "BKE_attribute_math.hh"
#include "BKE_curves.hh"
+#include "BKE_instances.hh"
#include "BKE_mesh.h"
#include "BKE_pointcloud.h"
@@ -40,14 +41,14 @@ static void node_declare(NodeDeclarationBuilder &b)
.description(N_("The indices of the duplicates for each element"));
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryDuplicateElements *data = MEM_cnew<NodeGeometryDuplicateElements>(__func__);
data->domain = ATTR_DOMAIN_POINT;
node->storage = data;
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
}
@@ -334,11 +335,10 @@ static void duplicate_curves(GeometrySet &geometry_set,
geometry_set.keep_only_during_modify({GEO_COMPONENT_TYPE_CURVE});
GeometryComponentEditData::remember_deformed_curve_positions_if_necessary(geometry_set);
- const CurveComponent &src_component = *geometry_set.get_component_for_read<CurveComponent>();
- const Curves &curves_id = *src_component.get_for_read();
+ const Curves &curves_id = *geometry_set.get_curves_for_read();
const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
- GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_CURVE};
+ bke::CurvesFieldContext field_context{curves, ATTR_DOMAIN_CURVE};
FieldEvaluator evaluator{field_context, curves.curves_num()};
evaluator.add(count_field);
evaluator.set_selection(selection_field);
@@ -487,7 +487,7 @@ static void copy_stable_id_faces(const Mesh &mesh,
VArraySpan<int> src{src_attribute.varray.typed<int>()};
MutableSpan<int> dst = dst_attribute.span.typed<int>();
- Span<MPoly> polys(mesh.mpoly, mesh.totpoly);
+ const Span<MPoly> polys = mesh.polys();
int loop_index = 0;
for (const int i_poly : selection.index_range()) {
const IndexRange range = range_for_offsets_index(poly_offsets, i_poly);
@@ -522,14 +522,13 @@ static void duplicate_faces(GeometrySet &geometry_set,
}
geometry_set.keep_only_during_modify({GEO_COMPONENT_TYPE_MESH});
- const MeshComponent &src_component = *geometry_set.get_component_for_read<MeshComponent>();
- const Mesh &mesh = *src_component.get_for_read();
- Span<MVert> verts(mesh.mvert, mesh.totvert);
- Span<MEdge> edges(mesh.medge, mesh.totedge);
- Span<MPoly> polys(mesh.mpoly, mesh.totpoly);
- Span<MLoop> loops(mesh.mloop, mesh.totloop);
+ const Mesh &mesh = *geometry_set.get_mesh_for_read();
+ const Span<MVert> verts = mesh.verts();
+ const Span<MEdge> edges = mesh.edges();
+ const Span<MPoly> polys = mesh.polys();
+ const Span<MLoop> loops = mesh.loops();
- GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_FACE};
+ bke::MeshFieldContext field_context{mesh, ATTR_DOMAIN_FACE};
FieldEvaluator evaluator(field_context, polys.size());
evaluator.add(count_field);
evaluator.set_selection(selection_field);
@@ -549,10 +548,10 @@ static void duplicate_faces(GeometrySet &geometry_set,
offsets[selection.size()] = total_polys;
Mesh *new_mesh = BKE_mesh_new_nomain(total_loops, total_loops, 0, total_loops, total_polys);
- MutableSpan<MVert> new_verts(new_mesh->mvert, new_mesh->totvert);
- MutableSpan<MEdge> new_edges(new_mesh->medge, new_mesh->totedge);
- MutableSpan<MLoop> new_loops(new_mesh->mloop, new_mesh->totloop);
- MutableSpan<MPoly> new_poly(new_mesh->mpoly, new_mesh->totpoly);
+ MutableSpan<MVert> new_verts = new_mesh->verts_for_write();
+ MutableSpan<MEdge> new_edges = new_mesh->edges_for_write();
+ MutableSpan<MPoly> new_polys = new_mesh->polys_for_write();
+ MutableSpan<MLoop> new_loops = new_mesh->loops_for_write();
Array<int> vert_mapping(new_verts.size());
Array<int> edge_mapping(new_edges.size());
@@ -565,8 +564,8 @@ static void duplicate_faces(GeometrySet &geometry_set,
const MPoly &source = polys[selection[i_selection]];
for ([[maybe_unused]] const int i_duplicate : IndexRange(poly_range.size())) {
- new_poly[poly_index] = source;
- new_poly[poly_index].loopstart = loop_index;
+ new_polys[poly_index] = source;
+ new_polys[poly_index].loopstart = loop_index;
for (const int i_loops : IndexRange(source.totloop)) {
const MLoop &current_loop = loops[source.loopstart + i_loops];
loop_mapping[loop_index] = source.loopstart + i_loops;
@@ -579,7 +578,7 @@ static void duplicate_faces(GeometrySet &geometry_set,
new_edges[loop_index].v2 = loop_index + 1;
}
else {
- new_edges[loop_index].v2 = new_poly[poly_index].loopstart;
+ new_edges[loop_index].v2 = new_polys[poly_index].loopstart;
}
new_loops[loop_index].v = loop_index;
new_loops[loop_index].e = loop_index;
@@ -595,22 +594,15 @@ static void duplicate_faces(GeometrySet &geometry_set,
loop_mapping,
offsets,
selection,
- bke::mesh_attributes(mesh),
- bke::mesh_attributes_for_write(*new_mesh));
+ mesh.attributes(),
+ new_mesh->attributes_for_write());
- copy_stable_id_faces(mesh,
- selection,
- offsets,
- vert_mapping,
- bke::mesh_attributes(mesh),
- bke::mesh_attributes_for_write(*new_mesh));
+ copy_stable_id_faces(
+ mesh, selection, offsets, vert_mapping, mesh.attributes(), new_mesh->attributes_for_write());
if (attribute_outputs.duplicate_index) {
- create_duplicate_index_attribute(bke::mesh_attributes_for_write(*new_mesh),
- ATTR_DOMAIN_FACE,
- selection,
- attribute_outputs,
- offsets);
+ create_duplicate_index_attribute(
+ new_mesh->attributes_for_write(), ATTR_DOMAIN_FACE, selection, attribute_outputs, offsets);
}
geometry_set.replace_mesh(new_mesh);
@@ -691,7 +683,7 @@ static void copy_stable_id_edges(const Mesh &mesh,
return;
}
- Span<MEdge> edges(mesh.medge, mesh.totedge);
+ const Span<MEdge> edges = mesh.edges();
VArraySpan<int> src{src_attribute.varray.typed<int>()};
MutableSpan<int> dst = dst_attribute.span.typed<int>();
@@ -724,12 +716,10 @@ static void duplicate_edges(GeometrySet &geometry_set,
geometry_set.remove_geometry_during_modify();
return;
};
- const MeshComponent &src_component = *geometry_set.get_component_for_read<MeshComponent>();
- const Mesh &mesh = *src_component.get_for_read();
- Span<MVert> verts(mesh.mvert, mesh.totvert);
- Span<MEdge> edges(mesh.medge, mesh.totedge);
+ const Mesh &mesh = *geometry_set.get_mesh_for_read();
+ const Span<MEdge> edges = mesh.edges();
- GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_EDGE};
+ bke::MeshFieldContext field_context{mesh, ATTR_DOMAIN_EDGE};
FieldEvaluator evaluator{field_context, edges.size()};
evaluator.add(count_field);
evaluator.set_selection(selection_field);
@@ -740,8 +730,7 @@ static void duplicate_edges(GeometrySet &geometry_set,
Array<int> edge_offsets = accumulate_counts_to_offsets(selection, counts);
Mesh *new_mesh = BKE_mesh_new_nomain(edge_offsets.last() * 2, edge_offsets.last(), 0, 0, 0);
- MutableSpan<MVert> new_verts(new_mesh->mvert, new_mesh->totvert);
- MutableSpan<MEdge> new_edges(new_mesh->medge, new_mesh->totedge);
+ MutableSpan<MEdge> new_edges = new_mesh->edges_for_write();
Array<int> vert_orig_indices(edge_offsets.last() * 2);
threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
@@ -774,17 +763,14 @@ static void duplicate_edges(GeometrySet &geometry_set,
vert_orig_indices,
edge_offsets,
selection,
- bke::mesh_attributes(mesh),
- bke::mesh_attributes_for_write(*new_mesh));
+ mesh.attributes(),
+ new_mesh->attributes_for_write());
- copy_stable_id_edges(mesh,
- selection,
- edge_offsets,
- bke::mesh_attributes(mesh),
- bke::mesh_attributes_for_write(*new_mesh));
+ copy_stable_id_edges(
+ mesh, selection, edge_offsets, mesh.attributes(), new_mesh->attributes_for_write());
if (attribute_outputs.duplicate_index) {
- create_duplicate_index_attribute(bke::mesh_attributes_for_write(*new_mesh),
+ create_duplicate_index_attribute(new_mesh->attributes_for_write(),
ATTR_DOMAIN_EDGE,
selection,
attribute_outputs,
@@ -805,14 +791,13 @@ static void duplicate_points_curve(GeometrySet &geometry_set,
const Field<bool> &selection_field,
const IndexAttributes &attribute_outputs)
{
- const CurveComponent &src_component = *geometry_set.get_component_for_read<CurveComponent>();
- const Curves &src_curves_id = *src_component.get_for_read();
+ const Curves &src_curves_id = *geometry_set.get_curves_for_read();
const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(src_curves_id.geometry);
if (src_curves.points_num() == 0) {
return;
}
- GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_POINT};
+ bke::CurvesFieldContext field_context{src_curves, ATTR_DOMAIN_POINT};
FieldEvaluator evaluator{field_context, src_curves.points_num()};
evaluator.add(count_field);
evaluator.set_selection(selection_field);
@@ -845,7 +830,7 @@ static void duplicate_points_curve(GeometrySet &geometry_set,
for (const Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
const AttributeIDRef attribute_id = entry.key;
- GAttributeReader src_attribute = src_component.attributes()->lookup(attribute_id);
+ GAttributeReader src_attribute = src_curves.attributes().lookup(attribute_id);
if (!src_attribute) {
continue;
}
@@ -909,11 +894,10 @@ static void duplicate_points_mesh(GeometrySet &geometry_set,
const Field<bool> &selection_field,
const IndexAttributes &attribute_outputs)
{
- const MeshComponent &src_component = *geometry_set.get_component_for_read<MeshComponent>();
const Mesh &mesh = *geometry_set.get_mesh_for_read();
- Span<MVert> src_verts(mesh.mvert, mesh.totvert);
+ const Span<MVert> src_verts = mesh.verts();
- GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_POINT};
+ bke::MeshFieldContext field_context{mesh, ATTR_DOMAIN_POINT};
FieldEvaluator evaluator{field_context, src_verts.size()};
evaluator.add(count_field);
evaluator.set_selection(selection_field);
@@ -924,7 +908,7 @@ static void duplicate_points_mesh(GeometrySet &geometry_set,
Array<int> offsets = accumulate_counts_to_offsets(selection, counts);
Mesh *new_mesh = BKE_mesh_new_nomain(offsets.last(), 0, 0, 0, 0);
- MutableSpan<MVert> dst_verts(new_mesh->mvert, new_mesh->totvert);
+ MutableSpan<MVert> dst_verts = new_mesh->verts_for_write();
threaded_slice_fill(offsets.as_span(), selection, src_verts, dst_verts);
@@ -933,14 +917,13 @@ static void duplicate_points_mesh(GeometrySet &geometry_set,
ATTR_DOMAIN_POINT,
offsets,
selection,
- bke::mesh_attributes(mesh),
- bke::mesh_attributes_for_write(*new_mesh));
+ mesh.attributes(),
+ new_mesh->attributes_for_write());
- copy_stable_id_point(
- offsets, bke::mesh_attributes(mesh), bke::mesh_attributes_for_write(*new_mesh));
+ copy_stable_id_point(offsets, mesh.attributes(), new_mesh->attributes_for_write());
if (attribute_outputs.duplicate_index) {
- create_duplicate_index_attribute(bke::mesh_attributes_for_write(*new_mesh),
+ create_duplicate_index_attribute(new_mesh->attributes_for_write(),
ATTR_DOMAIN_POINT,
selection,
attribute_outputs,
@@ -961,12 +944,10 @@ static void duplicate_points_pointcloud(GeometrySet &geometry_set,
const Field<bool> &selection_field,
const IndexAttributes &attribute_outputs)
{
- const PointCloudComponent &src_points =
- *geometry_set.get_component_for_read<PointCloudComponent>();
- const int point_num = src_points.attribute_domain_size(ATTR_DOMAIN_POINT);
+ const PointCloud &src_points = *geometry_set.get_pointcloud_for_read();
- GeometryComponentFieldContext field_context{src_points, ATTR_DOMAIN_POINT};
- FieldEvaluator evaluator{field_context, point_num};
+ bke::PointCloudFieldContext field_context{src_points};
+ FieldEvaluator evaluator{field_context, src_points.totpoint};
evaluator.add(count_field);
evaluator.set_selection(selection_field);
evaluator.evaluate();
@@ -982,14 +963,13 @@ static void duplicate_points_pointcloud(GeometrySet &geometry_set,
ATTR_DOMAIN_POINT,
offsets,
selection,
- *src_points.attributes(),
- bke::pointcloud_attributes_for_write(*pointcloud));
+ src_points.attributes(),
+ pointcloud->attributes_for_write());
- copy_stable_id_point(
- offsets, *src_points.attributes(), bke::pointcloud_attributes_for_write(*pointcloud));
+ copy_stable_id_point(offsets, src_points.attributes(), pointcloud->attributes_for_write());
if (attribute_outputs.duplicate_index) {
- create_duplicate_index_attribute(bke::pointcloud_attributes_for_write(*pointcloud),
+ create_duplicate_index_attribute(pointcloud->attributes_for_write(),
ATTR_DOMAIN_POINT,
selection,
attribute_outputs,
@@ -1052,10 +1032,9 @@ static void duplicate_instances(GeometrySet &geometry_set,
return;
}
- const InstancesComponent &src_instances =
- *geometry_set.get_component_for_read<InstancesComponent>();
+ const bke::Instances &src_instances = *geometry_set.get_instances_for_read();
- GeometryComponentFieldContext field_context{src_instances, ATTR_DOMAIN_INSTANCE};
+ bke::InstancesFieldContext field_context{src_instances};
FieldEvaluator evaluator{field_context, src_instances.instances_num()};
evaluator.add(count_field);
evaluator.set_selection(selection_field);
@@ -1069,20 +1048,20 @@ static void duplicate_instances(GeometrySet &geometry_set,
return;
}
- GeometrySet dst_geometry;
- InstancesComponent &dst_instances = dst_geometry.get_component_for_write<InstancesComponent>();
- dst_instances.resize(offsets.last());
+ std::unique_ptr<bke::Instances> dst_instances = std::make_unique<bke::Instances>();
+
+ dst_instances->resize(offsets.last());
for (const int i_selection : selection.index_range()) {
const IndexRange range = range_for_offsets_index(offsets, i_selection);
if (range.size() == 0) {
continue;
}
- const int old_handle = src_instances.instance_reference_handles()[i_selection];
- const InstanceReference reference = src_instances.references()[old_handle];
- const int new_handle = dst_instances.add_reference(reference);
- const float4x4 transform = src_instances.instance_transforms()[i_selection];
- dst_instances.instance_transforms().slice(range).fill(transform);
- dst_instances.instance_reference_handles().slice(range).fill(new_handle);
+ const int old_handle = src_instances.reference_handles()[i_selection];
+ const bke::InstanceReference reference = src_instances.references()[old_handle];
+ const int new_handle = dst_instances->add_reference(reference);
+ const float4x4 transform = src_instances.transforms()[i_selection];
+ dst_instances->transforms().slice(range).fill(transform);
+ dst_instances->reference_handles().slice(range).fill(new_handle);
}
copy_attributes_without_id(geometry_set,
@@ -1090,18 +1069,18 @@ static void duplicate_instances(GeometrySet &geometry_set,
ATTR_DOMAIN_INSTANCE,
offsets,
selection,
- *src_instances.attributes(),
- *dst_instances.attributes_for_write());
+ src_instances.attributes(),
+ dst_instances->attributes_for_write());
if (attribute_outputs.duplicate_index) {
- create_duplicate_index_attribute(*dst_instances.attributes_for_write(),
+ create_duplicate_index_attribute(dst_instances->attributes_for_write(),
ATTR_DOMAIN_INSTANCE,
selection,
attribute_outputs,
offsets);
}
- geometry_set = std::move(dst_geometry);
+ geometry_set = GeometrySet::create_with_instances(dst_instances.release());
}
/** \} */
diff --git a/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_curves.cc
index 89abfa0aa88..ba09acf0bf0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_curves.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_curves.cc
@@ -3,7 +3,6 @@
#include "BKE_curves.hh"
#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
#include "GEO_mesh_to_curve.hh"
@@ -23,7 +22,6 @@ static Curves *edge_paths_to_curves_convert(const Mesh &mesh,
const IndexMask start_verts_mask,
const Span<int> next_indices)
{
- const Span<MVert> mvert{mesh.mvert, mesh.totvert};
Vector<int> vert_indices;
Vector<int> curve_offsets;
Array<bool> visited(mesh.totvert, false);
@@ -70,14 +68,14 @@ static void node_geo_exec(GeoNodeExecParams params)
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (!geometry_set.has_mesh()) {
+ const Mesh *mesh = geometry_set.get_mesh_for_read();
+ if (mesh == nullptr) {
geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
return;
}
- const MeshComponent &component = *geometry_set.get_component_for_read<MeshComponent>();
- GeometryComponentFieldContext context{component, ATTR_DOMAIN_POINT};
- fn::FieldEvaluator evaluator{context, component.attribute_domain_size(ATTR_DOMAIN_POINT)};
+ bke::MeshFieldContext context{*mesh, ATTR_DOMAIN_POINT};
+ fn::FieldEvaluator evaluator{context, mesh->totvert};
evaluator.add(params.get_input<Field<int>>("Next Vertex Index"));
evaluator.add(params.get_input<Field<bool>>("Start Vertices"));
evaluator.evaluate();
@@ -89,8 +87,7 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
- const Mesh &mesh = *component.get_for_read();
- geometry_set.replace_curves(edge_paths_to_curves_convert(mesh, start_verts, next_vert));
+ geometry_set.replace_curves(edge_paths_to_curves_convert(*mesh, start_verts, next_vert));
geometry_set.keep_only({GEO_COMPONENT_TYPE_CURVE, GEO_COMPONENT_TYPE_INSTANCES});
});
diff --git a/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_selection.cc
index 53cbd691fdb..f0bd01a012b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_selection.cc
@@ -7,9 +7,6 @@
#include "BLI_set.hh"
#include "BLI_task.hh"
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-
#include "node_geometry_util.hh"
#include <set>
@@ -28,6 +25,8 @@ static void edge_paths_to_selection(const Mesh &src_mesh,
const Span<int> next_indices,
MutableSpan<bool> r_selection)
{
+ const Span<MEdge> edges = src_mesh.edges();
+
Array<bool> selection(src_mesh.totvert, false);
for (const int start_vert : start_selection) {
@@ -45,8 +44,8 @@ static void edge_paths_to_selection(const Mesh &src_mesh,
}
}
- for (const int i : IndexRange(src_mesh.totedge)) {
- const MEdge &edge = src_mesh.medge[i];
+ for (const int i : edges.index_range()) {
+ const MEdge &edge = edges[i];
if ((selection[edge.v1] && selection[edge.v2]) &&
(edge.v1 == next_indices[edge.v2] || edge.v2 == next_indices[edge.v1])) {
r_selection[i] = true;
@@ -54,36 +53,26 @@ static void edge_paths_to_selection(const Mesh &src_mesh,
}
}
-class PathToEdgeSelectionFieldInput final : public GeometryFieldInput {
+class PathToEdgeSelectionFieldInput final : public bke::MeshFieldInput {
private:
Field<bool> start_vertices_;
Field<int> next_vertex_;
public:
- PathToEdgeSelectionFieldInput(Field<bool> start_vertices, Field<int> next_vertex)
- : GeometryFieldInput(CPPType::get<bool>(), "Edge Selection"),
- start_vertices_(start_vertices),
+ PathToEdgeSelectionFieldInput(Field<bool> start_verts, Field<int> next_vertex)
+ : bke::MeshFieldInput(CPPType::get<bool>(), "Edge Selection"),
+ start_vertices_(start_verts),
next_vertex_(next_vertex)
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
+ GVArray get_varray_for_context(const Mesh &mesh,
const eAttrDomain domain,
- [[maybe_unused]] IndexMask mask) const final
+ const IndexMask /*mask*/) const final
{
- if (component.type() != GEO_COMPONENT_TYPE_MESH) {
- return {};
- }
-
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- const Mesh *mesh = mesh_component.get_for_read();
- if (mesh == nullptr) {
- return {};
- }
-
- GeometryComponentFieldContext context{mesh_component, ATTR_DOMAIN_POINT};
- fn::FieldEvaluator evaluator{context, mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT)};
+ bke::MeshFieldContext context{mesh, ATTR_DOMAIN_POINT};
+ fn::FieldEvaluator evaluator{context, mesh.totvert};
evaluator.add(next_vertex_);
evaluator.add(start_vertices_);
evaluator.evaluate();
@@ -94,12 +83,12 @@ class PathToEdgeSelectionFieldInput final : public GeometryFieldInput {
return {};
}
- Array<bool> selection(mesh->totedge, false);
+ Array<bool> selection(mesh.totedge, false);
MutableSpan<bool> selection_span = selection.as_mutable_span();
- edge_paths_to_selection(*mesh, start_verts, next_vert, selection_span);
+ edge_paths_to_selection(mesh, start_verts, next_vert, selection_span);
- return mesh_component.attributes()->adapt_domain<bool>(
+ return mesh.attributes().adapt_domain<bool>(
VArray<bool>::ForContainer(std::move(selection)), ATTR_DOMAIN_EDGE, domain);
}
@@ -117,14 +106,19 @@ class PathToEdgeSelectionFieldInput final : public GeometryFieldInput {
}
return false;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_EDGE;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
{
- Field<bool> start_vertices = params.extract_input<Field<bool>>("Start Vertices");
+ Field<bool> start_verts = params.extract_input<Field<bool>>("Start Vertices");
Field<int> next_vertex = params.extract_input<Field<int>>("Next Vertex Index");
Field<bool> selection_field{
- std::make_shared<PathToEdgeSelectionFieldInput>(start_vertices, next_vertex)};
+ std::make_shared<PathToEdgeSelectionFieldInput>(start_verts, next_vertex)};
params.set_output("Selection", std::move(selection_field));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
index 84acab47661..0b4d5bd53f3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
@@ -1,5 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "DNA_mesh_types.h"
+
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
@@ -51,19 +53,18 @@ static void node_geo_exec(GeoNodeExecParams params)
const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (!geometry_set.has_mesh()) {
- return;
- }
+ if (const Mesh *mesh = geometry_set.get_mesh_for_write()) {
- const MeshComponent &mesh_component = *geometry_set.get_component_for_read<MeshComponent>();
- GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_EDGE};
- const int domain_size = mesh_component.attribute_domain_size(ATTR_DOMAIN_EDGE);
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+ bke::MeshFieldContext field_context{*mesh, ATTR_DOMAIN_EDGE};
+ fn::FieldEvaluator selection_evaluator{field_context, mesh->totedge};
+ selection_evaluator.add(selection_field);
+ selection_evaluator.evaluate();
+ const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
- geometry_set.replace_mesh(mesh_edge_split(*mesh_component.get_for_read(), selection));
+ Mesh *result = mesh_edge_split(*mesh, selection);
+
+ geometry_set.replace_mesh(result);
+ }
});
params.set_output("Mesh", std::move(geometry_set));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
index 024dbd1c852..d348d886ad6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
@@ -24,7 +24,10 @@ static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Mesh").supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value();
- b.add_input<decl::Vector>(N_("Offset")).subtype(PROP_TRANSLATION).implicit_field().hide_value();
+ b.add_input<decl::Vector>(N_("Offset"))
+ .subtype(PROP_TRANSLATION)
+ .implicit_field(implicit_field_inputs::normal)
+ .hide_value();
b.add_input<decl::Float>(N_("Offset Scale")).default_value(1.0f).supports_field();
b.add_input<decl::Bool>(N_("Individual")).default_value(true);
b.add_output<decl::Geometry>("Mesh");
@@ -32,14 +35,14 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Bool>(N_("Side")).field_source();
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryExtrudeMesh *data = MEM_cnew<NodeGeometryExtrudeMesh>(__func__);
data->mode = GEO_NODE_EXTRUDE_MESH_FACES;
@@ -49,9 +52,9 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeGeometryExtrudeMesh &storage = node_storage(*node);
- const GeometryNodeExtrudeMeshMode mode = static_cast<GeometryNodeExtrudeMeshMode>(storage.mode);
+ const GeometryNodeExtrudeMeshMode mode = GeometryNodeExtrudeMeshMode(storage.mode);
- bNodeSocket *individual_socket = (bNodeSocket *)node->inputs.last;
+ bNodeSocket *individual_socket = static_cast<bNodeSocket *>(node->inputs.last);
nodeSetSocketAvailability(ntree, individual_socket, mode == GEO_NODE_EXTRUDE_MESH_FACES);
}
@@ -61,15 +64,15 @@ struct AttributeOutputs {
StrongAnonymousAttributeID side_id;
};
-static void save_selection_as_attribute(MeshComponent &component,
+static void save_selection_as_attribute(Mesh &mesh,
const AnonymousAttributeID *id,
const eAttrDomain domain,
const IndexMask selection)
{
- BLI_assert(!component.attributes()->contains(id));
+ MutableAttributeAccessor attributes = mesh.attributes_for_write();
+ BLI_assert(!attributes.contains(id));
- SpanAttributeWriter<bool> attribute =
- component.attributes_for_write()->lookup_or_add_for_write_span<bool>(id, domain);
+ SpanAttributeWriter<bool> attribute = attributes.lookup_or_add_for_write_span<bool>(id, domain);
/* Rely on the new attribute being zeroed by default. */
BLI_assert(!attribute.span.as_span().contains(true));
@@ -83,31 +86,6 @@ static void save_selection_as_attribute(MeshComponent &component,
attribute.finish();
}
-static MutableSpan<MVert> mesh_verts(Mesh &mesh)
-{
- return {mesh.mvert, mesh.totvert};
-}
-static MutableSpan<MEdge> mesh_edges(Mesh &mesh)
-{
- return {mesh.medge, mesh.totedge};
-}
-static Span<MPoly> mesh_polys(const Mesh &mesh)
-{
- return {mesh.mpoly, mesh.totpoly};
-}
-static MutableSpan<MPoly> mesh_polys(Mesh &mesh)
-{
- return {mesh.mpoly, mesh.totpoly};
-}
-static Span<MLoop> mesh_loops(const Mesh &mesh)
-{
- return {mesh.mloop, mesh.totloop};
-}
-static MutableSpan<MLoop> mesh_loops(Mesh &mesh)
-{
- return {mesh.mloop, mesh.totloop};
-}
-
/**
* \note Some areas in this file rely on the new sections of attributes from #CustomData_realloc
* to be zeroed.
@@ -119,30 +97,25 @@ static void expand_mesh(Mesh &mesh,
const int loop_expand)
{
if (vert_expand != 0) {
- CustomData_duplicate_referenced_layers(&mesh.vdata, mesh.totvert);
+ const int old_verts_num = mesh.totvert;
mesh.totvert += vert_expand;
- CustomData_realloc(&mesh.vdata, mesh.totvert);
- }
- else {
- /* Even when the number of vertices is not changed, the mesh can still be deformed. */
- CustomData_duplicate_referenced_layer(&mesh.vdata, CD_MVERT, mesh.totvert);
+ CustomData_realloc(&mesh.vdata, old_verts_num, mesh.totvert);
}
if (edge_expand != 0) {
- CustomData_duplicate_referenced_layers(&mesh.edata, mesh.totedge);
+ const int old_edges_num = mesh.totedge;
mesh.totedge += edge_expand;
- CustomData_realloc(&mesh.edata, mesh.totedge);
+ CustomData_realloc(&mesh.edata, old_edges_num, mesh.totedge);
}
if (poly_expand != 0) {
- CustomData_duplicate_referenced_layers(&mesh.pdata, mesh.totpoly);
+ const int old_polys_num = mesh.totpoly;
mesh.totpoly += poly_expand;
- CustomData_realloc(&mesh.pdata, mesh.totpoly);
+ CustomData_realloc(&mesh.pdata, old_polys_num, mesh.totpoly);
}
if (loop_expand != 0) {
- CustomData_duplicate_referenced_layers(&mesh.ldata, mesh.totloop);
+ const int old_loops_num = mesh.totloop;
mesh.totloop += loop_expand;
- CustomData_realloc(&mesh.ldata, mesh.totloop);
+ CustomData_realloc(&mesh.ldata, old_loops_num, mesh.totloop);
}
- BKE_mesh_update_customdata_pointers(&mesh, false);
}
static CustomData &get_customdata(Mesh &mesh, const eAttrDomain domain)
@@ -162,9 +135,12 @@ static CustomData &get_customdata(Mesh &mesh, const eAttrDomain domain)
}
}
+/**
+ * \note The result may be an empty span.
+ */
static MutableSpan<int> get_orig_index_layer(Mesh &mesh, const eAttrDomain domain)
{
- const bke::AttributeAccessor attributes = bke::mesh_attributes(mesh);
+ const bke::AttributeAccessor attributes = mesh.attributes();
CustomData &custom_data = get_customdata(mesh, domain);
if (int *orig_indices = static_cast<int *>(CustomData_get_layer(&custom_data, CD_ORIGINDEX))) {
return {orig_indices, attributes.domain_size(domain)};
@@ -247,16 +223,15 @@ static Array<Vector<int>> create_vert_to_edge_map(const int vert_size,
return vert_to_edge_map;
}
-static void extrude_mesh_vertices(MeshComponent &component,
+static void extrude_mesh_vertices(Mesh &mesh,
const Field<bool> &selection_field,
const Field<float3> &offset_field,
const AttributeOutputs &attribute_outputs)
{
- Mesh &mesh = *component.get_for_write();
const int orig_vert_size = mesh.totvert;
const int orig_edge_size = mesh.totedge;
- GeometryComponentFieldContext context{component, ATTR_DOMAIN_POINT};
+ bke::MeshFieldContext context{mesh, ATTR_DOMAIN_POINT};
FieldEvaluator evaluator{context, mesh.totvert};
evaluator.add(offset_field);
evaluator.set_selection(selection_field);
@@ -265,26 +240,29 @@ static void extrude_mesh_vertices(MeshComponent &component,
const VArray<float3> offsets = evaluator.get_evaluated<float3>(0);
/* This allows parallelizing attribute mixing for new edges. */
- Array<Vector<int>> vert_to_edge_map = create_vert_to_edge_map(orig_vert_size, mesh_edges(mesh));
+ Array<Vector<int>> vert_to_edge_map = create_vert_to_edge_map(orig_vert_size, mesh.edges());
expand_mesh(mesh, selection.size(), selection.size(), 0, 0);
const IndexRange new_vert_range{orig_vert_size, selection.size()};
const IndexRange new_edge_range{orig_edge_size, selection.size()};
- MutableSpan<MVert> new_verts = mesh_verts(mesh).slice(new_vert_range);
- MutableSpan<MEdge> new_edges = mesh_edges(mesh).slice(new_edge_range);
+ MutableSpan<MVert> new_verts = mesh.verts_for_write().slice(new_vert_range);
+ MutableSpan<MEdge> new_edges = mesh.edges_for_write().slice(new_edge_range);
for (const int i_selection : selection.index_range()) {
new_edges[i_selection] = new_loose_edge(selection[i_selection], new_vert_range[i_selection]);
}
- MutableAttributeAccessor attributes = *component.attributes_for_write();
+ MutableAttributeAccessor attributes = mesh.attributes_for_write();
attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
if (!ELEM(meta_data.domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE)) {
return true;
}
+ if (meta_data.data_type == CD_PROP_STRING) {
+ return true;
+ }
GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
id, meta_data.domain, meta_data.data_type);
attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
@@ -324,13 +302,16 @@ static void extrude_mesh_vertices(MeshComponent &component,
MutableSpan<int> vert_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_POINT);
vert_orig_indices.slice(new_vert_range).fill(ORIGINDEX_NONE);
+ MutableSpan<int> new_edge_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_EDGE);
+ new_edge_orig_indices.slice(new_edge_range).fill(ORIGINDEX_NONE);
+
if (attribute_outputs.top_id) {
save_selection_as_attribute(
- component, attribute_outputs.top_id.get(), ATTR_DOMAIN_POINT, new_vert_range);
+ mesh, attribute_outputs.top_id.get(), ATTR_DOMAIN_POINT, new_vert_range);
}
if (attribute_outputs.side_id) {
save_selection_as_attribute(
- component, attribute_outputs.side_id.get(), ATTR_DOMAIN_EDGE, new_edge_range);
+ mesh, attribute_outputs.side_id.get(), ATTR_DOMAIN_EDGE, new_edge_range);
}
BKE_mesh_runtime_clear_cache(&mesh);
@@ -338,8 +319,8 @@ static void extrude_mesh_vertices(MeshComponent &component,
static Array<Vector<int, 2>> mesh_calculate_polys_of_edge(const Mesh &mesh)
{
- Span<MPoly> polys = mesh_polys(mesh);
- Span<MLoop> loops = mesh_loops(mesh);
+ Span<MPoly> polys = mesh.polys();
+ Span<MLoop> loops = mesh.loops();
Array<Vector<int, 2>> polys_of_edge(mesh.totedge);
for (const int i_poly : polys.index_range()) {
@@ -397,29 +378,29 @@ template<typename T>
static VectorSet<int> vert_indices_from_edges(const Mesh &mesh, const Span<T> edge_indices)
{
static_assert(is_same_any_v<T, int, int64_t>);
+ const Span<MEdge> edges = mesh.edges();
VectorSet<int> vert_indices;
vert_indices.reserve(edge_indices.size());
for (const T i_edge : edge_indices) {
- const MEdge &edge = mesh.medge[i_edge];
+ const MEdge &edge = edges[i_edge];
vert_indices.add(edge.v1);
vert_indices.add(edge.v2);
}
return vert_indices;
}
-static void extrude_mesh_edges(MeshComponent &component,
+static void extrude_mesh_edges(Mesh &mesh,
const Field<bool> &selection_field,
const Field<float3> &offset_field,
const AttributeOutputs &attribute_outputs)
{
- Mesh &mesh = *component.get_for_write();
const int orig_vert_size = mesh.totvert;
- Span<MEdge> orig_edges = mesh_edges(mesh);
- Span<MPoly> orig_polys = mesh_polys(mesh);
+ Span<MEdge> orig_edges = mesh.edges();
+ Span<MPoly> orig_polys = mesh.polys();
const int orig_loop_size = mesh.totloop;
- GeometryComponentFieldContext edge_context{component, ATTR_DOMAIN_EDGE};
+ bke::MeshFieldContext edge_context{mesh, ATTR_DOMAIN_EDGE};
FieldEvaluator edge_evaluator{edge_context, mesh.totedge};
edge_evaluator.set_selection(selection_field);
edge_evaluator.add(offset_field);
@@ -465,12 +446,12 @@ static void extrude_mesh_edges(MeshComponent &component,
new_poly_range.size(),
new_loop_range.size());
- MutableSpan<MVert> new_verts = mesh_verts(mesh).slice(new_vert_range);
- MutableSpan<MEdge> connect_edges = mesh_edges(mesh).slice(connect_edge_range);
- MutableSpan<MEdge> duplicate_edges = mesh_edges(mesh).slice(duplicate_edge_range);
- MutableSpan<MPoly> polys = mesh_polys(mesh);
+ MutableSpan<MEdge> edges = mesh.edges_for_write();
+ MutableSpan<MEdge> connect_edges = edges.slice(connect_edge_range);
+ MutableSpan<MEdge> duplicate_edges = edges.slice(duplicate_edge_range);
+ MutableSpan<MPoly> polys = mesh.polys_for_write();
MutableSpan<MPoly> new_polys = polys.slice(new_poly_range);
- MutableSpan<MLoop> loops = mesh_loops(mesh);
+ MutableSpan<MLoop> loops = mesh.loops_for_write();
MutableSpan<MLoop> new_loops = loops.slice(new_loop_range);
for (const int i : connect_edges.index_range()) {
@@ -478,7 +459,7 @@ static void extrude_mesh_edges(MeshComponent &component,
}
for (const int i : duplicate_edges.index_range()) {
- const MEdge &orig_edge = mesh.medge[edge_selection[i]];
+ const MEdge &orig_edge = edges[edge_selection[i]];
const int i_new_vert_1 = new_vert_indices.index_of(orig_edge.v1);
const int i_new_vert_2 = new_vert_indices.index_of(orig_edge.v2);
duplicate_edges[i] = new_edge(new_vert_range[i_new_vert_1], new_vert_range[i_new_vert_2]);
@@ -525,9 +506,12 @@ static void extrude_mesh_edges(MeshComponent &component,
const Array<Vector<int>> new_vert_to_duplicate_edge_map = create_vert_to_edge_map(
new_vert_range.size(), duplicate_edges, orig_vert_size);
- MutableAttributeAccessor attributes = *component.attributes_for_write();
+ MutableAttributeAccessor attributes = mesh.attributes_for_write();
attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ if (meta_data.data_type == CD_PROP_STRING) {
+ return true;
+ }
GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
id, meta_data.domain, meta_data.data_type);
if (!attribute) {
@@ -633,6 +617,7 @@ static void extrude_mesh_edges(MeshComponent &component,
return true;
});
+ MutableSpan<MVert> new_verts = mesh.verts_for_write().slice(new_vert_range);
if (edge_offsets.is_single()) {
const float3 offset = edge_offsets.get_internal_single();
threading::parallel_for(new_verts.index_range(), 1024, [&](const IndexRange range) {
@@ -656,13 +641,16 @@ static void extrude_mesh_edges(MeshComponent &component,
edge_orig_indices.slice(connect_edge_range).fill(ORIGINDEX_NONE);
edge_orig_indices.slice(duplicate_edge_range).fill(ORIGINDEX_NONE);
+ MutableSpan<int> poly_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_FACE);
+ poly_orig_indices.slice(new_poly_range).fill(ORIGINDEX_NONE);
+
if (attribute_outputs.top_id) {
save_selection_as_attribute(
- component, attribute_outputs.top_id.get(), ATTR_DOMAIN_EDGE, duplicate_edge_range);
+ mesh, attribute_outputs.top_id.get(), ATTR_DOMAIN_EDGE, duplicate_edge_range);
}
if (attribute_outputs.side_id) {
save_selection_as_attribute(
- component, attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE, new_poly_range);
+ mesh, attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE, new_poly_range);
}
BKE_mesh_runtime_clear_cache(&mesh);
@@ -672,18 +660,17 @@ static void extrude_mesh_edges(MeshComponent &component,
* Edges connected to one selected face are on the boundary of a region and will be duplicated into
* a "side face". Edges inside a region will be duplicated to leave any original faces unchanged.
*/
-static void extrude_mesh_face_regions(MeshComponent &component,
+static void extrude_mesh_face_regions(Mesh &mesh,
const Field<bool> &selection_field,
const Field<float3> &offset_field,
const AttributeOutputs &attribute_outputs)
{
- Mesh &mesh = *component.get_for_write();
const int orig_vert_size = mesh.totvert;
- Span<MEdge> orig_edges = mesh_edges(mesh);
- Span<MPoly> orig_polys = mesh_polys(mesh);
- Span<MLoop> orig_loops = mesh_loops(mesh);
+ Span<MEdge> orig_edges = mesh.edges();
+ Span<MPoly> orig_polys = mesh.polys();
+ Span<MLoop> orig_loops = mesh.loops();
- GeometryComponentFieldContext poly_context{component, ATTR_DOMAIN_FACE};
+ bke::MeshFieldContext poly_context{mesh, ATTR_DOMAIN_FACE};
FieldEvaluator poly_evaluator{poly_context, mesh.totpoly};
poly_evaluator.set_selection(selection_field);
poly_evaluator.add(offset_field);
@@ -784,7 +771,7 @@ static void extrude_mesh_face_regions(MeshComponent &component,
/* The vertices attached to duplicate inner edges also have to be duplicated. */
for (const int i_edge : new_inner_edge_indices) {
- const MEdge &edge = mesh.medge[i_edge];
+ const MEdge &edge = orig_edges[i_edge];
new_vert_indices.add(edge.v1);
new_vert_indices.add(edge.v2);
}
@@ -808,13 +795,13 @@ static void extrude_mesh_face_regions(MeshComponent &component,
side_poly_range.size(),
side_loop_range.size());
- MutableSpan<MEdge> edges = mesh_edges(mesh);
+ MutableSpan<MEdge> edges = mesh.edges_for_write();
MutableSpan<MEdge> connect_edges = edges.slice(connect_edge_range);
MutableSpan<MEdge> boundary_edges = edges.slice(boundary_edge_range);
MutableSpan<MEdge> new_inner_edges = edges.slice(new_inner_edge_range);
- MutableSpan<MPoly> polys = mesh_polys(mesh);
+ MutableSpan<MPoly> polys = mesh.polys_for_write();
MutableSpan<MPoly> new_polys = polys.slice(side_poly_range);
- MutableSpan<MLoop> loops = mesh_loops(mesh);
+ MutableSpan<MLoop> loops = mesh.loops_for_write();
MutableSpan<MLoop> new_loops = loops.slice(side_loop_range);
/* Initialize the edges that form the sides of the extrusion. */
@@ -905,9 +892,12 @@ static void extrude_mesh_face_regions(MeshComponent &component,
const Array<Vector<int>> new_vert_to_duplicate_edge_map = create_vert_to_edge_map(
new_vert_range.size(), boundary_edges, orig_vert_size);
- MutableAttributeAccessor attributes = *component.attributes_for_write();
+ MutableAttributeAccessor attributes = mesh.attributes_for_write();
attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ if (meta_data.data_type == CD_PROP_STRING) {
+ return true;
+ }
GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
id, meta_data.domain, meta_data.data_type);
if (!attribute) {
@@ -1003,13 +993,14 @@ static void extrude_mesh_face_regions(MeshComponent &component,
/* Translate vertices based on the offset. If the vertex is used by a selected edge, it will
* have been duplicated and only the new vertex should use the offset. Otherwise the vertex might
* still need an offset, but it was reused on the inside of a region of extruded faces. */
+ MutableSpan<MVert> verts = mesh.verts_for_write();
if (poly_offsets.is_single()) {
const float3 offset = poly_offsets.get_internal_single();
threading::parallel_for(
IndexRange(all_selected_verts.size()), 1024, [&](const IndexRange range) {
for (const int i_orig : all_selected_verts.as_span().slice(range)) {
const int i_new = new_vert_indices.index_of_try(i_orig);
- MVert &vert = mesh_verts(mesh)[(i_new == -1) ? i_orig : new_vert_range[i_new]];
+ MVert &vert = verts[(i_new == -1) ? i_orig : new_vert_range[i_new]];
add_v3_v3(vert.co, offset);
}
});
@@ -1020,7 +1011,7 @@ static void extrude_mesh_face_regions(MeshComponent &component,
for (const int i_orig : all_selected_verts.as_span().slice(range)) {
const int i_new = new_vert_indices.index_of_try(i_orig);
const float3 offset = vert_offsets[i_orig];
- MVert &vert = mesh_verts(mesh)[(i_new == -1) ? i_orig : new_vert_range[i_new]];
+ MVert &vert = verts[(i_new == -1) ? i_orig : new_vert_range[i_new]];
add_v3_v3(vert.co, offset);
}
});
@@ -1039,11 +1030,11 @@ static void extrude_mesh_face_regions(MeshComponent &component,
if (attribute_outputs.top_id) {
save_selection_as_attribute(
- component, attribute_outputs.top_id.get(), ATTR_DOMAIN_FACE, poly_selection);
+ mesh, attribute_outputs.top_id.get(), ATTR_DOMAIN_FACE, poly_selection);
}
if (attribute_outputs.side_id) {
save_selection_as_attribute(
- component, attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE, side_poly_range);
+ mesh, attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE, side_poly_range);
}
BKE_mesh_runtime_clear_cache(&mesh);
@@ -1057,21 +1048,20 @@ static IndexRange selected_corner_range(Span<int> offsets, const int index)
return IndexRange(offset, next_offset - offset);
}
-static void extrude_individual_mesh_faces(MeshComponent &component,
+static void extrude_individual_mesh_faces(Mesh &mesh,
const Field<bool> &selection_field,
const Field<float3> &offset_field,
const AttributeOutputs &attribute_outputs)
{
- Mesh &mesh = *component.get_for_write();
const int orig_vert_size = mesh.totvert;
const int orig_edge_size = mesh.totedge;
- Span<MPoly> orig_polys = mesh_polys(mesh);
- Span<MLoop> orig_loops = mesh_loops(mesh);
+ Span<MPoly> orig_polys = mesh.polys();
+ Span<MLoop> orig_loops = mesh.loops();
/* Use a mesh for the result of the evaluation because the mesh is reallocated before
* the vertices are moved, and the evaluated result might reference an attribute. */
Array<float3> poly_offset(orig_polys.size());
- GeometryComponentFieldContext poly_context{component, ATTR_DOMAIN_FACE};
+ bke::MeshFieldContext poly_context{mesh, ATTR_DOMAIN_FACE};
FieldEvaluator poly_evaluator{poly_context, mesh.totpoly};
poly_evaluator.set_selection(selection_field);
poly_evaluator.add_with_destination(offset_field, poly_offset.as_mutable_span());
@@ -1105,13 +1095,13 @@ static void extrude_individual_mesh_faces(MeshComponent &component,
side_poly_range.size(),
side_loop_range.size());
- MutableSpan<MVert> new_verts = mesh_verts(mesh).slice(new_vert_range);
- MutableSpan<MEdge> edges{mesh.medge, mesh.totedge};
+ MutableSpan<MVert> new_verts = mesh.verts_for_write().slice(new_vert_range);
+ MutableSpan<MEdge> edges = mesh.edges_for_write();
MutableSpan<MEdge> connect_edges = edges.slice(connect_edge_range);
MutableSpan<MEdge> duplicate_edges = edges.slice(duplicate_edge_range);
- MutableSpan<MPoly> polys{mesh.mpoly, mesh.totpoly};
+ MutableSpan<MPoly> polys = mesh.polys_for_write();
MutableSpan<MPoly> new_polys = polys.slice(side_poly_range);
- MutableSpan<MLoop> loops{mesh.mloop, mesh.totloop};
+ MutableSpan<MLoop> loops = mesh.loops_for_write();
/* For every selected polygon, build the faces that form the sides of the extrusion. Filling some
* of this data like the new edges or polygons could be easily split into separate loops, which
@@ -1159,9 +1149,12 @@ static void extrude_individual_mesh_faces(MeshComponent &component,
}
});
- MutableAttributeAccessor attributes = *component.attributes_for_write();
+ MutableAttributeAccessor attributes = mesh.attributes_for_write();
attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ if (meta_data.data_type == CD_PROP_STRING) {
+ return true;
+ }
GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
id, meta_data.domain, meta_data.data_type);
if (!attribute) {
@@ -1318,11 +1311,11 @@ static void extrude_individual_mesh_faces(MeshComponent &component,
if (attribute_outputs.top_id) {
save_selection_as_attribute(
- component, attribute_outputs.top_id.get(), ATTR_DOMAIN_FACE, poly_selection);
+ mesh, attribute_outputs.top_id.get(), ATTR_DOMAIN_FACE, poly_selection);
}
if (attribute_outputs.side_id) {
save_selection_as_attribute(
- component, attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE, side_poly_range);
+ mesh, attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE, side_poly_range);
}
BKE_mesh_runtime_clear_cache(&mesh);
@@ -1335,7 +1328,7 @@ static void node_geo_exec(GeoNodeExecParams params)
Field<float3> offset_field = params.extract_input<Field<float3>>("Offset");
Field<float> scale_field = params.extract_input<Field<float>>("Offset Scale");
const NodeGeometryExtrudeMesh &storage = node_storage(params.node());
- GeometryNodeExtrudeMeshMode mode = static_cast<GeometryNodeExtrudeMeshMode>(storage.mode);
+ GeometryNodeExtrudeMeshMode mode = GeometryNodeExtrudeMeshMode(storage.mode);
/* Create a combined field from the offset and the scale so the field evaluator
* can take care of the multiplication and to simplify each extrude function. */
@@ -1359,27 +1352,26 @@ static void node_geo_exec(GeoNodeExecParams params)
params.extract_input<bool>("Individual");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (geometry_set.has_mesh()) {
- MeshComponent &component = geometry_set.get_component_for_write<MeshComponent>();
+ if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
switch (mode) {
case GEO_NODE_EXTRUDE_MESH_VERTICES:
- extrude_mesh_vertices(component, selection, final_offset, attribute_outputs);
+ extrude_mesh_vertices(*mesh, selection, final_offset, attribute_outputs);
break;
case GEO_NODE_EXTRUDE_MESH_EDGES:
- extrude_mesh_edges(component, selection, final_offset, attribute_outputs);
+ extrude_mesh_edges(*mesh, selection, final_offset, attribute_outputs);
break;
case GEO_NODE_EXTRUDE_MESH_FACES: {
if (extrude_individual) {
- extrude_individual_mesh_faces(component, selection, final_offset, attribute_outputs);
+ extrude_individual_mesh_faces(*mesh, selection, final_offset, attribute_outputs);
}
else {
- extrude_mesh_face_regions(component, selection, final_offset, attribute_outputs);
+ extrude_mesh_face_regions(*mesh, selection, final_offset, attribute_outputs);
}
break;
}
}
- BLI_assert(BKE_mesh_is_valid(component.get_for_write()));
+ BLI_assert(BKE_mesh_is_valid(mesh));
}
});
diff --git a/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc b/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc
index bde4af12d84..fc1e2cb2503 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc
@@ -11,6 +11,63 @@
#include "NOD_socket_search_link.hh"
+namespace blender::nodes {
+
+FieldAtIndexInput::FieldAtIndexInput(Field<int> index_field,
+ GField value_field,
+ eAttrDomain value_field_domain)
+ : bke::GeometryFieldInput(value_field.cpp_type(), "Field at Index"),
+ index_field_(std::move(index_field)),
+ value_field_(std::move(value_field)),
+ value_field_domain_(value_field_domain)
+{
+}
+
+GVArray FieldAtIndexInput::get_varray_for_context(const bke::GeometryFieldContext &context,
+ const IndexMask mask) const
+{
+ const std::optional<AttributeAccessor> attributes = context.attributes();
+ if (!attributes) {
+ return {};
+ }
+
+ const bke::GeometryFieldContext value_field_context{
+ context.geometry(), context.type(), value_field_domain_};
+ FieldEvaluator value_evaluator{value_field_context,
+ attributes->domain_size(value_field_domain_)};
+ value_evaluator.add(value_field_);
+ value_evaluator.evaluate();
+ const GVArray &values = value_evaluator.get_evaluated(0);
+
+ FieldEvaluator index_evaluator{context, &mask};
+ index_evaluator.add(index_field_);
+ index_evaluator.evaluate();
+ const VArray<int> indices = index_evaluator.get_evaluated<int>(0);
+
+ GVArray output_array;
+ attribute_math::convert_to_static_type(*type_, [&](auto dummy) {
+ using T = decltype(dummy);
+ Array<T> dst_array(mask.min_array_size());
+ VArray<T> src_values = values.typed<T>();
+ threading::parallel_for(mask.index_range(), 1024, [&](const IndexRange range) {
+ for (const int i : mask.slice(range)) {
+ const int index = indices[i];
+ if (src_values.index_range().contains(index)) {
+ dst_array[i] = src_values[index];
+ }
+ else {
+ dst_array[i] = {};
+ }
+ }
+ });
+ output_array = VArray<T>::ForContainer(std::move(dst_array));
+ });
+
+ return output_array;
+}
+
+} // namespace blender::nodes
+
namespace blender::nodes::node_geo_field_at_index_cc {
static void node_declare(NodeDeclarationBuilder &b)
@@ -30,13 +87,13 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Bool>(N_("Value"), "Value_Bool").field_source();
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
node->custom1 = ATTR_DOMAIN_POINT;
node->custom2 = CD_PROP_FLOAT;
@@ -44,7 +101,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
{
- const eCustomDataType data_type = static_cast<eCustomDataType>(node->custom2);
+ const eCustomDataType data_type = eCustomDataType(node->custom2);
bNodeSocket *sock_index = static_cast<bNodeSocket *>(node->inputs.first);
bNodeSocket *sock_in_float = sock_index->next;
@@ -89,61 +146,6 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
}
}
-class FieldAtIndex final : public GeometryFieldInput {
- private:
- Field<int> index_field_;
- GField value_field_;
- eAttrDomain value_field_domain_;
-
- public:
- FieldAtIndex(Field<int> index_field, GField value_field, eAttrDomain value_field_domain)
- : GeometryFieldInput(value_field.cpp_type(), "Field at Index"),
- index_field_(std::move(index_field)),
- value_field_(std::move(value_field)),
- value_field_domain_(value_field_domain)
- {
- }
-
- GVArray get_varray_for_context(const GeometryComponent &component,
- const eAttrDomain domain,
- IndexMask mask) const final
- {
- const GeometryComponentFieldContext value_field_context{component, value_field_domain_};
- FieldEvaluator value_evaluator{value_field_context,
- component.attribute_domain_size(value_field_domain_)};
- value_evaluator.add(value_field_);
- value_evaluator.evaluate();
- const GVArray &values = value_evaluator.get_evaluated(0);
-
- const GeometryComponentFieldContext index_field_context{component, domain};
- FieldEvaluator index_evaluator{index_field_context, &mask};
- index_evaluator.add(index_field_);
- index_evaluator.evaluate();
- const VArray<int> indices = index_evaluator.get_evaluated<int>(0);
-
- GVArray output_array;
- attribute_math::convert_to_static_type(*type_, [&](auto dummy) {
- using T = decltype(dummy);
- Array<T> dst_array(mask.min_array_size());
- VArray<T> src_values = values.typed<T>();
- threading::parallel_for(mask.index_range(), 1024, [&](const IndexRange range) {
- for (const int i : mask.slice(range)) {
- const int index = indices[i];
- if (index >= 0 && index < src_values.size()) {
- dst_array[i] = src_values[index];
- }
- else {
- dst_array[i] = {};
- }
- }
- });
- output_array = VArray<T>::ForContainer(std::move(dst_array));
- });
-
- return output_array;
- }
-};
-
static StringRefNull identifier_suffix(eCustomDataType data_type)
{
switch (data_type) {
@@ -166,16 +168,16 @@ static StringRefNull identifier_suffix(eCustomDataType data_type)
static void node_geo_exec(GeoNodeExecParams params)
{
const bNode &node = params.node();
- const eAttrDomain domain = static_cast<eAttrDomain>(node.custom1);
- const eCustomDataType data_type = static_cast<eCustomDataType>(node.custom2);
+ const eAttrDomain domain = eAttrDomain(node.custom1);
+ const eCustomDataType data_type = eCustomDataType(node.custom2);
Field<int> index_field = params.extract_input<Field<int>>("Index");
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
static const std::string identifier = "Value_" + identifier_suffix(data_type);
Field<T> value_field = params.extract_input<Field<T>>(identifier);
- Field<T> output_field{
- std::make_shared<FieldAtIndex>(std::move(index_field), std::move(value_field), domain)};
+ Field<T> output_field{std::make_shared<FieldAtIndexInput>(
+ std::move(index_field), std::move(value_field), domain)};
params.set_output(identifier, std::move(output_field));
});
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc
index 15b2822805a..95a0013a9e1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc
@@ -19,24 +19,19 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void mesh_flip_faces(MeshComponent &component, const Field<bool> &selection_field)
+static void mesh_flip_faces(Mesh &mesh, const Field<bool> &selection_field)
{
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE};
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
- if (domain_size == 0) {
+ if (mesh.totpoly == 0) {
return;
}
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ bke::MeshFieldContext field_context{mesh, ATTR_DOMAIN_FACE};
+ fn::FieldEvaluator evaluator{field_context, mesh.totpoly};
evaluator.add(selection_field);
evaluator.evaluate();
const IndexMask selection = evaluator.get_evaluated_as_mask(0);
- Mesh *mesh = component.get_for_write();
-
- mesh->mloop = (MLoop *)CustomData_duplicate_referenced_layer(
- &mesh->ldata, CD_MLOOP, mesh->totloop);
- Span<MPoly> polys{mesh->mpoly, mesh->totpoly};
- MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop};
+ const Span<MPoly> polys = mesh.polys();
+ MutableSpan<MLoop> loops = mesh.loops_for_write();
for (const int i : selection.index_range()) {
const MPoly &poly = polys[selection[i]];
@@ -49,9 +44,12 @@ static void mesh_flip_faces(MeshComponent &component, const Field<bool> &selecti
}
}
- MutableAttributeAccessor attributes = *component.attributes_for_write();
+ MutableAttributeAccessor attributes = mesh.attributes_for_write();
attributes.for_all(
[&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ if (meta_data.data_type == CD_PROP_STRING) {
+ return true;
+ }
if (meta_data.domain == ATTR_DOMAIN_CORNER) {
GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
attribute_id, ATTR_DOMAIN_CORNER, meta_data.data_type);
@@ -76,11 +74,9 @@ static void node_geo_exec(GeoNodeExecParams params)
const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (!geometry_set.has_mesh()) {
- return;
+ if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
+ mesh_flip_faces(*mesh, selection_field);
}
- MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
- mesh_flip_faces(mesh_component, selection_field);
});
params.set_output("Mesh", std::move(geometry_set));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc
index 1f84f8f288d..45808ff9996 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc
@@ -1,5 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "BKE_instances.hh"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_geometry_to_instance_cc {
@@ -12,16 +14,14 @@ static void node_declare(NodeDeclarationBuilder &b)
static void node_geo_exec(GeoNodeExecParams params)
{
- Vector<GeometrySet> geometries = params.extract_multi_input<GeometrySet>("Geometry");
- GeometrySet instances_geometry;
- InstancesComponent &instances_component =
- instances_geometry.get_component_for_write<InstancesComponent>();
+ Vector<GeometrySet> geometries = params.extract_input<Vector<GeometrySet>>("Geometry");
+ std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>();
for (GeometrySet &geometry : geometries) {
geometry.ensure_owns_direct_data();
- const int handle = instances_component.add_reference(std::move(geometry));
- instances_component.add_instance(handle, float4x4::identity());
+ const int handle = instances->add_reference(std::move(geometry));
+ instances->add_instance(handle, float4x4::identity());
}
- params.set_output("Instances", std::move(instances_geometry));
+ params.set_output("Instances", GeometrySet::create_with_instances(instances.release()));
}
} // namespace blender::nodes::node_geo_geometry_to_instance_cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc b/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc
index 33802d00d2b..f39337d3fc3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc
@@ -24,20 +24,20 @@ static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Image>(N_("Image")).hide_label();
b.add_input<decl::Vector>(N_("Vector"))
- .implicit_field()
- .description(("Texture coordinates from 0 to 1"));
+ .implicit_field(implicit_field_inputs::position)
+ .description("Texture coordinates from 0 to 1");
b.add_input<decl::Int>(N_("Frame")).min(0).max(MAXFRAMEF);
b.add_output<decl::Color>(N_("Color")).no_muted_links().dependent_field();
b.add_output<decl::Float>(N_("Alpha")).no_muted_links().dependent_field();
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "interpolation", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
uiItemR(layout, ptr, "extension", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryImageTexture *tex = MEM_cnew<NodeGeometryImageTexture>(__func__);
node->storage = tex;
@@ -122,9 +122,9 @@ class ImageFieldsFunction : public fn::MultiFunction {
static float frac(const float x, int *ix)
{
- const int i = (int)x - ((x < 0.0f) ? 1 : 0);
+ const int i = int(x) - ((x < 0.0f) ? 1 : 0);
*ix = i;
- return x - (float)i;
+ return x - float(i);
}
static float4 image_cubic_texture_lookup(const ImBuf *ibuf,
@@ -135,8 +135,8 @@ class ImageFieldsFunction : public fn::MultiFunction {
const int width = ibuf->x;
const int height = ibuf->y;
int pix, piy, nix, niy;
- const float tx = frac(px * (float)width - 0.5f, &pix);
- const float ty = frac(py * (float)height - 0.5f, &piy);
+ const float tx = frac(px * float(width) - 0.5f, &pix);
+ const float ty = frac(py * float(height) - 0.5f, &piy);
int ppix, ppiy, nnix, nniy;
switch (extension) {
@@ -189,22 +189,22 @@ class ImageFieldsFunction : public fn::MultiFunction {
v[2] = ((-0.5f * ty + 0.5f) * ty + 0.5f) * ty + (1.0f / 6.0f);
v[3] = (1.0f / 6.0f) * ty * ty * ty;
- return (v[0] * (u[0] * (image_pixel_lookup(ibuf, xc[0], yc[0])) +
- u[1] * (image_pixel_lookup(ibuf, xc[1], yc[0])) +
- u[2] * (image_pixel_lookup(ibuf, xc[2], yc[0])) +
- u[3] * (image_pixel_lookup(ibuf, xc[3], yc[0])))) +
- (v[1] * (u[0] * (image_pixel_lookup(ibuf, xc[0], yc[1])) +
- u[1] * (image_pixel_lookup(ibuf, xc[1], yc[1])) +
- u[2] * (image_pixel_lookup(ibuf, xc[2], yc[1])) +
- u[3] * (image_pixel_lookup(ibuf, xc[3], yc[1])))) +
- (v[2] * (u[0] * (image_pixel_lookup(ibuf, xc[0], yc[2])) +
- u[1] * (image_pixel_lookup(ibuf, xc[1], yc[2])) +
- u[2] * (image_pixel_lookup(ibuf, xc[2], yc[2])) +
- u[3] * (image_pixel_lookup(ibuf, xc[3], yc[2])))) +
- (v[3] * (u[0] * (image_pixel_lookup(ibuf, xc[0], yc[3])) +
- u[1] * (image_pixel_lookup(ibuf, xc[1], yc[3])) +
- u[2] * (image_pixel_lookup(ibuf, xc[2], yc[3])) +
- u[3] * (image_pixel_lookup(ibuf, xc[3], yc[3]))));
+ return (v[0] * (u[0] * image_pixel_lookup(ibuf, xc[0], yc[0]) +
+ u[1] * image_pixel_lookup(ibuf, xc[1], yc[0]) +
+ u[2] * image_pixel_lookup(ibuf, xc[2], yc[0]) +
+ u[3] * image_pixel_lookup(ibuf, xc[3], yc[0]))) +
+ (v[1] * (u[0] * image_pixel_lookup(ibuf, xc[0], yc[1]) +
+ u[1] * image_pixel_lookup(ibuf, xc[1], yc[1]) +
+ u[2] * image_pixel_lookup(ibuf, xc[2], yc[1]) +
+ u[3] * image_pixel_lookup(ibuf, xc[3], yc[1]))) +
+ (v[2] * (u[0] * image_pixel_lookup(ibuf, xc[0], yc[2]) +
+ u[1] * image_pixel_lookup(ibuf, xc[1], yc[2]) +
+ u[2] * image_pixel_lookup(ibuf, xc[2], yc[2]) +
+ u[3] * image_pixel_lookup(ibuf, xc[3], yc[2]))) +
+ (v[3] * (u[0] * image_pixel_lookup(ibuf, xc[0], yc[3]) +
+ u[1] * image_pixel_lookup(ibuf, xc[1], yc[3]) +
+ u[2] * image_pixel_lookup(ibuf, xc[2], yc[3]) +
+ u[3] * image_pixel_lookup(ibuf, xc[3], yc[3])));
}
static float4 image_linear_texture_lookup(const ImBuf *ibuf,
@@ -215,8 +215,8 @@ class ImageFieldsFunction : public fn::MultiFunction {
const int width = ibuf->x;
const int height = ibuf->y;
int pix, piy, nix, niy;
- const float nfx = frac(px * (float)width - 0.5f, &pix);
- const float nfy = frac(py * (float)height - 0.5f, &piy);
+ const float nfx = frac(px * float(width) - 0.5f, &pix);
+ const float nfy = frac(py * float(height) - 0.5f, &piy);
switch (extension) {
case SHD_IMAGE_EXTENSION_CLIP: {
@@ -257,8 +257,8 @@ class ImageFieldsFunction : public fn::MultiFunction {
const int width = ibuf->x;
const int height = ibuf->y;
int ix, iy;
- const float tx = frac(px * (float)width, &ix);
- const float ty = frac(py * (float)height, &iy);
+ const float tx = frac(px * float(width), &ix);
+ const float ty = frac(py * float(height), &iy);
switch (extension) {
case SHD_IMAGE_EXTENSION_REPEAT: {
@@ -285,14 +285,14 @@ class ImageFieldsFunction : public fn::MultiFunction {
}
}
- void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext /*context*/) const override
{
const VArray<float3> &vectors = params.readonly_single_input<float3>(0, "Vector");
MutableSpan<ColorGeometry4f> r_color = params.uninitialized_single_output<ColorGeometry4f>(
1, "Color");
MutableSpan<float> r_alpha = params.uninitialized_single_output_if_required<float>(2, "Alpha");
- MutableSpan<float4> color_data{(float4 *)r_color.data(), r_color.size()};
+ MutableSpan<float4> color_data{reinterpret_cast<float4 *>(r_color.data()), r_color.size()};
/* Sample image texture. */
switch (interpolation_) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc
index bc1b9e940a1..2979d0e4639 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc
@@ -1,5 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "BKE_curves.hh"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_input_curve_handles_cc {
@@ -15,31 +17,27 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Vector>(N_("Right")).field_source();
}
-class HandlePositionFieldInput final : public GeometryFieldInput {
+class HandlePositionFieldInput final : public bke::CurvesFieldInput {
Field<bool> relative_;
bool left_;
public:
HandlePositionFieldInput(Field<bool> relative, bool left)
- : GeometryFieldInput(CPPType::get<float3>(), "Handle"), relative_(relative), left_(left)
+ : bke::CurvesFieldInput(CPPType::get<float3>(), "Handle"), relative_(relative), left_(left)
{
}
- GVArray get_varray_for_context(const GeometryComponent &component,
+ GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
const eAttrDomain domain,
- IndexMask mask) const final
+ const IndexMask mask) const final
{
- if (component.type() != GEO_COMPONENT_TYPE_CURVE) {
- return {};
- }
-
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
+ bke::CurvesFieldContext field_context{curves, ATTR_DOMAIN_POINT};
fn::FieldEvaluator evaluator(field_context, &mask);
evaluator.add(relative_);
evaluator.evaluate();
const VArray<bool> relative = evaluator.get_evaluated<bool>(0);
- const AttributeAccessor attributes = *component.attributes();
+ const AttributeAccessor attributes = curves.attributes();
VArray<float3> positions = attributes.lookup_or_default<float3>(
"position", ATTR_DOMAIN_POINT, {0, 0, 0});
@@ -69,7 +67,7 @@ class HandlePositionFieldInput final : public GeometryFieldInput {
output[i] = handles[i];
}
}
- return component.attributes()->adapt_domain<float3>(
+ return attributes.adapt_domain<float3>(
VArray<float3>::ForContainer(std::move(output)), ATTR_DOMAIN_POINT, domain);
}
@@ -86,6 +84,11 @@ class HandlePositionFieldInput final : public GeometryFieldInput {
}
return false;
}
+
+ std::optional<eAttrDomain> preferred_domain(const CurvesGeometry & /*curves*/) const
+ {
+ return ATTR_DOMAIN_POINT;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc b/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc
index 4c7a148a797..f78815ebe74 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc
@@ -2,6 +2,8 @@
#include "node_geometry_util.hh"
+#include "BKE_instances.hh"
+
namespace blender::nodes::node_geo_input_instance_rotation_cc {
static void node_declare(NodeDeclarationBuilder &b)
@@ -9,28 +11,17 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Vector>(N_("Rotation")).field_source();
}
-class VectorFieldInput final : public GeometryFieldInput {
+class InstanceRotationFieldInput final : public bke::InstancesFieldInput {
public:
- VectorFieldInput() : GeometryFieldInput(CPPType::get<float3>(), "Rotation")
+ InstanceRotationFieldInput() : bke::InstancesFieldInput(CPPType::get<float3>(), "Rotation")
{
}
- GVArray get_varray_for_context(const GeometryComponent &component,
- const eAttrDomain UNUSED(domain),
- IndexMask UNUSED(mask)) const final
+ GVArray get_varray_for_context(const bke::Instances &instances, IndexMask /*mask*/) const final
{
- if (component.type() != GEO_COMPONENT_TYPE_INSTANCES) {
- return {};
- }
-
- const InstancesComponent &instance_component = static_cast<const InstancesComponent &>(
- component);
-
- auto rotation_fn = [&](const int i) -> float3 {
- return instance_component.instance_transforms()[i].to_euler();
- };
+ auto rotation_fn = [&](const int i) -> float3 { return instances.transforms()[i].to_euler(); };
- return VArray<float3>::ForFunc(instance_component.instances_num(), rotation_fn);
+ return VArray<float3>::ForFunc(instances.instances_num(), rotation_fn);
}
uint64_t hash() const override
@@ -40,13 +31,13 @@ class VectorFieldInput final : public GeometryFieldInput {
bool is_equal_to(const fn::FieldNode &other) const override
{
- return dynamic_cast<const VectorFieldInput *>(&other) != nullptr;
+ return dynamic_cast<const InstanceRotationFieldInput *>(&other) != nullptr;
}
};
static void node_geo_exec(GeoNodeExecParams params)
{
- Field<float3> rotation{std::make_shared<VectorFieldInput>()};
+ Field<float3> rotation{std::make_shared<InstanceRotationFieldInput>()};
params.set_output("Rotation", std::move(rotation));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc b/source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc
index b3a362fbf3e..12ac48f8f11 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc
@@ -2,6 +2,8 @@
#include "node_geometry_util.hh"
+#include "BKE_instances.hh"
+
namespace blender::nodes::node_geo_input_instance_scale_cc {
static void node_declare(NodeDeclarationBuilder &b)
@@ -9,28 +11,17 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Vector>(N_("Scale")).field_source();
}
-class VectorFieldInput final : public GeometryFieldInput {
+class InstanceScaleFieldInput final : public bke::InstancesFieldInput {
public:
- VectorFieldInput() : GeometryFieldInput(CPPType::get<float3>(), "Scale")
+ InstanceScaleFieldInput() : bke::InstancesFieldInput(CPPType::get<float3>(), "Scale")
{
}
- GVArray get_varray_for_context(const GeometryComponent &component,
- const eAttrDomain UNUSED(domain),
- IndexMask UNUSED(mask)) const final
+ GVArray get_varray_for_context(const bke::Instances &instances, IndexMask /*mask*/) const final
{
- if (component.type() != GEO_COMPONENT_TYPE_INSTANCES) {
- return {};
- }
-
- const InstancesComponent &instance_component = static_cast<const InstancesComponent &>(
- component);
-
- auto scale_fn = [&](const int i) -> float3 {
- return instance_component.instance_transforms()[i].scale();
- };
+ auto scale_fn = [&](const int i) -> float3 { return instances.transforms()[i].scale(); };
- return VArray<float3>::ForFunc(instance_component.instances_num(), scale_fn);
+ return VArray<float3>::ForFunc(instances.instances_num(), scale_fn);
}
uint64_t hash() const override
@@ -40,13 +31,13 @@ class VectorFieldInput final : public GeometryFieldInput {
bool is_equal_to(const fn::FieldNode &other) const override
{
- return dynamic_cast<const VectorFieldInput *>(&other) != nullptr;
+ return dynamic_cast<const InstanceScaleFieldInput *>(&other) != nullptr;
}
};
static void node_geo_exec(GeoNodeExecParams params)
{
- Field<float3> scale{std::make_shared<VectorFieldInput>()};
+ Field<float3> scale{std::make_shared<InstanceScaleFieldInput>()};
params.set_output("Scale", std::move(scale));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_material.cc b/source/blender/nodes/geometry/nodes/node_geo_input_material.cc
index 19882c4966d..943193a0d82 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_material.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_material.cc
@@ -12,14 +12,14 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Material>(N_("Material"));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "material", 0, "", ICON_NONE);
}
static void node_geo_exec(GeoNodeExecParams params)
{
- Material *material = (Material *)params.node().id;
+ Material *material = reinterpret_cast<Material *>(params.node().id);
params.set_output("Material", material);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc
index b009aaa5291..29730ab8dc4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc
@@ -53,46 +53,36 @@ static Array<EdgeMapEntry> create_edge_map(const Span<MPoly> polys,
return edge_map;
}
-class AngleFieldInput final : public GeometryFieldInput {
+class AngleFieldInput final : public bke::MeshFieldInput {
public:
- AngleFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Unsigned Angle Field")
+ AngleFieldInput() : bke::MeshFieldInput(CPPType::get<float>(), "Unsigned Angle Field")
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
+ GVArray get_varray_for_context(const Mesh &mesh,
const eAttrDomain domain,
- IndexMask UNUSED(mask)) const final
+ const IndexMask /*mask*/) const final
{
- if (component.type() != GEO_COMPONENT_TYPE_MESH) {
- return {};
- }
-
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- const Mesh *mesh = mesh_component.get_for_read();
- if (mesh == nullptr) {
- return {};
- }
-
- Span<MPoly> polys{mesh->mpoly, mesh->totpoly};
- Span<MLoop> loops{mesh->mloop, mesh->totloop};
- Array<EdgeMapEntry> edge_map = create_edge_map(polys, loops, mesh->totedge);
+ const Span<MVert> verts = mesh.verts();
+ const Span<MPoly> polys = mesh.polys();
+ const Span<MLoop> loops = mesh.loops();
+ Array<EdgeMapEntry> edge_map = create_edge_map(polys, loops, mesh.totedge);
- auto angle_fn = [edge_map, polys, loops, mesh](const int i) -> float {
+ auto angle_fn = [edge_map = std::move(edge_map), verts, polys, loops](const int i) -> float {
if (edge_map[i].face_count != 2) {
return 0.0f;
}
const MPoly &mpoly_1 = polys[edge_map[i].face_index_1];
const MPoly &mpoly_2 = polys[edge_map[i].face_index_2];
float3 normal_1, normal_2;
- BKE_mesh_calc_poly_normal(&mpoly_1, &loops[mpoly_1.loopstart], mesh->mvert, normal_1);
- BKE_mesh_calc_poly_normal(&mpoly_2, &loops[mpoly_2.loopstart], mesh->mvert, normal_2);
+ BKE_mesh_calc_poly_normal(&mpoly_1, &loops[mpoly_1.loopstart], verts.data(), normal_1);
+ BKE_mesh_calc_poly_normal(&mpoly_2, &loops[mpoly_2.loopstart], verts.data(), normal_2);
return angle_normalized_v3v3(normal_1, normal_2);
};
- VArray<float> angles = VArray<float>::ForFunc(mesh->totedge, angle_fn);
- return component.attributes()->adapt_domain<float>(
- std::move(angles), ATTR_DOMAIN_EDGE, domain);
+ VArray<float> angles = VArray<float>::ForFunc(mesh.totedge, angle_fn);
+ return mesh.attributes().adapt_domain<float>(std::move(angles), ATTR_DOMAIN_EDGE, domain);
}
uint64_t hash() const override
@@ -105,34 +95,32 @@ class AngleFieldInput final : public GeometryFieldInput {
{
return dynamic_cast<const AngleFieldInput *>(&other) != nullptr;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_EDGE;
+ }
};
-class SignedAngleFieldInput final : public GeometryFieldInput {
+class SignedAngleFieldInput final : public bke::MeshFieldInput {
public:
- SignedAngleFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Signed Angle Field")
+ SignedAngleFieldInput() : bke::MeshFieldInput(CPPType::get<float>(), "Signed Angle Field")
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
+ GVArray get_varray_for_context(const Mesh &mesh,
const eAttrDomain domain,
- IndexMask UNUSED(mask)) const final
+ const IndexMask /*mask*/) const final
{
- if (component.type() != GEO_COMPONENT_TYPE_MESH) {
- return {};
- }
-
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- const Mesh *mesh = mesh_component.get_for_read();
- if (mesh == nullptr) {
- return {};
- }
-
- Span<MPoly> polys{mesh->mpoly, mesh->totpoly};
- Span<MLoop> loops{mesh->mloop, mesh->totloop};
- Array<EdgeMapEntry> edge_map = create_edge_map(polys, loops, mesh->totedge);
-
- auto angle_fn = [edge_map, polys, loops, mesh](const int i) -> float {
+ const Span<MVert> verts = mesh.verts();
+ const Span<MEdge> edges = mesh.edges();
+ const Span<MPoly> polys = mesh.polys();
+ const Span<MLoop> loops = mesh.loops();
+ Array<EdgeMapEntry> edge_map = create_edge_map(polys, loops, mesh.totedge);
+
+ auto angle_fn =
+ [edge_map = std::move(edge_map), verts, edges, polys, loops](const int i) -> float {
if (edge_map[i].face_count != 2) {
return 0.0f;
}
@@ -141,18 +129,18 @@ class SignedAngleFieldInput final : public GeometryFieldInput {
/* Find the normals of the 2 polys. */
float3 poly_1_normal, poly_2_normal;
- BKE_mesh_calc_poly_normal(&mpoly_1, &loops[mpoly_1.loopstart], mesh->mvert, poly_1_normal);
- BKE_mesh_calc_poly_normal(&mpoly_2, &loops[mpoly_2.loopstart], mesh->mvert, poly_2_normal);
+ BKE_mesh_calc_poly_normal(&mpoly_1, &loops[mpoly_1.loopstart], verts.data(), poly_1_normal);
+ BKE_mesh_calc_poly_normal(&mpoly_2, &loops[mpoly_2.loopstart], verts.data(), poly_2_normal);
/* Find the centerpoint of the axis edge */
- const float3 edge_centerpoint = (float3(mesh->mvert[mesh->medge[i].v1].co) +
- float3(mesh->mvert[mesh->medge[i].v2].co)) *
+ const float3 edge_centerpoint = (float3(verts[edges[i].v1].co) +
+ float3(verts[edges[i].v2].co)) *
0.5f;
/* Get the centerpoint of poly 2 and subtract the edge centerpoint to get a tangent
* normal for poly 2. */
float3 poly_center_2;
- BKE_mesh_calc_poly_center(&mpoly_2, &loops[mpoly_2.loopstart], mesh->mvert, poly_center_2);
+ BKE_mesh_calc_poly_center(&mpoly_2, &loops[mpoly_2.loopstart], verts.data(), poly_center_2);
const float3 poly_2_tangent = math::normalize(poly_center_2 - edge_centerpoint);
const float concavity = math::dot(poly_1_normal, poly_2_tangent);
@@ -165,9 +153,8 @@ class SignedAngleFieldInput final : public GeometryFieldInput {
return -angle;
};
- VArray<float> angles = VArray<float>::ForFunc(mesh->totedge, angle_fn);
- return component.attributes()->adapt_domain<float>(
- std::move(angles), ATTR_DOMAIN_EDGE, domain);
+ VArray<float> angles = VArray<float>::ForFunc(mesh.totedge, angle_fn);
+ return mesh.attributes().adapt_domain<float>(std::move(angles), ATTR_DOMAIN_EDGE, domain);
}
uint64_t hash() const override
@@ -180,6 +167,11 @@ class SignedAngleFieldInput final : public GeometryFieldInput {
{
return dynamic_cast<const SignedAngleFieldInput *>(&other) != nullptr;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_EDGE;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc
index 50d6998bb27..97c950988e7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc
@@ -16,34 +16,26 @@ static void node_declare(NodeDeclarationBuilder &b)
.description(N_("The number of faces that use each edge as one of their sides"));
}
-class EdgeNeighborCountFieldInput final : public GeometryFieldInput {
+class EdgeNeighborCountFieldInput final : public bke::MeshFieldInput {
public:
EdgeNeighborCountFieldInput()
- : GeometryFieldInput(CPPType::get<int>(), "Edge Neighbor Count Field")
+ : bke::MeshFieldInput(CPPType::get<int>(), "Edge Neighbor Count Field")
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
+ GVArray get_varray_for_context(const Mesh &mesh,
const eAttrDomain domain,
- IndexMask UNUSED(mask)) const final
+ const IndexMask /*mask*/) const final
{
- if (component.type() == GEO_COMPONENT_TYPE_MESH) {
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- const Mesh *mesh = mesh_component.get_for_read();
- if (mesh == nullptr) {
- return {};
- }
-
- Array<int> face_count(mesh->totedge, 0);
- for (const int i : IndexRange(mesh->totloop)) {
- face_count[mesh->mloop[i].e]++;
- }
-
- return mesh_component.attributes()->adapt_domain<int>(
- VArray<int>::ForContainer(std::move(face_count)), ATTR_DOMAIN_EDGE, domain);
+ const Span<MLoop> loops = mesh.loops();
+ Array<int> face_count(mesh.totedge, 0);
+ for (const MLoop &loop : loops) {
+ face_count[loop.e]++;
}
- return {};
+
+ return mesh.attributes().adapt_domain<int>(
+ VArray<int>::ForContainer(std::move(face_count)), ATTR_DOMAIN_EDGE, domain);
}
uint64_t hash() const override
@@ -56,6 +48,11 @@ class EdgeNeighborCountFieldInput final : public GeometryFieldInput {
{
return dynamic_cast<const EdgeNeighborCountFieldInput *>(&other) != nullptr;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_EDGE;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc
index 83e511f45c2..513ddd76055 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc
@@ -25,114 +25,102 @@ static void node_declare(NodeDeclarationBuilder &b)
.description(N_("The position of the second vertex in the edge"));
}
-enum VertexNumber { VERTEX_ONE, VERTEX_TWO };
+enum class VertNumber { V1, V2 };
-static VArray<int> construct_edge_vertices_gvarray(const MeshComponent &component,
- const VertexNumber vertex,
- const eAttrDomain domain)
+static VArray<int> construct_edge_verts_gvarray(const Mesh &mesh,
+ const VertNumber vertex,
+ const eAttrDomain domain)
{
- const Mesh *mesh = component.get_for_read();
- if (mesh == nullptr) {
- return {};
- }
+ const Span<MEdge> edges = mesh.edges();
if (domain == ATTR_DOMAIN_EDGE) {
- if (vertex == VERTEX_ONE) {
- return VArray<int>::ForFunc(mesh->totedge,
- [mesh](const int i) -> int { return mesh->medge[i].v1; });
+ if (vertex == VertNumber::V1) {
+ return VArray<int>::ForFunc(edges.size(),
+ [edges](const int i) -> int { return edges[i].v1; });
}
- return VArray<int>::ForFunc(mesh->totedge,
- [mesh](const int i) -> int { return mesh->medge[i].v2; });
+ return VArray<int>::ForFunc(edges.size(), [edges](const int i) -> int { return edges[i].v2; });
}
return {};
}
-class EdgeVerticesFieldInput final : public GeometryFieldInput {
+class EdgeVertsInput final : public bke::MeshFieldInput {
private:
- VertexNumber vertex_;
+ VertNumber vertex_;
public:
- EdgeVerticesFieldInput(VertexNumber vertex)
- : GeometryFieldInput(CPPType::get<int>(), "Edge Vertices Field"), vertex_(vertex)
+ EdgeVertsInput(VertNumber vertex)
+ : bke::MeshFieldInput(CPPType::get<int>(), "Edge Vertices Field"), vertex_(vertex)
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
+ GVArray get_varray_for_context(const Mesh &mesh,
const eAttrDomain domain,
- IndexMask UNUSED(mask)) const final
+ const IndexMask /*mask*/) const final
{
- if (component.type() == GEO_COMPONENT_TYPE_MESH) {
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- return construct_edge_vertices_gvarray(mesh_component, vertex_, domain);
- }
- return {};
+ return construct_edge_verts_gvarray(mesh, vertex_, domain);
}
uint64_t hash() const override
{
- return vertex_ == VERTEX_ONE ? 23847562893465 : 92384598734567;
+ return vertex_ == VertNumber::V1 ? 23847562893465 : 92384598734567;
}
bool is_equal_to(const fn::FieldNode &other) const override
{
- if (const EdgeVerticesFieldInput *other_field = dynamic_cast<const EdgeVerticesFieldInput *>(
- &other)) {
+ if (const EdgeVertsInput *other_field = dynamic_cast<const EdgeVertsInput *>(&other)) {
return vertex_ == other_field->vertex_;
}
return false;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_EDGE;
+ }
};
-static VArray<float3> construct_edge_positions_gvarray(const MeshComponent &component,
- const VertexNumber vertex,
+static VArray<float3> construct_edge_positions_gvarray(const Mesh &mesh,
+ const VertNumber vertex,
const eAttrDomain domain)
{
- const Mesh *mesh = component.get_for_read();
- if (mesh == nullptr) {
- return {};
- }
+ const Span<MVert> verts = mesh.verts();
+ const Span<MEdge> edges = mesh.edges();
- if (vertex == VERTEX_ONE) {
- return component.attributes()->adapt_domain<float3>(
- VArray<float3>::ForFunc(
- mesh->totedge,
- [mesh](const int i) { return float3(mesh->mvert[mesh->medge[i].v1].co); }),
+ if (vertex == VertNumber::V1) {
+ return mesh.attributes().adapt_domain<float3>(
+ VArray<float3>::ForFunc(edges.size(),
+ [verts, edges](const int i) { return verts[edges[i].v1].co; }),
ATTR_DOMAIN_EDGE,
domain);
}
- return component.attributes()->adapt_domain<float3>(
- VArray<float3>::ForFunc(
- mesh->totedge,
- [mesh](const int i) { return float3(mesh->mvert[mesh->medge[i].v2].co); }),
+ return mesh.attributes().adapt_domain<float3>(
+ VArray<float3>::ForFunc(edges.size(),
+ [verts, edges](const int i) { return verts[edges[i].v2].co; }),
ATTR_DOMAIN_EDGE,
domain);
}
-class EdgePositionFieldInput final : public GeometryFieldInput {
+class EdgePositionFieldInput final : public bke::MeshFieldInput {
private:
- VertexNumber vertex_;
+ VertNumber vertex_;
public:
- EdgePositionFieldInput(VertexNumber vertex)
- : GeometryFieldInput(CPPType::get<float3>(), "Edge Position Field"), vertex_(vertex)
+ EdgePositionFieldInput(VertNumber vertex)
+ : bke::MeshFieldInput(CPPType::get<float3>(), "Edge Position Field"), vertex_(vertex)
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
+ GVArray get_varray_for_context(const Mesh &mesh,
const eAttrDomain domain,
- IndexMask UNUSED(mask)) const final
+ IndexMask /*mask*/) const final
{
- if (component.type() == GEO_COMPONENT_TYPE_MESH) {
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- return construct_edge_positions_gvarray(mesh_component, vertex_, domain);
- }
- return {};
+ return construct_edge_positions_gvarray(mesh, vertex_, domain);
}
uint64_t hash() const override
{
- return vertex_ == VERTEX_ONE ? 987456978362 : 374587679866;
+ return vertex_ == VertNumber::V1 ? 987456978362 : 374587679866;
}
bool is_equal_to(const fn::FieldNode &other) const override
@@ -143,14 +131,19 @@ class EdgePositionFieldInput final : public GeometryFieldInput {
}
return false;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_EDGE;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
{
- Field<int> vertex_field_1{std::make_shared<EdgeVerticesFieldInput>(VERTEX_ONE)};
- Field<int> vertex_field_2{std::make_shared<EdgeVerticesFieldInput>(VERTEX_TWO)};
- Field<float3> position_field_1{std::make_shared<EdgePositionFieldInput>(VERTEX_ONE)};
- Field<float3> position_field_2{std::make_shared<EdgePositionFieldInput>(VERTEX_TWO)};
+ Field<int> vertex_field_1{std::make_shared<EdgeVertsInput>(VertNumber::V1)};
+ Field<int> vertex_field_2{std::make_shared<EdgeVertsInput>(VertNumber::V2)};
+ Field<float3> position_field_1{std::make_shared<EdgePositionFieldInput>(VertNumber::V1)};
+ Field<float3> position_field_2{std::make_shared<EdgePositionFieldInput>(VertNumber::V2)};
params.set_output("Vertex Index 1", std::move(vertex_field_1));
params.set_output("Vertex Index 2", std::move(vertex_field_2));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc
index 4d21bf9443a..aec1c27a4fc 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc
@@ -16,39 +16,33 @@ static void node_declare(NodeDeclarationBuilder &b)
.description(N_("The surface area of each of the mesh's faces"));
}
-static VArray<float> construct_face_area_gvarray(const MeshComponent &component,
- const eAttrDomain domain)
+static VArray<float> construct_face_area_varray(const Mesh &mesh, const eAttrDomain domain)
{
- const Mesh *mesh = component.get_for_read();
- if (mesh == nullptr) {
- return {};
- }
+ const Span<MVert> verts = mesh.verts();
+ const Span<MPoly> polys = mesh.polys();
+ const Span<MLoop> loops = mesh.loops();
- auto area_fn = [mesh](const int i) -> float {
- const MPoly *mp = &mesh->mpoly[i];
- return BKE_mesh_calc_poly_area(mp, &mesh->mloop[mp->loopstart], mesh->mvert);
+ auto area_fn = [verts, polys, loops](const int i) -> float {
+ const MPoly &poly = polys[i];
+ return BKE_mesh_calc_poly_area(&poly, &loops[poly.loopstart], verts.data());
};
- return component.attributes()->adapt_domain<float>(
- VArray<float>::ForFunc(mesh->totpoly, area_fn), ATTR_DOMAIN_FACE, domain);
+ return mesh.attributes().adapt_domain<float>(
+ VArray<float>::ForFunc(polys.size(), area_fn), ATTR_DOMAIN_FACE, domain);
}
-class FaceAreaFieldInput final : public GeometryFieldInput {
+class FaceAreaFieldInput final : public bke::MeshFieldInput {
public:
- FaceAreaFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Face Area Field")
+ FaceAreaFieldInput() : bke::MeshFieldInput(CPPType::get<float>(), "Face Area Field")
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
+ GVArray get_varray_for_context(const Mesh &mesh,
const eAttrDomain domain,
- IndexMask UNUSED(mask)) const final
+ const IndexMask /*mask*/) const final
{
- if (component.type() == GEO_COMPONENT_TYPE_MESH) {
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- return construct_face_area_gvarray(mesh_component, domain);
- }
- return {};
+ return construct_face_area_varray(mesh, domain);
}
uint64_t hash() const override
@@ -61,6 +55,11 @@ class FaceAreaFieldInput final : public GeometryFieldInput {
{
return dynamic_cast<const FaceAreaFieldInput *>(&other) != nullptr;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_FACE;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc
index 6b04ff08d9e..7b084995fc3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc
@@ -22,53 +22,46 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Bool>("Planar").field_source();
}
-class PlanarFieldInput final : public GeometryFieldInput {
+class PlanarFieldInput final : public bke::MeshFieldInput {
private:
Field<float> threshold_;
public:
PlanarFieldInput(Field<float> threshold)
- : GeometryFieldInput(CPPType::get<bool>(), "Planar"), threshold_(threshold)
+ : bke::MeshFieldInput(CPPType::get<bool>(), "Planar"), threshold_(threshold)
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
+ GVArray get_varray_for_context(const Mesh &mesh,
const eAttrDomain domain,
- [[maybe_unused]] IndexMask mask) const final
+ IndexMask /*mask*/) const final
{
- if (component.type() != GEO_COMPONENT_TYPE_MESH) {
- return {};
- }
-
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- const Mesh *mesh = mesh_component.get_for_read();
- if (mesh == nullptr) {
- return {};
- }
-
- GeometryComponentFieldContext context{mesh_component, ATTR_DOMAIN_FACE};
- fn::FieldEvaluator evaluator{context, mesh->totpoly};
+ const Span<MVert> verts = mesh.verts();
+ const Span<MPoly> polys = mesh.polys();
+ const Span<MLoop> loops = mesh.loops();
+ const Span<float3> poly_normals{
+ reinterpret_cast<const float3 *>(BKE_mesh_poly_normals_ensure(&mesh)), mesh.totpoly};
+
+ bke::MeshFieldContext context{mesh, ATTR_DOMAIN_FACE};
+ fn::FieldEvaluator evaluator{context, polys.size()};
evaluator.add(threshold_);
evaluator.evaluate();
const VArray<float> thresholds = evaluator.get_evaluated<float>(0);
- Span<float3> poly_normals{(float3 *)BKE_mesh_poly_normals_ensure(mesh), mesh->totpoly};
-
- auto planar_fn = [mesh, thresholds, poly_normals](const int i_poly) -> bool {
- if (mesh->mpoly[i_poly].totloop <= 3) {
+ auto planar_fn = [verts, polys, loops, thresholds, poly_normals](const int i) -> bool {
+ const MPoly &poly = polys[i];
+ if (poly.totloop <= 3) {
return true;
}
- const int loopstart = mesh->mpoly[i_poly].loopstart;
- const int loops = mesh->mpoly[i_poly].totloop;
- Span<MLoop> poly_loops(&mesh->mloop[loopstart], loops);
- float3 reference_normal = poly_normals[i_poly];
+ const Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
+ const float3 &reference_normal = poly_normals[i];
float min = FLT_MAX;
float max = -FLT_MAX;
for (const int i_loop : poly_loops.index_range()) {
- const float3 vert = mesh->mvert[poly_loops[i_loop].v].co;
+ const float3 vert = verts[poly_loops[i_loop].v].co;
float dot = math::dot(reference_normal, vert);
if (dot > max) {
max = dot;
@@ -77,11 +70,11 @@ class PlanarFieldInput final : public GeometryFieldInput {
min = dot;
}
}
- return max - min < thresholds[i_poly] / 2.0f;
+ return max - min < thresholds[i] / 2.0f;
};
- return component.attributes()->adapt_domain<bool>(
- VArray<bool>::ForFunc(mesh->totpoly, planar_fn), ATTR_DOMAIN_FACE, domain);
+ return mesh.attributes().adapt_domain<bool>(
+ VArray<bool>::ForFunc(polys.size(), planar_fn), ATTR_DOMAIN_FACE, domain);
}
uint64_t hash() const override
@@ -94,6 +87,11 @@ class PlanarFieldInput final : public GeometryFieldInput {
{
return dynamic_cast<const PlanarFieldInput *>(&other) != nullptr;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_FACE;
+ }
};
static void geo_node_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc
index a225ce61b14..f1724ef4a41 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc
@@ -19,48 +19,41 @@ static void node_declare(NodeDeclarationBuilder &b)
.description(N_("Number of faces which share an edge with the face"));
}
-static VArray<int> construct_neighbor_count_gvarray(const MeshComponent &component,
- const eAttrDomain domain)
+static VArray<int> construct_neighbor_count_varray(const Mesh &mesh, const eAttrDomain domain)
{
- const Mesh *mesh = component.get_for_read();
- if (mesh == nullptr) {
- return {};
- }
+ const Span<MPoly> polys = mesh.polys();
+ const Span<MLoop> loops = mesh.loops();
- Array<int> edge_count(mesh->totedge, 0);
- for (const int i : IndexRange(mesh->totloop)) {
- edge_count[mesh->mloop[i].e]++;
+ Array<int> edge_count(mesh.totedge, 0);
+ for (const MLoop &loop : loops) {
+ edge_count[loop.e]++;
}
- Array<int> poly_count(mesh->totpoly, 0);
- for (const int poly_num : IndexRange(mesh->totpoly)) {
- MPoly &poly = mesh->mpoly[poly_num];
- for (const int loop_num : IndexRange(poly.loopstart, poly.totloop)) {
- poly_count[poly_num] += edge_count[mesh->mloop[loop_num].e] - 1;
+ Array<int> poly_count(polys.size(), 0);
+ for (const int poly_index : polys.index_range()) {
+ const MPoly &poly = polys[poly_index];
+ for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) {
+ poly_count[poly_index] += edge_count[loop.e] - 1;
}
}
- return component.attributes()->adapt_domain<int>(
+ return mesh.attributes().adapt_domain<int>(
VArray<int>::ForContainer(std::move(poly_count)), ATTR_DOMAIN_FACE, domain);
}
-class FaceNeighborCountFieldInput final : public GeometryFieldInput {
+class FaceNeighborCountFieldInput final : public bke::MeshFieldInput {
public:
FaceNeighborCountFieldInput()
- : GeometryFieldInput(CPPType::get<int>(), "Face Neighbor Count Field")
+ : bke::MeshFieldInput(CPPType::get<int>(), "Face Neighbor Count Field")
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
+ GVArray get_varray_for_context(const Mesh &mesh,
const eAttrDomain domain,
- IndexMask UNUSED(mask)) const final
+ const IndexMask /*mask*/) const final
{
- if (component.type() == GEO_COMPONENT_TYPE_MESH) {
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- return construct_neighbor_count_gvarray(mesh_component, domain);
- }
- return {};
+ return construct_neighbor_count_varray(mesh, domain);
}
uint64_t hash() const override
@@ -73,39 +66,35 @@ class FaceNeighborCountFieldInput final : public GeometryFieldInput {
{
return dynamic_cast<const FaceNeighborCountFieldInput *>(&other) != nullptr;
}
-};
-static VArray<int> construct_vertex_count_gvarray(const MeshComponent &component,
- const eAttrDomain domain)
-{
- const Mesh *mesh = component.get_for_read();
- if (mesh == nullptr) {
- return {};
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_FACE;
}
+};
- return component.attributes()->adapt_domain<int>(
- VArray<int>::ForFunc(mesh->totpoly,
- [mesh](const int i) -> float { return mesh->mpoly[i].totloop; }),
+static VArray<int> construct_vertex_count_varray(const Mesh &mesh, const eAttrDomain domain)
+{
+ const Span<MPoly> polys = mesh.polys();
+ return mesh.attributes().adapt_domain<int>(
+ VArray<int>::ForFunc(polys.size(),
+ [polys](const int i) -> float { return polys[i].totloop; }),
ATTR_DOMAIN_FACE,
domain);
}
-class FaceVertexCountFieldInput final : public GeometryFieldInput {
+class FaceVertexCountFieldInput final : public bke::MeshFieldInput {
public:
- FaceVertexCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Vertex Count Field")
+ FaceVertexCountFieldInput() : bke::MeshFieldInput(CPPType::get<int>(), "Vertex Count Field")
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
+ GVArray get_varray_for_context(const Mesh &mesh,
const eAttrDomain domain,
- IndexMask UNUSED(mask)) const final
+ const IndexMask /*mask*/) const final
{
- if (component.type() == GEO_COMPONENT_TYPE_MESH) {
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- return construct_vertex_count_gvarray(mesh_component, domain);
- }
- return {};
+ return construct_vertex_count_varray(mesh, domain);
}
uint64_t hash() const override
@@ -118,6 +107,11 @@ class FaceVertexCountFieldInput final : public GeometryFieldInput {
{
return dynamic_cast<const FaceVertexCountFieldInput *>(&other) != nullptr;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_FACE;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc
index 2c7eef5665f..6b54828b042 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc
@@ -22,39 +22,32 @@ static void node_declare(NodeDeclarationBuilder &b)
.description(N_("The total number of mesh islands"));
}
-class IslandFieldInput final : public GeometryFieldInput {
+class IslandFieldInput final : public bke::MeshFieldInput {
public:
- IslandFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Island Index")
+ IslandFieldInput() : bke::MeshFieldInput(CPPType::get<int>(), "Island Index")
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
+ GVArray get_varray_for_context(const Mesh &mesh,
const eAttrDomain domain,
- IndexMask UNUSED(mask)) const final
+ const IndexMask /*mask*/) const final
{
- if (component.type() != GEO_COMPONENT_TYPE_MESH) {
- return {};
- }
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- const Mesh *mesh = mesh_component.get_for_read();
- if (mesh == nullptr) {
- return {};
- }
+ const Span<MEdge> edges = mesh.edges();
- DisjointSet islands(mesh->totvert);
- for (const int i : IndexRange(mesh->totedge)) {
- islands.join(mesh->medge[i].v1, mesh->medge[i].v2);
+ DisjointSet islands(mesh.totvert);
+ for (const int i : edges.index_range()) {
+ islands.join(edges[i].v1, edges[i].v2);
}
- Array<int> output(mesh->totvert);
+ Array<int> output(mesh.totvert);
VectorSet<int> ordered_roots;
- for (const int i : IndexRange(mesh->totvert)) {
+ for (const int i : IndexRange(mesh.totvert)) {
const int64_t root = islands.find_root(i);
output[i] = ordered_roots.index_of_or_add(root);
}
- return mesh_component.attributes()->adapt_domain<int>(
+ return mesh.attributes().adapt_domain<int>(
VArray<int>::ForContainer(std::move(output)), ATTR_DOMAIN_POINT, domain);
}
@@ -68,41 +61,38 @@ class IslandFieldInput final : public GeometryFieldInput {
{
return dynamic_cast<const IslandFieldInput *>(&other) != nullptr;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_POINT;
+ }
};
-class IslandCountFieldInput final : public GeometryFieldInput {
+class IslandCountFieldInput final : public bke::MeshFieldInput {
public:
- IslandCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Island Count")
+ IslandCountFieldInput() : bke::MeshFieldInput(CPPType::get<int>(), "Island Count")
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
+ GVArray get_varray_for_context(const Mesh &mesh,
const eAttrDomain domain,
- IndexMask UNUSED(mask)) const final
+ const IndexMask /*mask*/) const final
{
- if (component.type() != GEO_COMPONENT_TYPE_MESH) {
- return {};
- }
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- const Mesh *mesh = mesh_component.get_for_read();
- if (mesh == nullptr) {
- return {};
- }
+ const Span<MEdge> edges = mesh.edges();
- DisjointSet islands(mesh->totvert);
- for (const int i : IndexRange(mesh->totedge)) {
- islands.join(mesh->medge[i].v1, mesh->medge[i].v2);
+ DisjointSet islands(mesh.totvert);
+ for (const int i : edges.index_range()) {
+ islands.join(edges[i].v1, edges[i].v2);
}
Set<int> island_list;
- for (const int i_vert : IndexRange(mesh->totvert)) {
+ for (const int i_vert : IndexRange(mesh.totvert)) {
const int64_t root = islands.find_root(i_vert);
island_list.add(root);
}
- return VArray<int>::ForSingle(island_list.size(),
- mesh_component.attribute_domain_size(domain));
+ return VArray<int>::ForSingle(island_list.size(), mesh.attributes().domain_size(domain));
}
uint64_t hash() const override
@@ -115,6 +105,11 @@ class IslandCountFieldInput final : public GeometryFieldInput {
{
return dynamic_cast<const IslandCountFieldInput *>(&other) != nullptr;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_POINT;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc
index 62b3f9d0e92..5b1b32c7b9c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc
@@ -20,41 +20,32 @@ static void node_declare(NodeDeclarationBuilder &b)
.description(N_("Number of faces that contain the vertex"));
}
-static VArray<int> construct_vertex_count_gvarray(const MeshComponent &component,
- const eAttrDomain domain)
+static VArray<int> construct_vertex_count_gvarray(const Mesh &mesh, const eAttrDomain domain)
{
- const Mesh *mesh = component.get_for_read();
- if (mesh == nullptr) {
- return {};
- }
-
+ const Span<MEdge> edges = mesh.edges();
if (domain == ATTR_DOMAIN_POINT) {
- Array<int> vertices(mesh->totvert, 0);
- for (const int i : IndexRange(mesh->totedge)) {
- vertices[mesh->medge[i].v1]++;
- vertices[mesh->medge[i].v2]++;
+ Array<int> counts(mesh.totvert, 0);
+ for (const int i : edges.index_range()) {
+ counts[edges[i].v1]++;
+ counts[edges[i].v2]++;
}
- return VArray<int>::ForContainer(std::move(vertices));
+ return VArray<int>::ForContainer(std::move(counts));
}
return {};
}
-class VertexCountFieldInput final : public GeometryFieldInput {
+class VertexCountFieldInput final : public bke::MeshFieldInput {
public:
- VertexCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Vertex Count Field")
+ VertexCountFieldInput() : bke::MeshFieldInput(CPPType::get<int>(), "Vertex Count Field")
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
+ GVArray get_varray_for_context(const Mesh &mesh,
const eAttrDomain domain,
- IndexMask UNUSED(mask)) const final
+ const IndexMask /*mask*/) const final
{
- if (component.type() == GEO_COMPONENT_TYPE_MESH) {
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- return construct_vertex_count_gvarray(mesh_component, domain);
- }
- return {};
+ return construct_vertex_count_gvarray(mesh, domain);
}
uint64_t hash() const override
@@ -67,20 +58,20 @@ class VertexCountFieldInput final : public GeometryFieldInput {
{
return dynamic_cast<const VertexCountFieldInput *>(&other) != nullptr;
}
-};
-static VArray<int> construct_face_count_gvarray(const MeshComponent &component,
- const eAttrDomain domain)
-{
- const Mesh *mesh = component.get_for_read();
- if (mesh == nullptr) {
- return {};
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_POINT;
}
+};
+static VArray<int> construct_face_count_gvarray(const Mesh &mesh, const eAttrDomain domain)
+{
+ const Span<MLoop> loops = mesh.loops();
if (domain == ATTR_DOMAIN_POINT) {
- Array<int> vertices(mesh->totvert, 0);
- for (const int i : IndexRange(mesh->totloop)) {
- int vertex = mesh->mloop[i].v;
+ Array<int> vertices(mesh.totvert, 0);
+ for (const int i : loops.index_range()) {
+ int vertex = loops[i].v;
vertices[vertex]++;
}
return VArray<int>::ForContainer(std::move(vertices));
@@ -88,22 +79,18 @@ static VArray<int> construct_face_count_gvarray(const MeshComponent &component,
return {};
}
-class VertexFaceCountFieldInput final : public GeometryFieldInput {
+class VertexFaceCountFieldInput final : public bke::MeshFieldInput {
public:
- VertexFaceCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Vertex Face Count Field")
+ VertexFaceCountFieldInput() : bke::MeshFieldInput(CPPType::get<int>(), "Vertex Face Count Field")
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
+ GVArray get_varray_for_context(const Mesh &mesh,
const eAttrDomain domain,
- IndexMask UNUSED(mask)) const final
+ const IndexMask /*mask*/) const final
{
- if (component.type() == GEO_COMPONENT_TYPE_MESH) {
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- return construct_face_count_gvarray(mesh_component, domain);
- }
- return {};
+ return construct_face_count_gvarray(mesh, domain);
}
uint64_t hash() const override
@@ -116,6 +103,11 @@ class VertexFaceCountFieldInput final : public GeometryFieldInput {
{
return dynamic_cast<const VertexFaceCountFieldInput *>(&other) != nullptr;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_POINT;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc
index 122c7b352c7..1063a022e9d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc
@@ -22,12 +22,12 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Int>(N_("Attribute"), "Attribute_Int").field_source();
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryInputNamedAttribute *data = MEM_cnew<NodeGeometryInputNamedAttribute>(__func__);
data->data_type = CD_PROP_FLOAT;
@@ -37,9 +37,9 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeGeometryInputNamedAttribute &storage = node_storage(*node);
- const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
+ const eCustomDataType data_type = eCustomDataType(storage.data_type);
- bNodeSocket *socket_vector = (bNodeSocket *)node->outputs.first;
+ bNodeSocket *socket_vector = static_cast<bNodeSocket *>(node->outputs.first);
bNodeSocket *socket_float = socket_vector->next;
bNodeSocket *socket_color4f = socket_float->next;
bNodeSocket *socket_boolean = socket_color4f->next;
@@ -59,7 +59,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
if (params.in_out() == SOCK_OUT) {
const std::optional<eCustomDataType> type = node_data_type_to_custom_data_type(
- static_cast<eNodeSocketDatatype>(params.other_socket().type));
+ eNodeSocketDatatype(params.other_socket().type));
if (type && *type != CD_PROP_STRING) {
/* The input and output sockets have the same name. */
params.add_item(IFACE_("Attribute"), [type](LinkSearchOpParams &params) {
@@ -74,7 +74,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
static void node_geo_exec(GeoNodeExecParams params)
{
const NodeGeometryInputNamedAttribute &storage = node_storage(params.node());
- const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
+ const eCustomDataType data_type = eCustomDataType(storage.data_type);
const std::string name = params.extract_input<std::string>("Name");
@@ -88,7 +88,7 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
- params.used_named_attribute(name, eNamedAttrUsage::Read);
+ params.used_named_attribute(name, NamedAttributeUsage::Read);
switch (data_type) {
case CD_PROP_FLOAT:
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc b/source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc
index 0222ccbbd02..74d10c286a0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc
@@ -18,7 +18,7 @@ static void node_exec(GeoNodeExecParams params)
{
const Scene *scene = DEG_get_input_scene(params.depsgraph());
const float scene_ctime = BKE_scene_ctime_get(scene);
- const double frame_rate = (((double)scene->r.frs_sec) / (double)scene->r.frs_sec_base);
+ const double frame_rate = (double(scene->r.frs_sec) / double(scene->r.frs_sec_base));
params.set_output("Seconds", float(scene_ctime / frame_rate));
params.set_output("Frame", scene_ctime);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_shortest_edge_paths.cc b/source/blender/nodes/geometry/nodes/node_geo_input_shortest_edge_paths.cc
index ca6406d2810..00c92e30443 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_shortest_edge_paths.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_shortest_edge_paths.cc
@@ -2,14 +2,12 @@
#include <queue>
-#include "BKE_curves.hh"
-
#include "BLI_map.hh"
#include "BLI_math_vec_types.hh"
#include "BLI_set.hh"
+#include "BLI_task.hh"
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
+#include "BKE_mesh.h"
#include "node_geometry_util.hh"
@@ -28,10 +26,10 @@ typedef std::pair<float, int> VertPriority;
struct EdgeVertMap {
Array<Vector<int>> edges_by_vertex_map;
- EdgeVertMap(const Mesh *mesh)
+ EdgeVertMap(const Mesh &mesh)
{
- const Span<MEdge> edges{mesh->medge, mesh->totedge};
- edges_by_vertex_map.reinitialize(mesh->totvert);
+ const Span<MEdge> edges = mesh.edges();
+ edges_by_vertex_map.reinitialize(mesh.totvert);
for (const int edge_i : edges.index_range()) {
const MEdge &edge = edges[edge_i];
edges_by_vertex_map[edge.v1].append(edge_i);
@@ -40,16 +38,15 @@ struct EdgeVertMap {
}
};
-static void shortest_paths(const Mesh *mesh,
+static void shortest_paths(const Mesh &mesh,
EdgeVertMap &maps,
const IndexMask end_selection,
const VArray<float> &input_cost,
MutableSpan<int> r_next_index,
MutableSpan<float> r_cost)
{
- const Span<MVert> verts{mesh->mvert, mesh->totvert};
- const Span<MEdge> edges{mesh->medge, mesh->totedge};
- Array<bool> visited(mesh->totvert, false);
+ const Span<MEdge> edges = mesh.edges();
+ Array<bool> visited(mesh.totvert, false);
std::priority_queue<VertPriority, std::vector<VertPriority>, std::greater<VertPriority>> queue;
@@ -84,46 +81,38 @@ static void shortest_paths(const Mesh *mesh,
}
}
-class ShortestEdgePathsNextVertFieldInput final : public GeometryFieldInput {
+class ShortestEdgePathsNextVertFieldInput final : public bke::MeshFieldInput {
private:
Field<bool> end_selection_;
Field<float> cost_;
public:
ShortestEdgePathsNextVertFieldInput(Field<bool> end_selection, Field<float> cost)
- : GeometryFieldInput(CPPType::get<int>(), "Shortest Edge Paths Next Vertex Field"),
+ : bke::MeshFieldInput(CPPType::get<int>(), "Shortest Edge Paths Next Vertex Field"),
end_selection_(end_selection),
cost_(cost)
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
+ GVArray get_varray_for_context(const Mesh &mesh,
const eAttrDomain domain,
- [[maybe_unused]] IndexMask mask) const final
+ const IndexMask /*mask*/) const final
{
- if (component.type() != GEO_COMPONENT_TYPE_MESH) {
- return {};
- }
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- const Mesh *mesh = mesh_component.get_for_read();
- if (mesh == nullptr) {
- return {};
- }
- GeometryComponentFieldContext edge_context{component, ATTR_DOMAIN_EDGE};
- fn::FieldEvaluator edge_evaluator{edge_context, mesh->totedge};
+ bke::MeshFieldContext edge_context{mesh, ATTR_DOMAIN_EDGE};
+ fn::FieldEvaluator edge_evaluator{edge_context, mesh.totedge};
edge_evaluator.add(cost_);
edge_evaluator.evaluate();
const VArray<float> input_cost = edge_evaluator.get_evaluated<float>(0);
- GeometryComponentFieldContext point_context{component, ATTR_DOMAIN_POINT};
- fn::FieldEvaluator point_evaluator{point_context, mesh->totvert};
+ bke::MeshFieldContext point_context{mesh, ATTR_DOMAIN_POINT};
+ fn::FieldEvaluator point_evaluator{point_context, mesh.totvert};
point_evaluator.add(end_selection_);
point_evaluator.evaluate();
const IndexMask end_selection = point_evaluator.get_evaluated_as_mask(0);
- Array<int> next_index(mesh->totvert, -1);
- Array<float> cost(mesh->totvert, FLT_MAX);
+ Array<int> next_index(mesh.totvert, -1);
+ Array<float> cost(mesh.totvert, FLT_MAX);
if (!end_selection.is_empty()) {
EdgeVertMap maps(mesh);
@@ -136,7 +125,7 @@ class ShortestEdgePathsNextVertFieldInput final : public GeometryFieldInput {
}
}
});
- return component.attributes()->adapt_domain<int>(
+ return mesh.attributes().adapt_domain<int>(
VArray<int>::ForContainer(std::move(next_index)), ATTR_DOMAIN_POINT, domain);
}
@@ -154,48 +143,45 @@ class ShortestEdgePathsNextVertFieldInput final : public GeometryFieldInput {
}
return false;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_POINT;
+ }
};
-class ShortestEdgePathsCostFieldInput final : public GeometryFieldInput {
+class ShortestEdgePathsCostFieldInput final : public bke::MeshFieldInput {
private:
Field<bool> end_selection_;
Field<float> cost_;
public:
ShortestEdgePathsCostFieldInput(Field<bool> end_selection, Field<float> cost)
- : GeometryFieldInput(CPPType::get<float>(), "Shortest Edge Paths Cost Field"),
+ : bke::MeshFieldInput(CPPType::get<float>(), "Shortest Edge Paths Cost Field"),
end_selection_(end_selection),
cost_(cost)
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
+ GVArray get_varray_for_context(const Mesh &mesh,
const eAttrDomain domain,
- [[maybe_unused]] IndexMask mask) const final
+ const IndexMask /*mask*/) const final
{
- if (component.type() != GEO_COMPONENT_TYPE_MESH) {
- return {};
- }
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- const Mesh *mesh = mesh_component.get_for_read();
- if (mesh == nullptr) {
- return {};
- }
- GeometryComponentFieldContext edge_context{component, ATTR_DOMAIN_EDGE};
- fn::FieldEvaluator edge_evaluator{edge_context, mesh->totedge};
+ bke::MeshFieldContext edge_context{mesh, ATTR_DOMAIN_EDGE};
+ fn::FieldEvaluator edge_evaluator{edge_context, mesh.totedge};
edge_evaluator.add(cost_);
edge_evaluator.evaluate();
const VArray<float> input_cost = edge_evaluator.get_evaluated<float>(0);
- GeometryComponentFieldContext point_context{component, ATTR_DOMAIN_POINT};
- fn::FieldEvaluator point_evaluator{point_context, mesh->totvert};
+ bke::MeshFieldContext point_context{mesh, ATTR_DOMAIN_POINT};
+ fn::FieldEvaluator point_evaluator{point_context, mesh.totvert};
point_evaluator.add(end_selection_);
point_evaluator.evaluate();
const IndexMask end_selection = point_evaluator.get_evaluated_as_mask(0);
- Array<int> next_index(mesh->totvert, -1);
- Array<float> cost(mesh->totvert, FLT_MAX);
+ Array<int> next_index(mesh.totvert, -1);
+ Array<float> cost(mesh.totvert, FLT_MAX);
if (!end_selection.is_empty()) {
EdgeVertMap maps(mesh);
@@ -208,7 +194,7 @@ class ShortestEdgePathsCostFieldInput final : public GeometryFieldInput {
}
}
});
- return component.attributes()->adapt_domain<float>(
+ return mesh.attributes().adapt_domain<float>(
VArray<float>::ForContainer(std::move(cost)), ATTR_DOMAIN_POINT, domain);
}
@@ -225,6 +211,11 @@ class ShortestEdgePathsCostFieldInput final : public GeometryFieldInput {
}
return false;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_POINT;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
index 267ba44cc00..4bb4618588b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
@@ -16,15 +16,9 @@ static void node_declare(NodeDeclarationBuilder &b)
* Spline Count
*/
-static VArray<int> construct_curve_point_count_gvarray(const CurveComponent &component,
+static VArray<int> construct_curve_point_count_gvarray(const bke::CurvesGeometry &curves,
const eAttrDomain domain)
{
- if (!component.has_curves()) {
- return {};
- }
- const Curves &curves_id = *component.get_for_read();
- const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
-
auto count_fn = [curves](int64_t i) { return curves.points_for_curve(i).size(); };
if (domain == ATTR_DOMAIN_CURVE) {
@@ -32,29 +26,24 @@ static VArray<int> construct_curve_point_count_gvarray(const CurveComponent &com
}
if (domain == ATTR_DOMAIN_POINT) {
VArray<int> count = VArray<int>::ForFunc(curves.curves_num(), count_fn);
- return component.attributes()->adapt_domain<int>(
- std::move(count), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
+ return curves.adapt_domain<int>(std::move(count), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
}
return {};
}
-class SplineCountFieldInput final : public GeometryFieldInput {
+class SplineCountFieldInput final : public bke::CurvesFieldInput {
public:
- SplineCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Spline Point Count")
+ SplineCountFieldInput() : bke::CurvesFieldInput(CPPType::get<int>(), "Spline Point Count")
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
+ GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
const eAttrDomain domain,
- IndexMask UNUSED(mask)) const final
+ const IndexMask /*mask*/) const final
{
- if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- return construct_curve_point_count_gvarray(curve_component, domain);
- }
- return {};
+ return construct_curve_point_count_gvarray(curves, domain);
}
uint64_t hash() const override
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
index a2aab5464aa..7e7b0eb215f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
@@ -63,19 +63,12 @@ static Array<float3> curve_tangent_point_domain(const bke::CurvesGeometry &curve
return results;
}
-static VArray<float3> construct_curve_tangent_gvarray(const CurveComponent &component,
+static VArray<float3> construct_curve_tangent_gvarray(const bke::CurvesGeometry &curves,
const eAttrDomain domain)
{
- if (!component.has_curves()) {
- return {};
- }
-
- const Curves &curves_id = *component.get_for_read();
- const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
-
const VArray<int8_t> types = curves.curve_types();
if (curves.is_single_type(CURVE_TYPE_POLY)) {
- return component.attributes()->adapt_domain<float3>(
+ return curves.adapt_domain<float3>(
VArray<float3>::ForSpan(curves.evaluated_tangents()), ATTR_DOMAIN_POINT, domain);
}
@@ -86,29 +79,25 @@ static VArray<float3> construct_curve_tangent_gvarray(const CurveComponent &comp
}
if (domain == ATTR_DOMAIN_CURVE) {
- return component.attributes()->adapt_domain<float3>(
+ return curves.adapt_domain<float3>(
VArray<float3>::ForContainer(std::move(tangents)), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
}
return nullptr;
}
-class TangentFieldInput final : public GeometryFieldInput {
+class TangentFieldInput final : public bke::CurvesFieldInput {
public:
- TangentFieldInput() : GeometryFieldInput(CPPType::get<float3>(), "Tangent node")
+ TangentFieldInput() : bke::CurvesFieldInput(CPPType::get<float3>(), "Tangent node")
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
+ GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
const eAttrDomain domain,
- IndexMask UNUSED(mask)) const final
+ const IndexMask /*mask*/) const final
{
- if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- return construct_curve_tangent_gvarray(curve_component, domain);
- }
- return {};
+ return construct_curve_tangent_gvarray(curves, domain);
}
uint64_t hash() const override
diff --git a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
index 37f9917f39d..affeb43e33b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
@@ -9,6 +9,7 @@
#include "UI_resources.h"
#include "BKE_attribute_math.hh"
+#include "BKE_instances.hh"
#include "node_geometry_util.hh"
@@ -25,7 +26,7 @@ static void node_declare(NodeDeclarationBuilder &b)
.description(N_("Choose instances from the \"Instance\" input at each point instead of "
"instancing the entire geometry"));
b.add_input<decl::Int>(N_("Instance Index"))
- .implicit_field()
+ .implicit_field(implicit_field_inputs::id_or_index)
.description(N_(
"Index of the instance that used for each point. This is only used when Pick Instances "
"is on. By default the point index is used"));
@@ -43,7 +44,7 @@ static void node_declare(NodeDeclarationBuilder &b)
}
static void add_instances_from_component(
- InstancesComponent &dst_component,
+ bke::Instances &dst_component,
const GeometryComponent &src_component,
const GeometrySet &instance,
const GeoNodeExecParams &params,
@@ -57,7 +58,7 @@ static void add_instances_from_component(
VArray<float3> rotations;
VArray<float3> scales;
- GeometryComponentFieldContext field_context{src_component, domain};
+ bke::GeometryFieldContext field_context{src_component, domain};
const Field<bool> selection_field = params.get_input<Field<bool>>("Selection");
fn::FieldEvaluator evaluator{field_context, domain_num};
evaluator.set_selection(selection_field);
@@ -80,25 +81,23 @@ static void add_instances_from_component(
const int select_len = selection.index_range().size();
dst_component.resize(start_len + select_len);
- MutableSpan<int> dst_handles = dst_component.instance_reference_handles().slice(start_len,
- select_len);
- MutableSpan<float4x4> dst_transforms = dst_component.instance_transforms().slice(start_len,
- select_len);
+ MutableSpan<int> dst_handles = dst_component.reference_handles().slice(start_len, select_len);
+ MutableSpan<float4x4> dst_transforms = dst_component.transforms().slice(start_len, select_len);
VArray<float3> positions = src_component.attributes()->lookup_or_default<float3>(
"position", domain, {0, 0, 0});
- const InstancesComponent *src_instances = instance.get_component_for_read<InstancesComponent>();
+ const bke::Instances *src_instances = instance.get_instances_for_read();
/* Maps handles from the source instances to handles on the new instance. */
Array<int> handle_mapping;
/* Only fill #handle_mapping when it may be used below. */
if (src_instances != nullptr &&
(!pick_instance.is_single() || pick_instance.get_internal_single())) {
- Span<InstanceReference> src_references = src_instances->references();
+ Span<bke::InstanceReference> src_references = src_instances->references();
handle_mapping.reinitialize(src_references.size());
for (const int src_instance_handle : src_references.index_range()) {
- const InstanceReference &reference = src_references[src_instance_handle];
+ const bke::InstanceReference &reference = src_references[src_instance_handle];
const int dst_instance_handle = dst_component.add_reference(reference);
handle_mapping[src_instance_handle] = dst_instance_handle;
}
@@ -106,7 +105,7 @@ static void add_instances_from_component(
const int full_instance_handle = dst_component.add_reference(instance);
/* Add this reference last, because it is the most likely one to be removed later on. */
- const int empty_reference_handle = dst_component.add_reference(InstanceReference());
+ const int empty_reference_handle = dst_component.add_reference(bke::InstanceReference());
threading::parallel_for(selection.index_range(), 1024, [&](IndexRange selection_range) {
for (const int range_i : selection_range) {
@@ -129,12 +128,11 @@ static void add_instances_from_component(
const int index = mod_i(original_index, std::max(src_instances_num, 1));
if (index < src_instances_num) {
/* Get the reference to the source instance. */
- const int src_handle = src_instances->instance_reference_handles()[index];
+ const int src_handle = src_instances->reference_handles()[index];
dst_handle = handle_mapping[src_handle];
/* Take transforms of the source instance into account. */
- mul_m4_m4_post(dst_transform.values,
- src_instances->instance_transforms()[index].values);
+ mul_m4_m4_post(dst_transform.values, src_instances->transforms()[index].values);
}
}
}
@@ -157,7 +155,7 @@ static void add_instances_from_component(
}
}
- bke::CustomDataAttributes &instance_attributes = dst_component.instance_attributes();
+ bke::CustomDataAttributes &instance_attributes = dst_component.custom_data_attributes();
for (const auto item : attributes_to_propagate.items()) {
const AttributeIDRef &attribute_id = item.key;
const AttributeKind attribute_kind = item.value;
@@ -196,7 +194,15 @@ static void node_geo_exec(GeoNodeExecParams params)
instance.ensure_owns_direct_data();
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
+ /* It's important not to invalidate the existing #InstancesComponent because it owns references
+ * to other geometry sets that are processed by this node. */
+ InstancesComponent &instances_component =
+ geometry_set.get_component_for_write<InstancesComponent>();
+ bke::Instances *dst_instances = instances_component.get_for_write();
+ if (dst_instances == nullptr) {
+ dst_instances = new bke::Instances();
+ instances_component.replace(dst_instances);
+ }
const Array<GeometryComponentType> types{
GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE};
@@ -208,14 +214,13 @@ static void node_geo_exec(GeoNodeExecParams params)
for (const GeometryComponentType type : types) {
if (geometry_set.has(type)) {
- add_instances_from_component(instances,
+ add_instances_from_component(*dst_instances,
*geometry_set.get_component_for_read(type),
instance,
params,
attributes_to_propagate);
}
}
-
geometry_set.remove_geometry_during_modify();
});
@@ -223,8 +228,9 @@ static void node_geo_exec(GeoNodeExecParams params)
* process them needlessly.
* This should eventually be moved into the loop above, but currently this is quite tricky
* because it might remove references that the loop still wants to iterate over. */
- InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
- instances.remove_unused_references();
+ if (bke::Instances *instances = geometry_set.get_instances_for_write()) {
+ instances->remove_unused_references();
+ }
params.set_output("Instances", std::move(geometry_set));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
index 5e0789e557b..acd00d119ab 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
@@ -3,6 +3,7 @@
#include "DNA_pointcloud_types.h"
#include "BKE_attribute_math.hh"
+#include "BKE_instances.hh"
#include "BKE_pointcloud.h"
#include "node_geometry_util.hh"
@@ -13,7 +14,7 @@ static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Instances")).only_instances();
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
- b.add_input<decl::Vector>(N_("Position")).implicit_field();
+ b.add_input<decl::Vector>(N_("Position")).implicit_field(implicit_field_inputs::position);
b.add_input<decl::Float>(N_("Radius"))
.default_value(0.05f)
.min(0.0f)
@@ -27,12 +28,10 @@ static void convert_instances_to_points(GeometrySet &geometry_set,
Field<float> radius_field,
const Field<bool> selection_field)
{
- const InstancesComponent &instances = *geometry_set.get_component_for_read<InstancesComponent>();
+ const bke::Instances &instances = *geometry_set.get_instances_for_read();
- GeometryComponentFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE};
- const int domain_size = instances.instances_num();
-
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ const bke::InstancesFieldContext context{instances};
+ fn::FieldEvaluator evaluator{context, instances.instances_num()};
evaluator.set_selection(std::move(selection_field));
evaluator.add(std::move(position_field));
evaluator.add(std::move(radius_field));
@@ -47,8 +46,7 @@ static void convert_instances_to_points(GeometrySet &geometry_set,
PointCloud *pointcloud = BKE_pointcloud_new_nomain(selection.size());
geometry_set.replace_pointcloud(pointcloud);
- bke::MutableAttributeAccessor point_attributes = bke::pointcloud_attributes_for_write(
- *pointcloud);
+ bke::MutableAttributeAccessor point_attributes = pointcloud->attributes_for_write();
bke::SpanAttributeWriter<float3> point_positions =
point_attributes.lookup_or_add_for_write_only_span<float3>("position", ATTR_DOMAIN_POINT);
@@ -73,7 +71,7 @@ static void convert_instances_to_points(GeometrySet &geometry_set,
const AttributeIDRef &attribute_id = item.key;
const AttributeKind attribute_kind = item.value;
- const GVArray src = instances.attributes()->lookup_or_default(
+ const GVArray src = instances.attributes().lookup_or_default(
attribute_id, ATTR_DOMAIN_INSTANCE, attribute_kind.data_type);
BLI_assert(src);
GSpanAttributeWriter dst = point_attributes.lookup_or_add_for_write_only_span(
diff --git a/source/blender/nodes/geometry/nodes/node_geo_interpolate_domain.cc b/source/blender/nodes/geometry/nodes/node_geo_interpolate_domain.cc
index 93203988552..d4e18321665 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_interpolate_domain.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_interpolate_domain.cc
@@ -28,13 +28,13 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Bool>(N_("Value"), "Value_Bool").field_source();
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
node->custom1 = ATTR_DOMAIN_POINT;
node->custom2 = CD_PROP_FLOAT;
@@ -42,7 +42,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
{
- const eCustomDataType data_type = static_cast<eCustomDataType>(node->custom2);
+ const eCustomDataType data_type = eCustomDataType(node->custom2);
bNodeSocket *sock_in_float = static_cast<bNodeSocket *>(node->inputs.first);
bNodeSocket *sock_in_int = sock_in_float->next;
@@ -83,31 +83,39 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
}
}
-class InterpolateDomain final : public GeometryFieldInput {
+class InterpolateDomain final : public bke::GeometryFieldInput {
private:
GField src_field_;
eAttrDomain src_domain_;
public:
InterpolateDomain(GField field, eAttrDomain domain)
- : GeometryFieldInput(field.cpp_type(), "Interpolate Domain"),
+ : bke::GeometryFieldInput(field.cpp_type(), "Interpolate Domain"),
src_field_(std::move(field)),
src_domain_(domain)
{
}
- GVArray get_varray_for_context(const GeometryComponent &component,
- const eAttrDomain domain,
- IndexMask /* mask */) const final
+ GVArray get_varray_for_context(const bke::GeometryFieldContext &context,
+ IndexMask /*mask*/) const final
{
- const GeometryComponentFieldContext context{component, src_domain_};
- const int64_t src_domain_size = component.attribute_domain_size(src_domain_);
+ const bke::AttributeAccessor attributes = *context.attributes();
+
+ const bke::GeometryFieldContext other_domain_context{
+ context.geometry(), context.type(), src_domain_};
+ const int64_t src_domain_size = attributes.domain_size(src_domain_);
GArray values(src_field_.cpp_type(), src_domain_size);
- FieldEvaluator value_evaluator{context, src_domain_size};
+ FieldEvaluator value_evaluator{other_domain_context, src_domain_size};
value_evaluator.add_with_destination(src_field_, values.as_mutable_span());
value_evaluator.evaluate();
- return component.attributes()->adapt_domain(
- GVArray::ForGArray(std::move(values)), src_domain_, domain);
+ return attributes.adapt_domain(
+ GVArray::ForGArray(std::move(values)), src_domain_, context.domain());
+ }
+
+ std::optional<eAttrDomain> preferred_domain(
+ const GeometryComponent & /*component*/) const override
+ {
+ return src_domain_;
}
};
@@ -133,8 +141,8 @@ static StringRefNull identifier_suffix(eCustomDataType data_type)
static void node_geo_exec(GeoNodeExecParams params)
{
const bNode &node = params.node();
- const eAttrDomain domain = static_cast<eAttrDomain>(node.custom1);
- const eCustomDataType data_type = static_cast<eCustomDataType>(node.custom2);
+ const eAttrDomain domain = eAttrDomain(node.custom1);
+ const eCustomDataType data_type = eCustomDataType(node.custom2);
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
index 023d7a32a61..ea2646a9786 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
@@ -2,6 +2,8 @@
#include "GEO_realize_instances.hh"
+#include "BKE_instances.hh"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_join_geometry_cc {
@@ -29,6 +31,9 @@ static Map<AttributeIDRef, AttributeMetaData> get_final_attribute_info(
if (attribute_id.is_named() && ignored_attributes.contains(attribute_id.name())) {
return true;
}
+ if (meta_data.data_type == CD_PROP_STRING) {
+ return true;
+ }
info.add_or_modify(
attribute_id,
[&](AttributeMetaData *meta_data_final) { *meta_data_final = meta_data; },
@@ -97,40 +102,44 @@ static void join_attributes(Span<const GeometryComponent *> src_components,
static void join_components(Span<const InstancesComponent *> src_components, GeometrySet &result)
{
- InstancesComponent &dst_component = result.get_component_for_write<InstancesComponent>();
+ std::unique_ptr<bke::Instances> dst_instances = std::make_unique<bke::Instances>();
int tot_instances = 0;
for (const InstancesComponent *src_component : src_components) {
- tot_instances += src_component->instances_num();
+ tot_instances += src_component->get_for_read()->instances_num();
}
- dst_component.reserve(tot_instances);
+ dst_instances->reserve(tot_instances);
for (const InstancesComponent *src_component : src_components) {
- Span<InstanceReference> src_references = src_component->references();
+ const bke::Instances &src_instances = *src_component->get_for_read();
+
+ Span<bke::InstanceReference> src_references = src_instances.references();
Array<int> handle_map(src_references.size());
for (const int src_handle : src_references.index_range()) {
- handle_map[src_handle] = dst_component.add_reference(src_references[src_handle]);
+ handle_map[src_handle] = dst_instances->add_reference(src_references[src_handle]);
}
- Span<float4x4> src_transforms = src_component->instance_transforms();
- Span<int> src_reference_handles = src_component->instance_reference_handles();
+ Span<float4x4> src_transforms = src_instances.transforms();
+ Span<int> src_reference_handles = src_instances.reference_handles();
for (const int i : src_transforms.index_range()) {
const int src_handle = src_reference_handles[i];
const int dst_handle = handle_map[src_handle];
const float4x4 &transform = src_transforms[i];
- dst_component.add_instance(dst_handle, transform);
+ dst_instances->add_instance(dst_handle, transform);
}
}
+
+ result.replace_instances(dst_instances.release());
+ InstancesComponent &dst_component = result.get_component_for_write<InstancesComponent>();
join_attributes(to_base_components(src_components), dst_component, {"position"});
}
-static void join_components(Span<const VolumeComponent *> src_components, GeometrySet &result)
+static void join_components(Span<const VolumeComponent *> /*src_components*/,
+ GeometrySet & /*result*/)
{
/* Not yet supported. Joining volume grids with the same name requires resampling of at least one
* of the grids. The cell size of the resulting volume has to be determined somehow. */
- VolumeComponent &dst_component = result.get_component_for_write<VolumeComponent>();
- UNUSED_VARS(src_components, dst_component);
}
template<typename Component>
@@ -152,32 +161,30 @@ static void join_component_type(Span<GeometrySet> src_geometry_sets, GeometrySet
return;
}
- GeometrySet instances_geometry_set;
- InstancesComponent &instances =
- instances_geometry_set.get_component_for_write<InstancesComponent>();
-
if constexpr (is_same_any_v<Component, InstancesComponent, VolumeComponent>) {
join_components(components, result);
}
else {
+ std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>();
for (const Component *component : components) {
GeometrySet tmp_geo;
tmp_geo.add(*component);
- const int handle = instances.add_reference(InstanceReference{tmp_geo});
- instances.add_instance(handle, float4x4::identity());
+ const int handle = instances->add_reference(bke::InstanceReference{tmp_geo});
+ instances->add_instance(handle, float4x4::identity());
}
geometry::RealizeInstancesOptions options;
options.keep_original_ids = true;
options.realize_instance_attributes = false;
- GeometrySet joined_components = geometry::realize_instances(instances_geometry_set, options);
+ GeometrySet joined_components = geometry::realize_instances(
+ GeometrySet::create_with_instances(instances.release()), options);
result.add(joined_components.get_component_for_write<Component>());
}
}
static void node_geo_exec(GeoNodeExecParams params)
{
- Vector<GeometrySet> geometry_sets = params.extract_multi_input<GeometrySet>("Geometry");
+ Vector<GeometrySet> geometry_sets = params.extract_input<Vector<GeometrySet>>("Geometry");
GeometrySet geometry_set_result;
join_component_type<MeshComponent>(geometry_sets, geometry_set_result);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
index ca613ae009b..dfb4181926e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
@@ -23,46 +23,56 @@ static void node_declare(NodeDeclarationBuilder &b)
static void select_mesh_by_material(const Mesh &mesh,
const Material *material,
const IndexMask mask,
- const MutableSpan<bool> r_selection)
+ MutableSpan<bool> r_selection)
{
BLI_assert(mesh.totpoly >= r_selection.size());
- Vector<int> material_indices;
+ Vector<int> slots;
for (const int i : IndexRange(mesh.totcol)) {
if (mesh.mat[i] == material) {
- material_indices.append(i);
+ slots.append(i);
}
}
+ const AttributeAccessor attributes = mesh.attributes();
+ const VArray<int> material_indices = attributes.lookup_or_default<int>(
+ "material_index", ATTR_DOMAIN_FACE, 0);
+ if (material != nullptr && material_indices.is_single() &&
+ material_indices.get_internal_single() == 0) {
+ r_selection.fill_indices(mask, false);
+ return;
+ }
+
+ const VArraySpan<int> material_indices_span(material_indices);
+
threading::parallel_for(mask.index_range(), 1024, [&](IndexRange range) {
for (const int i : range) {
const int face_index = mask[i];
- r_selection[i] = material_indices.contains(mesh.mpoly[face_index].mat_nr);
+ r_selection[i] = slots.contains(material_indices_span[face_index]);
}
});
}
-class MaterialSelectionFieldInput final : public GeometryFieldInput {
+class MaterialSelectionFieldInput final : public bke::GeometryFieldInput {
Material *material_;
public:
MaterialSelectionFieldInput(Material *material)
- : GeometryFieldInput(CPPType::get<bool>(), "Material Selection node"), material_(material)
+ : bke::GeometryFieldInput(CPPType::get<bool>(), "Material Selection node"),
+ material_(material)
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
- const eAttrDomain domain,
- IndexMask mask) const final
+ GVArray get_varray_for_context(const bke::GeometryFieldContext &context,
+ const IndexMask mask) const final
{
- if (component.type() != GEO_COMPONENT_TYPE_MESH) {
+ if (context.type() != GEO_COMPONENT_TYPE_MESH) {
return {};
}
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- const Mesh *mesh = mesh_component.get_for_read();
+ const Mesh *mesh = context.mesh();
if (mesh == nullptr) {
return {};
}
-
+ const eAttrDomain domain = context.domain();
if (domain == ATTR_DOMAIN_FACE) {
Array<bool> selection(mask.min_array_size());
select_mesh_by_material(*mesh, material_, mask, selection);
@@ -71,7 +81,7 @@ class MaterialSelectionFieldInput final : public GeometryFieldInput {
Array<bool> selection(mesh->totpoly);
select_mesh_by_material(*mesh, material_, IndexMask(mesh->totpoly), selection);
- return mesh_component.attributes()->adapt_domain<bool>(
+ return mesh->attributes().adapt_domain<bool>(
VArray<bool>::ForContainer(std::move(selection)), ATTR_DOMAIN_FACE, domain);
return nullptr;
@@ -90,6 +100,12 @@ class MaterialSelectionFieldInput final : public GeometryFieldInput {
}
return false;
}
+
+ std::optional<eAttrDomain> preferred_domain(
+ const GeometryComponent & /*component*/) const override
+ {
+ return ATTR_DOMAIN_FACE;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc b/source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc
index a4fb79bef7a..ce8b078f195 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc
@@ -1,5 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "DNA_mesh_types.h"
+#include "DNA_pointcloud_types.h"
+
#include "GEO_mesh_merge_by_distance.hh"
#include "GEO_point_merge_by_distance.hh"
@@ -21,27 +24,26 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryMergeByDistance *data = MEM_cnew<NodeGeometryMergeByDistance>(__func__);
data->mode = GEO_NODE_MERGE_BY_DISTANCE_MODE_ALL;
node->storage = data;
}
-static PointCloud *pointcloud_merge_by_distance(const PointCloudComponent &src_points,
+static PointCloud *pointcloud_merge_by_distance(const PointCloud &src_points,
const float merge_distance,
const Field<bool> &selection_field)
{
- const int src_num = src_points.attribute_domain_size(ATTR_DOMAIN_POINT);
- GeometryComponentFieldContext context{src_points, ATTR_DOMAIN_POINT};
- FieldEvaluator evaluator{context, src_num};
+ bke::PointCloudFieldContext context{src_points};
+ FieldEvaluator evaluator{context, src_points.totpoint};
evaluator.add(selection_field);
evaluator.evaluate();
@@ -50,31 +52,28 @@ static PointCloud *pointcloud_merge_by_distance(const PointCloudComponent &src_p
return nullptr;
}
- return geometry::point_merge_by_distance(*src_points.get_for_read(), merge_distance, selection);
+ return geometry::point_merge_by_distance(src_points, merge_distance, selection);
}
-static std::optional<Mesh *> mesh_merge_by_distance_connected(const MeshComponent &mesh_component,
+static std::optional<Mesh *> mesh_merge_by_distance_connected(const Mesh &mesh,
const float merge_distance,
const Field<bool> &selection_field)
{
- const int src_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
- Array<bool> selection(src_num);
- GeometryComponentFieldContext context{mesh_component, ATTR_DOMAIN_POINT};
- FieldEvaluator evaluator{context, src_num};
+ Array<bool> selection(mesh.totvert);
+ bke::MeshFieldContext context{mesh, ATTR_DOMAIN_POINT};
+ FieldEvaluator evaluator{context, mesh.totvert};
evaluator.add_with_destination(selection_field, selection.as_mutable_span());
evaluator.evaluate();
- const Mesh &mesh = *mesh_component.get_for_read();
return geometry::mesh_merge_by_distance_connected(mesh, selection, merge_distance, false);
}
-static std::optional<Mesh *> mesh_merge_by_distance_all(const MeshComponent &mesh_component,
+static std::optional<Mesh *> mesh_merge_by_distance_all(const Mesh &mesh,
const float merge_distance,
const Field<bool> &selection_field)
{
- const int src_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
- GeometryComponentFieldContext context{mesh_component, ATTR_DOMAIN_POINT};
- FieldEvaluator evaluator{context, src_num};
+ bke::MeshFieldContext context{mesh, ATTR_DOMAIN_POINT};
+ FieldEvaluator evaluator{context, mesh.totvert};
evaluator.add(selection_field);
evaluator.evaluate();
@@ -83,7 +82,6 @@ static std::optional<Mesh *> mesh_merge_by_distance_all(const MeshComponent &mes
return std::nullopt;
}
- const Mesh &mesh = *mesh_component.get_for_read();
return geometry::mesh_merge_by_distance_all(mesh, selection, merge_distance);
}
@@ -98,22 +96,20 @@ static void node_geo_exec(GeoNodeExecParams params)
const float merge_distance = params.extract_input<float>("Distance");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (geometry_set.has_pointcloud()) {
- PointCloud *result = pointcloud_merge_by_distance(
- *geometry_set.get_component_for_read<PointCloudComponent>(), merge_distance, selection);
+ if (const PointCloud *pointcloud = geometry_set.get_pointcloud_for_read()) {
+ PointCloud *result = pointcloud_merge_by_distance(*pointcloud, merge_distance, selection);
if (result) {
geometry_set.replace_pointcloud(result);
}
}
- if (geometry_set.has_mesh()) {
- const MeshComponent &component = *geometry_set.get_component_for_read<MeshComponent>();
+ if (const Mesh *mesh = geometry_set.get_mesh_for_read()) {
std::optional<Mesh *> result;
switch (mode) {
case GEO_NODE_MERGE_BY_DISTANCE_MODE_ALL:
- result = mesh_merge_by_distance_all(component, merge_distance, selection);
+ result = mesh_merge_by_distance_all(*mesh, merge_distance, selection);
break;
case GEO_NODE_MERGE_BY_DISTANCE_MODE_CONNECTED:
- result = mesh_merge_by_distance_connected(component, merge_distance, selection);
+ result = mesh_merge_by_distance_connected(*mesh, merge_distance, selection);
break;
default:
BLI_assert_unreachable();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_face_set_boundaries.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_face_set_boundaries.cc
new file mode 100644
index 00000000000..1b9852cf7b9
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_face_set_boundaries.cc
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_mesh_face_set_boundaries_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Int>(N_("Face Set"))
+ .default_value(0)
+ .hide_value()
+ .supports_field()
+ .description(N_("An identifier for the group of each face. All contiguous faces with the "
+ "same value are in the same region"));
+ b.add_output<decl::Bool>(N_("Boundary Edges"))
+ .field_source()
+ .description(N_("The edges that lie on the boundaries between the different face sets"));
+}
+
+class BoundaryFieldInput final : public bke::MeshFieldInput {
+ private:
+ const Field<int> face_set;
+
+ public:
+ BoundaryFieldInput(const Field<int> face_set)
+ : bke::MeshFieldInput(CPPType::get<bool>(), "Boundary Field"), face_set(face_set)
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const Mesh &mesh,
+ const eAttrDomain domain,
+ const IndexMask /*mask*/) const final
+ {
+ const bke::MeshFieldContext face_context{mesh, ATTR_DOMAIN_FACE};
+ FieldEvaluator face_evaluator{face_context, mesh.totpoly};
+ face_evaluator.add(face_set);
+ face_evaluator.evaluate();
+ const VArray<int> face_set = face_evaluator.get_evaluated<int>(0);
+
+ Array<bool> boundary(mesh.totedge, false);
+ Array<bool> edge_visited(mesh.totedge, false);
+ Array<int> edge_face_set(mesh.totedge, 0);
+ const Span<MPoly> polys = mesh.polys();
+ const Span<MLoop> loops = mesh.loops();
+ for (const int i : polys.index_range()) {
+ const MPoly &poly = polys[i];
+ for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) {
+ const int edge = loop.e;
+ if (edge_visited[edge]) {
+ if (edge_face_set[edge] != face_set[i]) {
+ /* This edge is connected to two faces on different face sets. */
+ boundary[edge] = true;
+ }
+ }
+ edge_visited[edge] = true;
+ edge_face_set[edge] = face_set[i];
+ }
+ }
+ return mesh.attributes().adapt_domain<bool>(
+ VArray<bool>::ForContainer(std::move(boundary)), ATTR_DOMAIN_EDGE, domain);
+ }
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_EDGE;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const Field<int> face_set_field = params.extract_input<Field<int>>("Face Set");
+ Field<bool> face_set_boundaries{std::make_shared<BoundaryFieldInput>(face_set_field)};
+ params.set_output("Boundary Edges", std::move(face_set_boundaries));
+}
+
+} // namespace blender::nodes::node_geo_mesh_face_set_boundaries_cc
+
+void register_node_type_geo_mesh_face_set_boundaries()
+{
+ namespace file_ns = blender::nodes::node_geo_mesh_face_set_boundaries_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_MESH_FACE_SET_BOUNDARIES, "Face Set Boundaries", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
index 9e85547315c..31a3e967905 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
@@ -29,14 +29,14 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryMeshCircle *node_storage = MEM_cnew<NodeGeometryMeshCircle>(__func__);
@@ -109,13 +109,13 @@ static Mesh *create_circle_mesh(const float radius,
circle_corner_total(fill_type, verts_num),
circle_face_total(fill_type, verts_num));
BKE_id_material_eval_ensure_default_slot(&mesh->id);
- MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
- MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop};
- MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
- MutableSpan<MPoly> polys{mesh->mpoly, mesh->totpoly};
+ MutableSpan<MVert> verts = mesh->verts_for_write();
+ MutableSpan<MEdge> edges = mesh->edges_for_write();
+ MutableSpan<MPoly> polys = mesh->polys_for_write();
+ MutableSpan<MLoop> loops = mesh->loops_for_write();
/* Assign vertex coordinates. */
- const float angle_delta = 2.0f * (M_PI / static_cast<float>(verts_num));
+ const float angle_delta = 2.0f * (M_PI / float(verts_num));
for (const int i : IndexRange(verts_num)) {
const float angle = i * angle_delta;
copy_v3_v3(verts[i].co, float3(std::cos(angle) * radius, std::sin(angle) * radius, 0.0f));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
index cb79ef93de9..4a9264b8464 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
@@ -255,10 +255,10 @@ int ConeConfig::calculate_total_corners()
return corner_total;
}
-static void calculate_cone_vertices(const MutableSpan<MVert> &verts, const ConeConfig &config)
+static void calculate_cone_verts(const MutableSpan<MVert> &verts, const ConeConfig &config)
{
Array<float2> circle(config.circle_segments);
- const float angle_delta = 2.0f * (M_PI / static_cast<float>(config.circle_segments));
+ const float angle_delta = 2.0f * (M_PI / float(config.circle_segments));
float angle = 0.0f;
for (const int i : IndexRange(config.circle_segments)) {
circle[i].x = std::cos(angle);
@@ -275,8 +275,7 @@ static void calculate_cone_vertices(const MutableSpan<MVert> &verts, const ConeC
/* Top fill including the outer edge of the fill. */
if (!config.top_is_point) {
- const float top_fill_radius_delta = config.radius_top /
- static_cast<float>(config.fill_segments);
+ const float top_fill_radius_delta = config.radius_top / float(config.fill_segments);
for (const int i : IndexRange(config.fill_segments)) {
const float top_fill_radius = top_fill_radius_delta * (i + 1);
for (const int j : IndexRange(config.circle_segments)) {
@@ -289,8 +288,8 @@ static void calculate_cone_vertices(const MutableSpan<MVert> &verts, const ConeC
/* Rings along the side. */
const float side_radius_delta = (config.radius_bottom - config.radius_top) /
- static_cast<float>(config.side_segments);
- const float height_delta = 2.0f * config.height / static_cast<float>(config.side_segments);
+ float(config.side_segments);
+ const float height_delta = 2.0f * config.height / float(config.side_segments);
for (const int i : IndexRange(config.side_segments - 1)) {
const float ring_radius = config.radius_top + (side_radius_delta * (i + 1));
const float ring_height = config.height - (height_delta * (i + 1));
@@ -303,8 +302,7 @@ static void calculate_cone_vertices(const MutableSpan<MVert> &verts, const ConeC
/* Bottom fill including the outer edge of the fill. */
if (!config.bottom_is_point) {
- const float bottom_fill_radius_delta = config.radius_bottom /
- static_cast<float>(config.fill_segments);
+ const float bottom_fill_radius_delta = config.radius_bottom / float(config.fill_segments);
for (const int i : IndexRange(config.fill_segments)) {
const float bottom_fill_radius = config.radius_bottom - (i * bottom_fill_radius_delta);
for (const int j : IndexRange(config.circle_segments)) {
@@ -480,12 +478,12 @@ static void calculate_selection_outputs(Mesh *mesh,
const ConeConfig &config,
ConeAttributeOutputs &attribute_outputs)
{
- MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*mesh);
+ MutableAttributeAccessor attributes = mesh->attributes_for_write();
/* Populate "Top" selection output. */
if (attribute_outputs.top_id) {
const bool face = !config.top_is_point && config.fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE;
- SpanAttributeWriter<bool> selection = attributes.lookup_or_add_for_write_only_span<bool>(
+ SpanAttributeWriter<bool> selection = attributes.lookup_or_add_for_write_span<bool>(
attribute_outputs.top_id.get(), face ? ATTR_DOMAIN_FACE : ATTR_DOMAIN_POINT);
if (config.top_is_point) {
@@ -501,7 +499,7 @@ static void calculate_selection_outputs(Mesh *mesh,
if (attribute_outputs.bottom_id) {
const bool face = !config.bottom_is_point &&
config.fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE;
- SpanAttributeWriter<bool> selection = attributes.lookup_or_add_for_write_only_span<bool>(
+ SpanAttributeWriter<bool> selection = attributes.lookup_or_add_for_write_span<bool>(
attribute_outputs.bottom_id.get(), face ? ATTR_DOMAIN_FACE : ATTR_DOMAIN_POINT);
if (config.bottom_is_point) {
@@ -518,7 +516,7 @@ static void calculate_selection_outputs(Mesh *mesh,
/* Populate "Side" selection output. */
if (attribute_outputs.side_id) {
- SpanAttributeWriter<bool> selection = attributes.lookup_or_add_for_write_only_span<bool>(
+ SpanAttributeWriter<bool> selection = attributes.lookup_or_add_for_write_span<bool>(
attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE);
selection.span.slice(config.side_faces_start, config.side_faces_len).fill(true);
@@ -536,7 +534,7 @@ static void calculate_selection_outputs(Mesh *mesh,
*/
static void calculate_cone_uvs(Mesh *mesh, const ConeConfig &config)
{
- MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*mesh);
+ MutableAttributeAccessor attributes = mesh->attributes_for_write();
SpanAttributeWriter<float2> uv_attribute = attributes.lookup_or_add_for_write_only_span<float2>(
"uv_map", ATTR_DOMAIN_CORNER);
@@ -544,7 +542,7 @@ static void calculate_cone_uvs(Mesh *mesh, const ConeConfig &config)
Array<float2> circle(config.circle_segments);
float angle = 0.0f;
- const float angle_delta = 2.0f * M_PI / static_cast<float>(config.circle_segments);
+ const float angle_delta = 2.0f * M_PI / float(config.circle_segments);
for (const int i : IndexRange(config.circle_segments)) {
circle[i].x = std::cos(angle) * 0.225f;
circle[i].y = std::sin(angle) * 0.225f;
@@ -556,9 +554,8 @@ static void calculate_cone_uvs(Mesh *mesh, const ConeConfig &config)
/* Left circle of the UV representing the top fill or top cone tip. */
if (config.top_is_point || config.fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE) {
const float2 center_left(0.25f, 0.25f);
- const float radius_factor_delta = 1.0f / (config.top_is_point ?
- static_cast<float>(config.side_segments) :
- static_cast<float>(config.fill_segments));
+ const float radius_factor_delta = 1.0f / (config.top_is_point ? float(config.side_segments) :
+ float(config.fill_segments));
const int left_circle_segment_count = config.top_is_point ? config.side_segments :
config.fill_segments;
@@ -595,8 +592,8 @@ static void calculate_cone_uvs(Mesh *mesh, const ConeConfig &config)
if (!config.top_is_point && !config.bottom_is_point) {
/* Mesh is a truncated cone or cylinder. The sides are unwrapped into a rectangle. */
const float bottom = (config.fill_type == GEO_NODE_MESH_CIRCLE_FILL_NONE) ? 0.0f : 0.5f;
- const float x_delta = 1.0f / static_cast<float>(config.circle_segments);
- const float y_delta = (1.0f - bottom) / static_cast<float>(config.side_segments);
+ const float x_delta = 1.0f / float(config.circle_segments);
+ const float y_delta = (1.0f - bottom) / float(config.side_segments);
for (const int i : IndexRange(config.side_segments)) {
for (const int j : IndexRange(config.circle_segments)) {
@@ -612,8 +609,8 @@ static void calculate_cone_uvs(Mesh *mesh, const ConeConfig &config)
if (config.bottom_is_point || config.fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE) {
const float2 center_right(0.75f, 0.25f);
const float radius_factor_delta = 1.0f / (config.bottom_is_point ?
- static_cast<float>(config.side_segments) :
- static_cast<float>(config.fill_segments));
+ float(config.side_segments) :
+ float(config.fill_segments));
const int right_circle_segment_count = config.bottom_is_point ? config.side_segments :
config.fill_segments;
@@ -657,7 +654,7 @@ static Mesh *create_vertex_mesh()
{
/* Returns a mesh with a single vertex at the origin. */
Mesh *mesh = BKE_mesh_new_nomain(1, 0, 0, 0, 0);
- copy_v3_fl3(mesh->mvert[0].co, 0.0f, 0.0f, 0.0f);
+ copy_v3_fl3(mesh->verts_for_write().first().co, 0.0f, 0.0f, 0.0f);
return mesh;
}
@@ -679,7 +676,7 @@ Mesh *create_cylinder_or_cone_mesh(const float radius_top,
if (config.height == 0.0f) {
return create_vertex_mesh();
}
- const float z_delta = -2.0f * config.height / static_cast<float>(config.side_segments);
+ const float z_delta = -2.0f * config.height / float(config.side_segments);
const float3 start(0.0f, 0.0f, config.height);
const float3 delta(0.0f, 0.0f, z_delta);
return create_line_mesh(start, delta, config.tot_verts);
@@ -689,12 +686,12 @@ Mesh *create_cylinder_or_cone_mesh(const float radius_top,
config.tot_verts, config.tot_edges, 0, config.tot_corners, config.tot_faces);
BKE_id_material_eval_ensure_default_slot(&mesh->id);
- MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
- MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop};
- MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
- MutableSpan<MPoly> polys{mesh->mpoly, mesh->totpoly};
+ MutableSpan<MVert> verts = mesh->verts_for_write();
+ MutableSpan<MEdge> edges = mesh->edges_for_write();
+ MutableSpan<MPoly> polys = mesh->polys_for_write();
+ MutableSpan<MLoop> loops = mesh->loops_for_write();
- calculate_cone_vertices(verts, config);
+ calculate_cone_verts(verts, config);
calculate_cone_edges(edges, config);
calculate_cone_faces(loops, polys, config);
calculate_cone_uvs(mesh, config);
@@ -746,7 +743,7 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Bool>(N_("Side")).field_source();
}
-static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryMeshCone *node_storage = MEM_cnew<NodeGeometryMeshCone>(__func__);
@@ -757,7 +754,7 @@ static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
{
- bNodeSocket *vertices_socket = (bNodeSocket *)node->inputs.first;
+ bNodeSocket *vertices_socket = static_cast<bNodeSocket *>(node->inputs.first);
bNodeSocket *rings_socket = vertices_socket->next;
bNodeSocket *fill_subdiv_socket = rings_socket->next;
@@ -767,7 +764,7 @@ static void node_update(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, fill_subdiv_socket, has_fill);
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
index 301d46e586f..f192b385b1b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
@@ -48,14 +48,14 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Bool>(N_("Bottom")).field_source();
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryMeshCylinder *node_storage = MEM_cnew<NodeGeometryMeshCylinder>(__func__);
@@ -66,7 +66,7 @@ static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
{
- bNodeSocket *vertices_socket = (bNodeSocket *)node->inputs.first;
+ bNodeSocket *vertices_socket = static_cast<bNodeSocket *>(node->inputs.first);
bNodeSocket *rings_socket = vertices_socket->next;
bNodeSocket *fill_subdiv_socket = rings_socket->next;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
index 9baf0b3171e..6f0b8283b72 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
@@ -18,7 +18,7 @@ namespace blender::nodes {
static void calculate_uvs(
Mesh *mesh, Span<MVert> verts, Span<MLoop> loops, const float size_x, const float size_y)
{
- MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*mesh);
+ MutableAttributeAccessor attributes = mesh->attributes_for_write();
SpanAttributeWriter<float2> uv_attribute = attributes.lookup_or_add_for_write_only_span<float2>(
"uv_map", ATTR_DOMAIN_CORNER);
@@ -49,10 +49,10 @@ Mesh *create_grid_mesh(const int verts_x,
0,
edges_x * edges_y * 4,
edges_x * edges_y);
- MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
- MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop};
- MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
- MutableSpan<MPoly> polys{mesh->mpoly, mesh->totpoly};
+ MutableSpan<MVert> verts = mesh->verts_for_write();
+ MutableSpan<MEdge> edges = mesh->edges_for_write();
+ MutableSpan<MPoly> polys = mesh->polys_for_write();
+ MutableSpan<MLoop> loops = mesh->loops_for_write();
{
const float dx = edges_x == 0 ? 0.0f : size_x / edges_x;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
index aa9a2e9013f..8287c6a6714 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
@@ -47,7 +47,7 @@ static Mesh *create_ico_sphere_mesh(const int subdivisions, const float radius)
BMeshToMeshParams params{};
params.calc_object_remap = false;
- Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr);
+ Mesh *mesh = reinterpret_cast<Mesh *>(BKE_id_new_nomain(ID_ME, nullptr));
BKE_id_material_eval_ensure_default_slot(&mesh->id);
BM_mesh_bm_to_me(nullptr, bm, mesh, &params);
BM_mesh_free(bm);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
index a5edc6c4b3f..7faa7e23274 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
@@ -43,7 +43,7 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -53,7 +53,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
}
}
-static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryMeshLine *node_storage = MEM_cnew<NodeGeometryMeshLine>(__func__);
@@ -65,7 +65,7 @@ static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
{
- bNodeSocket *count_socket = (bNodeSocket *)node->inputs.first;
+ bNodeSocket *count_socket = static_cast<bNodeSocket *>(node->inputs.first);
bNodeSocket *resolution_socket = count_socket->next;
bNodeSocket *start_socket = resolution_socket->next;
bNodeSocket *end_and_offset_socket = start_socket->next;
@@ -97,7 +97,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
return;
}
else if (params.node_tree().typeinfo->validate_link(
- static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_FLOAT)) {
+ eNodeSocketDatatype(params.other_socket().type), SOCK_FLOAT)) {
params.add_item(IFACE_("Count"), [](LinkSearchOpParams &params) {
bNode &node = params.add_node("GeometryNodeMeshLine");
node_storage(node).mode = GEO_NODE_MESH_LINE_MODE_OFFSET;
@@ -153,7 +153,7 @@ static void node_geo_exec(GeoNodeExecParams params)
mesh = create_line_mesh(start, float3(0), count);
}
else {
- const float3 delta = total_delta / (float)(count - 1);
+ const float3 delta = total_delta / float(count - 1);
mesh = create_line_mesh(start, delta, count);
}
}
@@ -179,8 +179,8 @@ Mesh *create_line_mesh(const float3 start, const float3 delta, const int count)
Mesh *mesh = BKE_mesh_new_nomain(count, count - 1, 0, 0, 0);
BKE_id_material_eval_ensure_default_slot(&mesh->id);
- MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
- MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
+ MutableSpan<MVert> verts = mesh->verts_for_write();
+ MutableSpan<MEdge> edges = mesh->edges_for_write();
threading::parallel_invoke(
1024 < count,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
index 85facf1e758..4b43693f0f6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
@@ -254,7 +254,7 @@ BLI_NOINLINE static void calculate_sphere_corners(MutableSpan<MLoop> loops,
BLI_NOINLINE static void calculate_sphere_uvs(Mesh *mesh, const float segments, const float rings)
{
- MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*mesh);
+ MutableAttributeAccessor attributes = mesh->attributes_for_write();
SpanAttributeWriter<float2> uv_attribute = attributes.lookup_or_add_for_write_only_span<float2>(
"uv_map", ATTR_DOMAIN_CORNER);
@@ -266,16 +266,16 @@ BLI_NOINLINE static void calculate_sphere_uvs(Mesh *mesh, const float segments,
const float segments_inv = 1.0f / segments;
for (const int i_segment : IndexRange(segments)) {
- const float segment = static_cast<float>(i_segment);
+ const float segment = float(i_segment);
uvs[loop_index++] = float2((segment + 0.5f) * segments_inv, 0.0f);
uvs[loop_index++] = float2(segment * segments_inv, dy);
uvs[loop_index++] = float2((segment + 1.0f) * segments_inv, dy);
}
for (const int i_ring : IndexRange(1, rings - 2)) {
- const float ring = static_cast<float>(i_ring);
+ const float ring = float(i_ring);
for (const int i_segment : IndexRange(segments)) {
- const float segment = static_cast<float>(i_segment);
+ const float segment = float(i_segment);
uvs[loop_index++] = float2(segment * segments_inv, ring / rings);
uvs[loop_index++] = float2(segment * segments_inv, (ring + 1.0f) / rings);
uvs[loop_index++] = float2((segment + 1.0f) * segments_inv, (ring + 1.0f) / rings);
@@ -284,7 +284,7 @@ BLI_NOINLINE static void calculate_sphere_uvs(Mesh *mesh, const float segments,
}
for (const int i_segment : IndexRange(segments)) {
- const float segment = static_cast<float>(i_segment);
+ const float segment = float(i_segment);
uvs[loop_index++] = float2((segment + 0.5f) * segments_inv, 1.0f);
uvs[loop_index++] = float2((segment + 1.0f) * segments_inv, 1.0f - dy);
uvs[loop_index++] = float2(segment * segments_inv, 1.0f - dy);
@@ -301,15 +301,16 @@ static Mesh *create_uv_sphere_mesh(const float radius, const int segments, const
sphere_corner_total(segments, rings),
sphere_face_total(segments, rings));
BKE_id_material_eval_ensure_default_slot(&mesh->id);
- MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
- MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop};
- MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
- MutableSpan<MPoly> polys{mesh->mpoly, mesh->totpoly};
+ MutableSpan<MVert> verts = mesh->verts_for_write();
+ MutableSpan<MEdge> edges = mesh->edges_for_write();
+ MutableSpan<MPoly> polys = mesh->polys_for_write();
+ MutableSpan<MLoop> loops = mesh->loops_for_write();
threading::parallel_invoke(
1024 < segments * rings,
[&]() {
- MutableSpan vert_normals{(float3 *)BKE_mesh_vertex_normals_for_write(mesh), mesh->totvert};
+ MutableSpan vert_normals{
+ reinterpret_cast<float3 *>(BKE_mesh_vertex_normals_for_write(mesh)), mesh->totvert};
calculate_sphere_vertex_data(verts, vert_normals, radius, segments, rings);
BKE_mesh_vertex_normals_clear_dirty(mesh);
},
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
index 40169def51e..4d08fa40a29 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
@@ -1,5 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "DNA_mesh_types.h"
+
#include "GEO_mesh_to_curve.hh"
#include "node_geometry_util.hh"
@@ -24,9 +26,8 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
- const MeshComponent &component = *geometry_set.get_component_for_read<MeshComponent>();
- GeometryComponentFieldContext context{component, ATTR_DOMAIN_EDGE};
- fn::FieldEvaluator evaluator{context, component.attribute_domain_size(ATTR_DOMAIN_EDGE)};
+ bke::MeshFieldContext context{*mesh, ATTR_DOMAIN_EDGE};
+ fn::FieldEvaluator evaluator{context, mesh->totedge};
evaluator.add(params.get_input<Field<bool>>("Selection"));
evaluator.evaluate();
const IndexMask selection = evaluator.get_evaluated_as_mask(0);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
index d3d1312be6d..d97a0e72060 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
@@ -1,7 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "BLI_array_utils.hh"
#include "BLI_task.hh"
+#include "DNA_mesh_types.h"
#include "DNA_pointcloud_types.h"
#include "BKE_attribute_math.hh"
@@ -22,7 +24,7 @@ static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value();
- b.add_input<decl::Vector>(N_("Position")).implicit_field();
+ b.add_input<decl::Vector>(N_("Position")).implicit_field(implicit_field_inputs::position);
b.add_input<decl::Float>(N_("Radius"))
.default_value(0.05f)
.min(0.0f)
@@ -31,47 +33,36 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Points"));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryMeshToPoints *data = MEM_cnew<NodeGeometryMeshToPoints>(__func__);
data->mode = GEO_NODE_MESH_TO_POINTS_VERTICES;
node->storage = data;
}
-static void materialize_compressed_to_uninitialized_threaded(const GVArray &src,
- const IndexMask mask,
- GMutableSpan dst)
-{
- BLI_assert(src.type() == dst.type());
- BLI_assert(mask.size() == dst.size());
- threading::parallel_for(mask.index_range(), 4096, [&](IndexRange range) {
- src.materialize_compressed_to_uninitialized(mask.slice(range), dst.slice(range).data());
- });
-}
-
static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
Field<float3> &position_field,
Field<float> &radius_field,
Field<bool> &selection_field,
const eAttrDomain domain)
{
- const MeshComponent *mesh_component = geometry_set.get_component_for_read<MeshComponent>();
- if (mesh_component == nullptr) {
+ const Mesh *mesh = geometry_set.get_mesh_for_read();
+ if (mesh == nullptr) {
geometry_set.remove_geometry_during_modify();
return;
}
- GeometryComponentFieldContext field_context{*mesh_component, domain};
- const int domain_num = mesh_component->attribute_domain_size(domain);
- if (domain_num == 0) {
+ const int domain_size = mesh->attributes().domain_size(domain);
+ if (domain_size == 0) {
geometry_set.remove_geometry_during_modify();
return;
}
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ bke::MeshFieldContext field_context{*mesh, domain};
+ fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.set_selection(selection_field);
/* Evaluating directly into the point cloud doesn't work because we are not using the full
* "min_array_size" array but compressing the selected elements into the final array with no
@@ -83,19 +74,16 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
PointCloud *pointcloud = BKE_pointcloud_new_nomain(selection.size());
geometry_set.replace_pointcloud(pointcloud);
- MutableAttributeAccessor pointcloud_attributes = bke::pointcloud_attributes_for_write(
- *pointcloud);
+ MutableAttributeAccessor dst_attributes = pointcloud->attributes_for_write();
- GSpanAttributeWriter position = pointcloud_attributes.lookup_or_add_for_write_only_span(
+ GSpanAttributeWriter position = dst_attributes.lookup_or_add_for_write_only_span(
"position", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
- materialize_compressed_to_uninitialized_threaded(
- evaluator.get_evaluated(0), selection, position.span);
+ array_utils::gather(evaluator.get_evaluated(0), selection, position.span);
position.finish();
- GSpanAttributeWriter radius = pointcloud_attributes.lookup_or_add_for_write_only_span(
+ GSpanAttributeWriter radius = dst_attributes.lookup_or_add_for_write_only_span(
"radius", ATTR_DOMAIN_POINT, CD_PROP_FLOAT);
- materialize_compressed_to_uninitialized_threaded(
- evaluator.get_evaluated(1), selection, radius.span);
+ array_utils::gather(evaluator.get_evaluated(1), selection, radius.span);
radius.finish();
Map<AttributeIDRef, AttributeKind> attributes;
@@ -103,14 +91,16 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
{GEO_COMPONENT_TYPE_MESH}, GEO_COMPONENT_TYPE_POINT_CLOUD, false, attributes);
attributes.remove("position");
+ const AttributeAccessor src_attributes = mesh->attributes();
+
for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
const AttributeIDRef attribute_id = entry.key;
const eCustomDataType data_type = entry.value.data_type;
- GVArray src = mesh_component->attributes()->lookup_or_default(attribute_id, domain, data_type);
- GSpanAttributeWriter dst = pointcloud_attributes.lookup_or_add_for_write_only_span(
+ GVArray src = src_attributes.lookup_or_default(attribute_id, domain, data_type);
+ GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span(
attribute_id, ATTR_DOMAIN_POINT, data_type);
if (dst && src) {
- materialize_compressed_to_uninitialized_threaded(src, selection, dst.span);
+ array_utils::gather(src, selection, dst.span);
dst.finish();
}
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_volume.cc
index 92814a8bc5e..8885903f828 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_volume.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_volume.cc
@@ -50,33 +50,31 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Volume"));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "resolution_mode", 0, IFACE_("Resolution"), ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
- NodeGeometryMeshToVolume *data = (NodeGeometryMeshToVolume *)MEM_callocN(
- sizeof(NodeGeometryMeshToVolume), __func__);
+ NodeGeometryMeshToVolume *data = MEM_cnew<NodeGeometryMeshToVolume>(__func__);
data->resolution_mode = MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT;
node->storage = data;
}
static void node_update(bNodeTree *ntree, bNode *node)
{
- NodeGeometryMeshToVolume *data = (NodeGeometryMeshToVolume *)node->storage;
+ NodeGeometryMeshToVolume &data = node_storage(*node);
bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size");
bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount");
nodeSetSocketAvailability(ntree,
voxel_amount_socket,
- data->resolution_mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT);
- nodeSetSocketAvailability(ntree,
- voxel_size_socket,
- data->resolution_mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE);
+ data.resolution_mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT);
+ nodeSetSocketAvailability(
+ ntree, voxel_size_socket, data.resolution_mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE);
}
#ifdef WITH_OPENVDB
@@ -126,7 +124,7 @@ static Volume *create_volume_from_mesh(const Mesh &mesh, GeoNodeExecParams &para
exterior_band_width,
mesh_to_volume_space_transform);
- Volume *volume = (Volume *)BKE_id_new_nomain(ID_VO, nullptr);
+ Volume *volume = reinterpret_cast<Volume *>(BKE_id_new_nomain(ID_VO, nullptr));
BKE_volume_init_grids(volume);
/* Convert mesh to grid and add to volume. */
@@ -149,7 +147,6 @@ static void node_geo_exec(GeoNodeExecParams params)
{
#ifdef WITH_OPENVDB
GeometrySet geometry_set(params.extract_input<GeometrySet>("Mesh"));
-
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
if (geometry_set.has_mesh()) {
Volume *volume = create_volume_from_mesh(*geometry_set.get_mesh_for_read(), params);
@@ -159,9 +156,9 @@ static void node_geo_exec(GeoNodeExecParams params)
});
params.set_output("Volume", std::move(geometry_set));
#else
+ params.set_default_remaining_outputs();
params.error_message_add(NodeWarningType::Error,
TIP_("Disabled, Blender was compiled without OpenVDB"));
- params.set_default_remaining_outputs();
return;
#endif
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_face.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_face.cc
new file mode 100644
index 00000000000..94bca02640b
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_face.cc
@@ -0,0 +1,189 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BLI_task.hh"
+
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_mesh_topology_corners_of_face_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Int>(N_("Face Index"))
+ .implicit_field(implicit_field_inputs::index)
+ .description(N_("The face to retrieve data from. Defaults to the face from the context"));
+ b.add_input<decl::Float>(N_("Weights"))
+ .supports_field()
+ .hide_value()
+ .description(N_("Values used to sort the face's corners. Uses indices by default"));
+ b.add_input<decl::Int>(N_("Sort Index"))
+ .min(0)
+ .supports_field()
+ .description(N_("Which of the sorted corners to output"));
+ b.add_output<decl::Int>(N_("Corner Index"))
+ .dependent_field()
+ .description(N_("A corner of the face, chosen by the sort index"));
+ b.add_output<decl::Int>(N_("Total"))
+ .dependent_field()
+ .description(N_("The number of corners in the face"));
+}
+
+class CornersOfFaceInput final : public bke::MeshFieldInput {
+ const Field<int> face_index_;
+ const Field<int> sort_index_;
+ const Field<float> sort_weight_;
+
+ public:
+ CornersOfFaceInput(Field<int> face_index, Field<int> sort_index, Field<float> sort_weight)
+ : bke::MeshFieldInput(CPPType::get<int>(), "Corner of Face"),
+ face_index_(std::move(face_index)),
+ sort_index_(std::move(sort_index)),
+ sort_weight_(std::move(sort_weight))
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const Mesh &mesh,
+ const eAttrDomain domain,
+ const IndexMask mask) const final
+ {
+ const Span<MPoly> polys = mesh.polys();
+
+ const bke::MeshFieldContext context{mesh, domain};
+ fn::FieldEvaluator evaluator{context, &mask};
+ evaluator.add(face_index_);
+ evaluator.add(sort_index_);
+ evaluator.evaluate();
+ const VArray<int> face_indices = evaluator.get_evaluated<int>(0);
+ const VArray<int> indices_in_sort = evaluator.get_evaluated<int>(1);
+
+ const bke::MeshFieldContext corner_context{mesh, ATTR_DOMAIN_CORNER};
+ fn::FieldEvaluator corner_evaluator{corner_context, mesh.totloop};
+ corner_evaluator.add(sort_weight_);
+ corner_evaluator.evaluate();
+ const VArray<float> all_sort_weights = corner_evaluator.get_evaluated<float>(0);
+
+ Array<int> corner_of_face(mask.min_array_size());
+ threading::parallel_for(mask.index_range(), 1024, [&](const IndexRange range) {
+ /* Reuse arrays to avoid allocation. */
+ Array<float> sort_weights;
+ Array<int> sort_indices;
+
+ for (const int selection_i : mask.slice(range)) {
+ const int poly_i = face_indices[selection_i];
+ const int index_in_sort = indices_in_sort[selection_i];
+ if (!polys.index_range().contains(poly_i)) {
+ corner_of_face[selection_i] = 0;
+ continue;
+ }
+
+ const MPoly &poly = polys[poly_i];
+ const IndexRange corners(poly.loopstart, poly.totloop);
+
+ /* Retrieve the weights for each corner. */
+ sort_weights.reinitialize(corners.size());
+ all_sort_weights.materialize_compressed(IndexMask(corners),
+ sort_weights.as_mutable_span());
+
+ /* Sort a separate array of compressed indices corresponding to the compressed weights.
+ * This allows using `materialize_compressed` to avoid virtual function call overhead
+ * when accessing values in the sort weights. However, it means a separate array of
+ * indices within the compressed array is necessary for sorting. */
+ sort_indices.reinitialize(corners.size());
+ std::iota(sort_indices.begin(), sort_indices.end(), 0);
+ std::stable_sort(sort_indices.begin(), sort_indices.end(), [&](int a, int b) {
+ return sort_weights[a] < sort_weights[b];
+ });
+
+ const int index_in_sort_wrapped = mod_i(index_in_sort, corners.size());
+ corner_of_face[selection_i] = corners[sort_indices[index_in_sort_wrapped]];
+ }
+ });
+
+ return VArray<int>::ForContainer(std::move(corner_of_face));
+ }
+
+ uint64_t hash() const final
+ {
+ return 6927982716657;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const final
+ {
+ if (const auto *typed = dynamic_cast<const CornersOfFaceInput *>(&other)) {
+ return typed->face_index_ == face_index_ && typed->sort_index_ == sort_index_ &&
+ typed->sort_weight_ == sort_weight_;
+ }
+ return false;
+ }
+};
+
+static int get_poly_totloop(const MPoly &poly)
+{
+ return poly.totloop;
+}
+
+class CornersOfFaceCountInput final : public bke::MeshFieldInput {
+ public:
+ CornersOfFaceCountInput() : bke::MeshFieldInput(CPPType::get<int>(), "Face Corner Count")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const Mesh &mesh,
+ const eAttrDomain domain,
+ const IndexMask /*mask*/) const final
+ {
+ if (domain != ATTR_DOMAIN_FACE) {
+ return {};
+ }
+ return VArray<int>::ForDerivedSpan<MPoly, get_poly_totloop>(mesh.polys());
+ }
+
+ uint64_t hash() const final
+ {
+ return 8345908765432698;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const final
+ {
+ if (dynamic_cast<const CornersOfFaceCountInput *>(&other)) {
+ return true;
+ }
+ return false;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const Field<int> face_index = params.extract_input<Field<int>>("Face Index");
+ if (params.output_is_required("Total")) {
+ params.set_output("Total",
+ Field<int>(std::make_shared<FieldAtIndexInput>(
+ face_index,
+ Field<int>(std::make_shared<CornersOfFaceCountInput>()),
+ ATTR_DOMAIN_FACE)));
+ }
+ if (params.output_is_required("Corner Index")) {
+ params.set_output("Corner Index",
+ Field<int>(std::make_shared<CornersOfFaceInput>(
+ face_index,
+ params.extract_input<Field<int>>("Sort Index"),
+ params.extract_input<Field<float>>("Weights"))));
+ }
+}
+
+} // namespace blender::nodes::node_geo_mesh_topology_corners_of_face_cc
+
+void register_node_type_geo_mesh_topology_corners_of_face()
+{
+ namespace file_ns = blender::nodes::node_geo_mesh_topology_corners_of_face_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_MESH_TOPOLOGY_CORNERS_OF_FACE, "Corners of Face", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc
new file mode 100644
index 00000000000..036af2d3b93
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc
@@ -0,0 +1,209 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+
+#include "BLI_task.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_mesh_topology_corners_of_vertex_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Int>(N_("Vertex Index"))
+ .implicit_field(implicit_field_inputs::index)
+ .description(
+ N_("The vertex to retrieve data from. Defaults to the vertex from the context"));
+ b.add_input<decl::Float>(N_("Weights"))
+ .supports_field()
+ .hide_value()
+ .description(
+ N_("Values used to sort corners attached to the vertex. Uses indices by default"));
+ b.add_input<decl::Int>(N_("Sort Index"))
+ .min(0)
+ .supports_field()
+ .description(N_("Which of the sorted corners to output"));
+ b.add_output<decl::Int>(N_("Corner Index"))
+ .dependent_field()
+ .description(N_("A corner connected to the face, chosen by the sort index"));
+ b.add_output<decl::Int>(N_("Total"))
+ .dependent_field()
+ .description(N_("The number of faces or corners connected to each vertex"));
+}
+
+static void convert_span(const Span<int> src, MutableSpan<int64_t> dst)
+{
+ for (const int i : src.index_range()) {
+ dst[i] = src[i];
+ }
+}
+
+class CornersOfVertInput final : public bke::MeshFieldInput {
+ const Field<int> vert_index_;
+ const Field<int> sort_index_;
+ const Field<float> sort_weight_;
+
+ public:
+ CornersOfVertInput(Field<int> vert_index, Field<int> sort_index, Field<float> sort_weight)
+ : bke::MeshFieldInput(CPPType::get<int>(), "Corner of Vertex"),
+ vert_index_(std::move(vert_index)),
+ sort_index_(std::move(sort_index)),
+ sort_weight_(std::move(sort_weight))
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const Mesh &mesh,
+ const eAttrDomain domain,
+ const IndexMask mask) const final
+ {
+ const IndexRange vert_range(mesh.totvert);
+ const Span<MLoop> loops = mesh.loops();
+ Array<Vector<int>> vert_to_loop_map = bke::mesh_topology::build_vert_to_loop_map(loops,
+ mesh.totvert);
+
+ const bke::MeshFieldContext context{mesh, domain};
+ fn::FieldEvaluator evaluator{context, &mask};
+ evaluator.add(vert_index_);
+ evaluator.add(sort_index_);
+ evaluator.evaluate();
+ const VArray<int> vert_indices = evaluator.get_evaluated<int>(0);
+ const VArray<int> indices_in_sort = evaluator.get_evaluated<int>(1);
+
+ const bke::MeshFieldContext corner_context{mesh, ATTR_DOMAIN_CORNER};
+ fn::FieldEvaluator corner_evaluator{corner_context, loops.size()};
+ corner_evaluator.add(sort_weight_);
+ corner_evaluator.evaluate();
+ const VArray<float> all_sort_weights = corner_evaluator.get_evaluated<float>(0);
+
+ Array<int> corner_of_vertex(mask.min_array_size());
+ threading::parallel_for(mask.index_range(), 1024, [&](const IndexRange range) {
+ /* Reuse arrays to avoid allocation. */
+ Array<int64_t> corner_indices;
+ Array<float> sort_weights;
+ Array<int> sort_indices;
+
+ for (const int selection_i : mask.slice(range)) {
+ const int vert_i = vert_indices[selection_i];
+ const int index_in_sort = indices_in_sort[selection_i];
+ if (!vert_range.contains(vert_i)) {
+ corner_of_vertex[selection_i] = 0;
+ continue;
+ }
+
+ const Span<int> corners = vert_to_loop_map[vert_i];
+ if (corners.is_empty()) {
+ corner_of_vertex[selection_i] = 0;
+ continue;
+ }
+
+ /* Retrieve the connected edge indices as 64 bit integers for #materialize_compressed. */
+ corner_indices.reinitialize(corners.size());
+ convert_span(corners, corner_indices);
+
+ /* Retrieve a compressed array of weights for each edge. */
+ sort_weights.reinitialize(corners.size());
+ all_sort_weights.materialize_compressed(IndexMask(corner_indices),
+ sort_weights.as_mutable_span());
+
+ /* Sort a separate array of compressed indices corresponding to the compressed weights.
+ * This allows using `materialize_compressed` to avoid virtual function call overhead
+ * when accessing values in the sort weights. However, it means a separate array of
+ * indices within the compressed array is necessary for sorting. */
+ sort_indices.reinitialize(corners.size());
+ std::iota(sort_indices.begin(), sort_indices.end(), 0);
+ std::stable_sort(sort_indices.begin(), sort_indices.end(), [&](int a, int b) {
+ return sort_weights[a] < sort_weights[b];
+ });
+
+ const int index_in_sort_wrapped = mod_i(index_in_sort, corners.size());
+ corner_of_vertex[selection_i] = corner_indices[sort_indices[index_in_sort_wrapped]];
+ }
+ });
+
+ return VArray<int>::ForContainer(std::move(corner_of_vertex));
+ }
+
+ uint64_t hash() const final
+ {
+ return 3541871368173645;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const final
+ {
+ if (const auto *typed = dynamic_cast<const CornersOfVertInput *>(&other)) {
+ return typed->vert_index_ == vert_index_ && typed->sort_index_ == sort_index_ &&
+ typed->sort_weight_ == sort_weight_;
+ }
+ return false;
+ }
+};
+
+class CornersOfVertCountInput final : public bke::MeshFieldInput {
+ public:
+ CornersOfVertCountInput() : bke::MeshFieldInput(CPPType::get<int>(), "Vertex Corner Count")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const Mesh &mesh,
+ const eAttrDomain domain,
+ const IndexMask /*mask*/) const final
+ {
+ if (domain != ATTR_DOMAIN_POINT) {
+ return {};
+ }
+ const Span<MLoop> loops = mesh.loops();
+ Array<int> counts(mesh.totvert, 0);
+ for (const int i : loops.index_range()) {
+ counts[loops[i].v]++;
+ }
+ return VArray<int>::ForContainer(std::move(counts));
+ }
+
+ uint64_t hash() const final
+ {
+ return 253098745374645;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const final
+ {
+ if (dynamic_cast<const CornersOfVertCountInput *>(&other)) {
+ return true;
+ }
+ return false;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const Field<int> vert_index = params.extract_input<Field<int>>("Vertex Index");
+ if (params.output_is_required("Total")) {
+ params.set_output("Total",
+ Field<int>(std::make_shared<FieldAtIndexInput>(
+ vert_index,
+ Field<int>(std::make_shared<CornersOfVertCountInput>()),
+ ATTR_DOMAIN_POINT)));
+ }
+ if (params.output_is_required("Corner Index")) {
+ params.set_output("Corner Index",
+ Field<int>(std::make_shared<CornersOfVertInput>(
+ vert_index,
+ params.extract_input<Field<int>>("Sort Index"),
+ params.extract_input<Field<float>>("Weights"))));
+ }
+}
+} // namespace blender::nodes::node_geo_mesh_topology_corners_of_vertex_cc
+
+void register_node_type_geo_mesh_topology_corners_of_vertex()
+{
+ namespace file_ns = blender::nodes::node_geo_mesh_topology_corners_of_vertex_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_MESH_TOPOLOGY_CORNERS_OF_VERTEX, "Corners of Vertex", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc
new file mode 100644
index 00000000000..84b560cb48a
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc
@@ -0,0 +1,136 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+
+#include "BLI_task.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_mesh_topology_edges_of_corner_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Int>(N_("Corner Index"))
+ .implicit_field(implicit_field_inputs::index)
+ .description(
+ N_("The corner to retrieve data from. Defaults to the corner from the context"));
+ b.add_output<decl::Int>(N_("Next Edge Index"))
+ .dependent_field()
+ .description(
+ N_("The edge after the corner in the face, in the direction of increasing indices"));
+ b.add_output<decl::Int>(N_("Previous Edge Index"))
+ .dependent_field()
+ .description(
+ N_("The edge before the corner in the face, in the direction of decreasing indices"));
+}
+
+static int get_loop_edge(const MLoop &loop)
+{
+ return loop.e;
+}
+
+class CornerNextEdgeFieldInput final : public bke::MeshFieldInput {
+ public:
+ CornerNextEdgeFieldInput() : bke::MeshFieldInput(CPPType::get<int>(), "Corner Next Edge")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const Mesh &mesh,
+ const eAttrDomain domain,
+ const IndexMask /*mask*/) const final
+ {
+ if (domain != ATTR_DOMAIN_CORNER) {
+ return {};
+ }
+ return VArray<int>::ForDerivedSpan<MLoop, get_loop_edge>(mesh.loops());
+ }
+
+ uint64_t hash() const final
+ {
+ return 1892753404495;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const final
+ {
+ if (dynamic_cast<const CornerNextEdgeFieldInput *>(&other)) {
+ return true;
+ }
+ return false;
+ }
+};
+
+class CornerPreviousEdgeFieldInput final : public bke::MeshFieldInput {
+ public:
+ CornerPreviousEdgeFieldInput() : bke::MeshFieldInput(CPPType::get<int>(), "Corner Previous Edge")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const Mesh &mesh,
+ const eAttrDomain domain,
+ const IndexMask /*mask*/) const final
+ {
+ if (domain != ATTR_DOMAIN_CORNER) {
+ return {};
+ }
+ const Span<MPoly> polys = mesh.polys();
+ const Span<MLoop> loops = mesh.loops();
+ Array<int> loop_to_poly_map = bke::mesh_topology::build_loop_to_poly_map(polys, mesh.totloop);
+ return VArray<int>::ForFunc(
+ mesh.totloop,
+ [polys, loops, loop_to_poly_map = std::move(loop_to_poly_map)](const int corner_i) {
+ const int poly_i = loop_to_poly_map[corner_i];
+ const MPoly &poly = polys[poly_i];
+ const int corner_i_prev = bke::mesh_topology::previous_poly_loop(poly, corner_i);
+ return loops[corner_i_prev].e;
+ });
+ }
+
+ uint64_t hash() const final
+ {
+ return 987298345762465;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const final
+ {
+ if (dynamic_cast<const CornerPreviousEdgeFieldInput *>(&other)) {
+ return true;
+ }
+ return false;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const Field<int> corner_index = params.extract_input<Field<int>>("Corner Index");
+ if (params.output_is_required("Next Edge Index")) {
+ params.set_output("Next Edge Index",
+ Field<int>(std::make_shared<FieldAtIndexInput>(
+ corner_index,
+ Field<int>(std::make_shared<CornerNextEdgeFieldInput>()),
+ ATTR_DOMAIN_CORNER)));
+ }
+ if (params.output_is_required("Previous Edge Index")) {
+ params.set_output("Previous Edge Index",
+ Field<int>(std::make_shared<FieldAtIndexInput>(
+ corner_index,
+ Field<int>(std::make_shared<CornerPreviousEdgeFieldInput>()),
+ ATTR_DOMAIN_CORNER)));
+ }
+}
+
+} // namespace blender::nodes::node_geo_mesh_topology_edges_of_corner_cc
+
+void register_node_type_geo_mesh_topology_edges_of_corner()
+{
+ namespace file_ns = blender::nodes::node_geo_mesh_topology_edges_of_corner_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_MESH_TOPOLOGY_EDGES_OF_CORNER, "Edges of Corner", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc
new file mode 100644
index 00000000000..f0cc191e217
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc
@@ -0,0 +1,211 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+
+#include "BLI_task.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_mesh_topology_edges_of_vertex_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Int>(N_("Vertex Index"))
+ .implicit_field(implicit_field_inputs::index)
+ .description(
+ N_("The vertex to retrieve data from. Defaults to the vertex from the context"));
+ b.add_input<decl::Float>(N_("Weights"))
+ .supports_field()
+ .hide_value()
+ .description(
+ N_("Values used to sort the edges connected to the vertex. Uses indices by default"));
+ b.add_input<decl::Int>(N_("Sort Index"))
+ .min(0)
+ .supports_field()
+ .description(N_("Which of the sorted edges to output"));
+ b.add_output<decl::Int>(N_("Edge Index"))
+ .dependent_field()
+ .description(N_("An edge connected to the face, chosen by the sort index"));
+ b.add_output<decl::Int>(N_("Total"))
+ .dependent_field()
+ .description(N_("The number of edges connected to each vertex"));
+}
+
+static void convert_span(const Span<int> src, MutableSpan<int64_t> dst)
+{
+ for (const int i : src.index_range()) {
+ dst[i] = src[i];
+ }
+}
+
+class EdgesOfVertInput final : public bke::MeshFieldInput {
+ const Field<int> vert_index_;
+ const Field<int> sort_index_;
+ const Field<float> sort_weight_;
+
+ public:
+ EdgesOfVertInput(Field<int> vert_index, Field<int> sort_index, Field<float> sort_weight)
+ : bke::MeshFieldInput(CPPType::get<int>(), "Edge of Vertex"),
+ vert_index_(std::move(vert_index)),
+ sort_index_(std::move(sort_index)),
+ sort_weight_(std::move(sort_weight))
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const Mesh &mesh,
+ const eAttrDomain domain,
+ const IndexMask mask) const final
+ {
+ const IndexRange vert_range(mesh.totvert);
+ const Span<MEdge> edges = mesh.edges();
+ Array<Vector<int>> vert_to_edge_map = bke::mesh_topology::build_vert_to_edge_map(edges,
+ mesh.totvert);
+
+ const bke::MeshFieldContext context{mesh, domain};
+ fn::FieldEvaluator evaluator{context, &mask};
+ evaluator.add(vert_index_);
+ evaluator.add(sort_index_);
+ evaluator.evaluate();
+ const VArray<int> vert_indices = evaluator.get_evaluated<int>(0);
+ const VArray<int> indices_in_sort = evaluator.get_evaluated<int>(1);
+
+ const bke::MeshFieldContext edge_context{mesh, ATTR_DOMAIN_EDGE};
+ fn::FieldEvaluator edge_evaluator{edge_context, mesh.totedge};
+ edge_evaluator.add(sort_weight_);
+ edge_evaluator.evaluate();
+ const VArray<float> all_sort_weights = edge_evaluator.get_evaluated<float>(0);
+
+ Array<int> edge_of_vertex(mask.min_array_size());
+ threading::parallel_for(mask.index_range(), 1024, [&](const IndexRange range) {
+ /* Reuse arrays to avoid allocation. */
+ Array<int64_t> edge_indices;
+ Array<float> sort_weights;
+ Array<int> sort_indices;
+
+ for (const int selection_i : mask.slice(range)) {
+ const int vert_i = vert_indices[selection_i];
+ const int index_in_sort = indices_in_sort[selection_i];
+ if (!vert_range.contains(vert_i)) {
+ edge_of_vertex[selection_i] = 0;
+ continue;
+ }
+
+ const Span<int> edges = vert_to_edge_map[vert_i];
+ if (edges.is_empty()) {
+ edge_of_vertex[selection_i] = 0;
+ continue;
+ }
+
+ /* Retrieve the connected edge indices as 64 bit integers for #materialize_compressed. */
+ edge_indices.reinitialize(edges.size());
+ convert_span(edges, edge_indices);
+
+ /* Retrieve a compressed array of weights for each edge. */
+ sort_weights.reinitialize(edges.size());
+ all_sort_weights.materialize_compressed(IndexMask(edge_indices),
+ sort_weights.as_mutable_span());
+
+ /* Sort a separate array of compressed indices corresponding to the compressed weights.
+ * This allows using `materialize_compressed` to avoid virtual function call overhead
+ * when accessing values in the sort weights. However, it means a separate array of
+ * indices within the compressed array is necessary for sorting. */
+ sort_indices.reinitialize(edges.size());
+ std::iota(sort_indices.begin(), sort_indices.end(), 0);
+ std::stable_sort(sort_indices.begin(), sort_indices.end(), [&](int a, int b) {
+ return sort_weights[a] < sort_weights[b];
+ });
+
+ const int index_in_sort_wrapped = mod_i(index_in_sort, edges.size());
+ edge_of_vertex[selection_i] = edge_indices[sort_indices[index_in_sort_wrapped]];
+ }
+ });
+
+ return VArray<int>::ForContainer(std::move(edge_of_vertex));
+ }
+
+ uint64_t hash() const final
+ {
+ return 98762349875636;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const final
+ {
+ if (const auto *typed = dynamic_cast<const EdgesOfVertInput *>(&other)) {
+ return typed->vert_index_ == vert_index_ && typed->sort_index_ == sort_index_ &&
+ typed->sort_weight_ == sort_weight_;
+ }
+ return false;
+ }
+};
+
+class EdgesOfVertCountInput final : public bke::MeshFieldInput {
+ public:
+ EdgesOfVertCountInput() : bke::MeshFieldInput(CPPType::get<int>(), "Corner Face Index")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const Mesh &mesh,
+ const eAttrDomain domain,
+ const IndexMask /*mask*/) const final
+ {
+ if (domain != ATTR_DOMAIN_POINT) {
+ return {};
+ }
+ const Span<MEdge> edges = mesh.edges();
+ Array<int> counts(mesh.totvert, 0);
+ for (const int i : edges.index_range()) {
+ counts[edges[i].v1]++;
+ counts[edges[i].v2]++;
+ }
+ return VArray<int>::ForContainer(std::move(counts));
+ }
+
+ uint64_t hash() const final
+ {
+ return 436758278618374;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const final
+ {
+ if (dynamic_cast<const EdgesOfVertCountInput *>(&other)) {
+ return true;
+ }
+ return false;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const Field<int> vert_index = params.extract_input<Field<int>>("Vertex Index");
+ if (params.output_is_required("Total")) {
+ params.set_output("Total",
+ Field<int>(std::make_shared<FieldAtIndexInput>(
+ vert_index,
+ Field<int>(std::make_shared<EdgesOfVertCountInput>()),
+ ATTR_DOMAIN_POINT)));
+ }
+ if (params.output_is_required("Edge Index")) {
+ params.set_output("Edge Index",
+ Field<int>(std::make_shared<EdgesOfVertInput>(
+ vert_index,
+ params.extract_input<Field<int>>("Sort Index"),
+ params.extract_input<Field<float>>("Weights"))));
+ }
+}
+
+} // namespace blender::nodes::node_geo_mesh_topology_edges_of_vertex_cc
+
+void register_node_type_geo_mesh_topology_edges_of_vertex()
+{
+ namespace file_ns = blender::nodes::node_geo_mesh_topology_edges_of_vertex_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_MESH_TOPOLOGY_EDGES_OF_VERTEX, "Edges of Vertex", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_face_of_corner.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_face_of_corner.cc
new file mode 100644
index 00000000000..d9f944ca11e
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_face_of_corner.cc
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_mesh_topology_face_of_corner_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Int>(N_("Corner Index"))
+ .implicit_field(implicit_field_inputs::index)
+ .description(
+ N_("The corner to retrieve data from. Defaults to the corner from the context"));
+ b.add_output<decl::Int>(N_("Face Index"))
+ .dependent_field()
+ .description(N_("The index of the face the corner is a part of"));
+ b.add_output<decl::Int>(N_("Index in Face"))
+ .dependent_field()
+ .description(N_("The index of the corner starting from the first corner in the face"));
+}
+
+class CornerFaceIndexInput final : public bke::MeshFieldInput {
+ public:
+ CornerFaceIndexInput() : bke::MeshFieldInput(CPPType::get<int>(), "Corner Face Index")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const Mesh &mesh,
+ const eAttrDomain domain,
+ const IndexMask /*mask*/) const final
+ {
+ if (domain != ATTR_DOMAIN_CORNER) {
+ return {};
+ }
+ return VArray<int>::ForContainer(
+ bke::mesh_topology::build_loop_to_poly_map(mesh.polys(), mesh.totloop));
+ }
+
+ uint64_t hash() const final
+ {
+ return 2348712958475728;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const final
+ {
+ return dynamic_cast<const CornerFaceIndexInput *>(&other) != nullptr;
+ }
+};
+
+class CornerIndexInFaceInput final : public bke::MeshFieldInput {
+ public:
+ CornerIndexInFaceInput() : bke::MeshFieldInput(CPPType::get<int>(), "Corner Index In Face")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const Mesh &mesh,
+ const eAttrDomain domain,
+ const IndexMask /*mask*/) const final
+ {
+ if (domain != ATTR_DOMAIN_CORNER) {
+ return {};
+ }
+ const Span<MPoly> polys = mesh.polys();
+ Array<int> loop_to_poly_map = bke::mesh_topology::build_loop_to_poly_map(polys, mesh.totloop);
+ return VArray<int>::ForFunc(
+ mesh.totloop, [polys, loop_to_poly_map = std::move(loop_to_poly_map)](const int corner_i) {
+ const int poly_i = loop_to_poly_map[corner_i];
+ return corner_i - polys[poly_i].loopstart;
+ });
+ }
+
+ uint64_t hash() const final
+ {
+ return 97837176448;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const final
+ {
+ if (dynamic_cast<const CornerIndexInFaceInput *>(&other)) {
+ return true;
+ }
+ return false;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const Field<int> corner_index = params.extract_input<Field<int>>("Corner Index");
+ if (params.output_is_required("Face Index")) {
+ params.set_output("Face Index",
+ Field<int>(std::make_shared<FieldAtIndexInput>(
+ corner_index,
+ Field<int>(std::make_shared<CornerFaceIndexInput>()),
+ ATTR_DOMAIN_CORNER)));
+ }
+ if (params.output_is_required("Index in Face")) {
+ params.set_output("Index in Face",
+ Field<int>(std::make_shared<FieldAtIndexInput>(
+ corner_index,
+ Field<int>(std::make_shared<CornerIndexInFaceInput>()),
+ ATTR_DOMAIN_CORNER)));
+ }
+}
+
+} // namespace blender::nodes::node_geo_mesh_topology_face_of_corner_cc
+
+void register_node_type_geo_mesh_topology_face_of_corner()
+{
+ namespace file_ns = blender::nodes::node_geo_mesh_topology_face_of_corner_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_MESH_TOPOLOGY_FACE_OF_CORNER, "Face of Corner", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc
new file mode 100644
index 00000000000..2cb9ae82fa1
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+
+#include "BLI_task.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_mesh_topology_offset_corner_in_face_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Int>(N_("Corner Index"))
+ .implicit_field(implicit_field_inputs::index)
+ .description(
+ N_("The corner to retrieve data from. Defaults to the corner from the context"));
+ b.add_input<decl::Int>(N_("Offset"))
+ .supports_field()
+ .description(N_("The number of corners to move around the face before finding the result, "
+ "circling around the start of the face if necessary"));
+ b.add_output<decl::Int>(N_("Corner Index"))
+ .dependent_field()
+ .description(N_("The index of the offset corner"));
+}
+
+class OffsetCornerInFaceFieldInput final : public bke::MeshFieldInput {
+ const Field<int> corner_index_;
+ const Field<int> offset_;
+
+ public:
+ OffsetCornerInFaceFieldInput(Field<int> corner_index, Field<int> offset)
+ : bke::MeshFieldInput(CPPType::get<int>(), "Offset Corner in Face"),
+ corner_index_(std::move(corner_index)),
+ offset_(std::move(offset))
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const Mesh &mesh,
+ const eAttrDomain domain,
+ const IndexMask mask) const final
+ {
+ const IndexRange corner_range(mesh.totloop);
+ const Span<MPoly> polys = mesh.polys();
+
+ const bke::MeshFieldContext context{mesh, domain};
+ fn::FieldEvaluator evaluator{context, &mask};
+ evaluator.add(corner_index_);
+ evaluator.add(offset_);
+ evaluator.evaluate();
+ const VArray<int> corner_indices = evaluator.get_evaluated<int>(0);
+ const VArray<int> offsets = evaluator.get_evaluated<int>(1);
+
+ Array<int> loop_to_poly_map = bke::mesh_topology::build_loop_to_poly_map(polys, mesh.totloop);
+
+ Array<int> offset_corners(mask.min_array_size());
+ threading::parallel_for(mask.index_range(), 2048, [&](const IndexRange range) {
+ for (const int selection_i : range) {
+ const int corner_i = corner_indices[selection_i];
+ const int offset = offsets[selection_i];
+ if (!corner_range.contains(corner_i)) {
+ offset_corners[selection_i] = 0;
+ continue;
+ }
+
+ const int poly_i = loop_to_poly_map[corner_i];
+ const IndexRange poly_range(polys[poly_i].loopstart, polys[poly_i].totloop);
+ offset_corners[selection_i] = apply_offset_in_cyclic_range(poly_range, corner_i, offset);
+ }
+ });
+
+ return VArray<int>::ForContainer(std::move(offset_corners));
+ }
+
+ uint64_t hash() const final
+ {
+ return get_default_hash(offset_);
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const final
+ {
+ if (const OffsetCornerInFaceFieldInput *other_field =
+ dynamic_cast<const OffsetCornerInFaceFieldInput *>(&other)) {
+ return other_field->corner_index_ == corner_index_ && other_field->offset_ == offset_;
+ }
+ return false;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ params.set_output("Corner Index",
+ Field<int>(std::make_shared<OffsetCornerInFaceFieldInput>(
+ params.extract_input<Field<int>>("Corner Index"),
+ params.extract_input<Field<int>>("Offset"))));
+}
+
+} // namespace blender::nodes::node_geo_mesh_topology_offset_corner_in_face_cc
+
+void register_node_type_geo_mesh_topology_offset_corner_in_face()
+{
+ namespace file_ns = blender::nodes::node_geo_mesh_topology_offset_corner_in_face_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(&ntype,
+ GEO_NODE_MESH_TOPOLOGY_OFFSET_CORNER_IN_FACE,
+ "Offset Corner in Face",
+ NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_vertex_of_corner.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_vertex_of_corner.cc
new file mode 100644
index 00000000000..f0163fa553a
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_vertex_of_corner.cc
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_mesh.h"
+
+#include "BLI_task.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_mesh_topology_vertex_of_corner_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Int>(N_("Corner Index"))
+ .implicit_field(implicit_field_inputs::index)
+ .description(
+ N_("The corner to retrieve data from. Defaults to the corner from the context"));
+ b.add_output<decl::Int>(N_("Vertex Index"))
+ .dependent_field()
+ .description(N_("The vertex the corner is attached to"));
+}
+
+static int get_loop_vert(const MLoop &loop)
+{
+ return loop.v;
+}
+
+class CornerVertFieldInput final : public bke::MeshFieldInput {
+ public:
+ CornerVertFieldInput() : bke::MeshFieldInput(CPPType::get<int>(), "Corner Vertex")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const Mesh &mesh,
+ const eAttrDomain domain,
+ const IndexMask /*mask*/) const final
+ {
+ if (domain != ATTR_DOMAIN_CORNER) {
+ return {};
+ }
+ return VArray<int>::ForDerivedSpan<MLoop, get_loop_vert>(mesh.loops());
+ }
+
+ uint64_t hash() const final
+ {
+ return 30495867093876;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const final
+ {
+ if (dynamic_cast<const CornerVertFieldInput *>(&other)) {
+ return true;
+ }
+ return false;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ params.set_output("Vertex Index",
+ Field<int>(std::make_shared<FieldAtIndexInput>(
+ params.extract_input<Field<int>>("Corner Index"),
+ Field<int>(std::make_shared<CornerVertFieldInput>()),
+ ATTR_DOMAIN_CORNER)));
+}
+
+} // namespace blender::nodes::node_geo_mesh_topology_vertex_of_corner_cc
+
+void register_node_type_geo_mesh_topology_vertex_of_corner()
+{
+ namespace file_ns = blender::nodes::node_geo_mesh_topology_vertex_of_corner_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_MESH_TOPOLOGY_VERTEX_OF_CORNER, "Vertex of Corner", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
index 0b2159364f1..bf064c6fcbe 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
@@ -3,6 +3,7 @@
#include "BLI_math_matrix.h"
#include "BKE_geometry_set_instances.hh"
+#include "BKE_instances.hh"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -25,7 +26,7 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "transform_space", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
@@ -68,19 +69,20 @@ static void node_geo_exec(GeoNodeExecParams params)
GeometrySet geometry_set;
if (params.get_input<bool>("As Instance")) {
- InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
- const int handle = instances.add_reference(*object);
+ std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>();
+ const int handle = instances->add_reference(*object);
if (transform_space_relative) {
- instances.add_instance(handle, transform);
+ instances->add_instance(handle, transform);
}
else {
- instances.add_instance(handle, float4x4::identity());
+ instances->add_instance(handle, float4x4::identity());
}
+ geometry_set = GeometrySet::create_with_instances(instances.release());
}
else {
geometry_set = bke::object_get_evaluated_geometry_set(*object);
if (transform_space_relative) {
- transform_geometry_set(geometry_set, transform, *params.depsgraph());
+ transform_geometry_set(params, geometry_set, transform, *params.depsgraph());
}
}
@@ -88,7 +90,7 @@ static void node_geo_exec(GeoNodeExecParams params)
}
}
-static void node_node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryObjectInfo *data = MEM_cnew<NodeGeometryObjectInfo>(__func__);
data->transform_space = GEO_NODE_TRANSFORM_SPACE_ORIGINAL;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_offset_point_in_curve.cc b/source/blender/nodes/geometry/nodes/node_geo_offset_point_in_curve.cc
new file mode 100644
index 00000000000..d71e27e0385
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_offset_point_in_curve.cc
@@ -0,0 +1,169 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BLI_task.hh"
+
+#include "BKE_curves.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes {
+
+int apply_offset_in_cyclic_range(const IndexRange range, const int start_index, const int offset)
+{
+ BLI_assert(range.contains(start_index));
+ const int start_in_range = start_index - range.first();
+ const int offset_in_range = start_in_range + offset;
+ const int mod_offset = offset_in_range % range.size();
+ if (mod_offset >= 0) {
+ return range[mod_offset];
+ }
+ return range.last(-(mod_offset + 1));
+}
+
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_offset_point_in_curve_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Int>(N_("Point Index"))
+ .implicit_field(implicit_field_inputs::index)
+ .description(
+ N_("The index of the control point to evaluate. Defaults to the current index"));
+ b.add_input<decl::Int>(N_("Offset"))
+ .supports_field()
+ .description(N_("The number of control points along the curve to traverse"));
+ b.add_output<decl::Bool>(N_("Is Valid Offset"))
+ .dependent_field()
+ .description(N_("Outputs true if the evaluated control point plus the offset "
+ "is a valid index of the original curve"));
+ b.add_output<decl::Int>(N_("Point Index"))
+ .dependent_field()
+ .description(N_("The index of the control point plus the offset within the entire "
+ "curves data-block"));
+}
+
+class ControlPointNeighborFieldInput final : public bke::CurvesFieldInput {
+ private:
+ const Field<int> index_;
+ const Field<int> offset_;
+
+ public:
+ ControlPointNeighborFieldInput(Field<int> index, Field<int> offset)
+ : CurvesFieldInput(CPPType::get<int>(), "Offset Point in Curve"),
+ index_(std::move(index)),
+ offset_(std::move(offset))
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
+ const eAttrDomain domain,
+ const IndexMask mask) const final
+ {
+ const VArray<bool> cyclic = curves.cyclic();
+ const Array<int> parent_curves = curves.point_to_curve_map();
+
+ const bke::CurvesFieldContext context{curves, domain};
+ fn::FieldEvaluator evaluator{context, &mask};
+ evaluator.add(index_);
+ evaluator.add(offset_);
+ evaluator.evaluate();
+ const VArray<int> indices = evaluator.get_evaluated<int>(0);
+ const VArray<int> offsets = evaluator.get_evaluated<int>(1);
+
+ Array<int> output(mask.min_array_size());
+ for (const int i_selection : mask) {
+ const int i_point = std::clamp(indices[i_selection], 0, curves.points_num() - 1);
+ const int i_curve = parent_curves[i_point];
+ const IndexRange curve_points = curves.points_for_curve(i_curve);
+ const int offset_point = i_point + offsets[i_point];
+
+ if (cyclic[i_curve]) {
+ output[i_selection] = apply_offset_in_cyclic_range(
+ curve_points, i_point, offsets[i_selection]);
+ continue;
+ }
+ output[i_selection] = std::clamp(offset_point, 0, curves.points_num() - 1);
+ }
+
+ return VArray<int>::ForContainer(std::move(output));
+ }
+};
+
+class OffsetValidFieldInput final : public bke::CurvesFieldInput {
+ private:
+ const Field<int> index_;
+ const Field<int> offset_;
+
+ public:
+ OffsetValidFieldInput(Field<int> index, Field<int> offset)
+ : CurvesFieldInput(CPPType::get<bool>(), "Offset Valid"),
+ index_(std::move(index)),
+ offset_(std::move(offset))
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const bke::CurvesGeometry &curves,
+ const eAttrDomain domain,
+ const IndexMask mask) const final
+ {
+ const VArray<bool> cyclic = curves.cyclic();
+ const Array<int> parent_curves = curves.point_to_curve_map();
+
+ const bke::CurvesFieldContext context{curves, domain};
+ fn::FieldEvaluator evaluator{context, &mask};
+ evaluator.add(index_);
+ evaluator.add(offset_);
+ evaluator.evaluate();
+ const VArray<int> indices = evaluator.get_evaluated<int>(0);
+ const VArray<int> offsets = evaluator.get_evaluated<int>(1);
+
+ Array<bool> output(mask.min_array_size());
+ for (const int i_selection : mask) {
+ const int i_point = indices[i_selection];
+ if (!curves.points_range().contains(i_point)) {
+ output[i_selection] = false;
+ continue;
+ }
+
+ const int i_curve = parent_curves[i_point];
+ const IndexRange curve_points = curves.points_for_curve(i_curve);
+ if (cyclic[i_curve]) {
+ output[i_selection] = true;
+ continue;
+ }
+ output[i_selection] = curve_points.contains(i_point + offsets[i_selection]);
+ };
+ return VArray<bool>::ForContainer(std::move(output));
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<int> index = params.extract_input<Field<int>>("Point Index");
+ Field<int> offset = params.extract_input<Field<int>>("Offset");
+
+ if (params.output_is_required("Point Index")) {
+ Field<int> curve_point_field{std::make_shared<ControlPointNeighborFieldInput>(index, offset)};
+ params.set_output("Point Index", std::move(curve_point_field));
+ }
+ if (params.output_is_required("Is Valid Offset")) {
+ Field<bool> valid_field{std::make_shared<OffsetValidFieldInput>(index, offset)};
+ params.set_output("Is Valid Offset", std::move(valid_field));
+ }
+}
+
+} // namespace blender::nodes::node_geo_offset_point_in_curve_cc
+
+void register_node_type_geo_offset_point_in_curve()
+{
+ namespace file_ns = blender::nodes::node_geo_offset_point_in_curve_cc;
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_OFFSET_POINT_IN_CURVE, "Offset Point in Curve", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_points.cc b/source/blender/nodes/geometry/nodes/node_geo_points.cc
index dd32e6714f4..dcbe176b384 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_points.cc
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BKE_pointcloud.h"
+#include "DNA_pointcloud_types.h"
#include "BLI_task.hh"
@@ -19,9 +20,10 @@ static void node_declare(NodeDeclarationBuilder &b)
.default_value(float3(0.0f))
.description(N_("The positions of the new points"));
b.add_input<decl::Float>(N_("Radius"))
+ .min(0.0f)
+ .default_value(0.1f)
.supports_field()
.subtype(PROP_DISTANCE)
- .default_value(float(0.1f))
.description(N_("The radii of the new points"));
b.add_output<decl::Geometry>(N_("Geometry"));
}
@@ -42,7 +44,7 @@ class PointsFieldContext : public FieldContext {
GVArray get_varray_for_input(const FieldInput &field_input,
const IndexMask mask,
- ResourceScope &UNUSED(scope)) const
+ ResourceScope & /*scope*/) const
{
const bke::IDAttributeFieldInput *id_field_input =
dynamic_cast<const bke::IDAttributeFieldInput *>(&field_input);
@@ -69,10 +71,8 @@ static void node_geo_exec(GeoNodeExecParams params)
Field<float3> position_field = params.extract_input<Field<float3>>("Position");
Field<float> radius_field = params.extract_input<Field<float>>("Radius");
- PointCloud *new_point_cloud = BKE_pointcloud_new_nomain(count);
- GeometrySet geometry_set = GeometrySet::create_with_pointcloud(new_point_cloud);
- PointCloudComponent &points = geometry_set.get_component_for_write<PointCloudComponent>();
- MutableAttributeAccessor attributes = *points.attributes_for_write();
+ PointCloud *points = BKE_pointcloud_new_nomain(count);
+ MutableAttributeAccessor attributes = points->attributes_for_write();
AttributeWriter<float3> output_position = attributes.lookup_or_add_for_write<float3>(
"position", ATTR_DOMAIN_POINT);
AttributeWriter<float> output_radii = attributes.lookup_or_add_for_write<float>(
@@ -86,7 +86,7 @@ static void node_geo_exec(GeoNodeExecParams params)
output_position.finish();
output_radii.finish();
- params.set_output("Geometry", std::move(geometry_set));
+ params.set_output("Geometry", GeometrySet::create_with_pointcloud(points));
}
} // namespace blender::nodes::node_geo_points_cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc
index ed7ef9b7c71..4ac3bf712f7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc
@@ -2,6 +2,8 @@
#include "BLI_task.hh"
+#include "DNA_pointcloud_types.h"
+
#include "BKE_attribute_math.hh"
#include "BKE_mesh.h"
@@ -22,21 +24,18 @@ static void node_declare(NodeDeclarationBuilder &b)
static void geometry_set_points_to_vertices(GeometrySet &geometry_set,
Field<bool> &selection_field)
{
- const PointCloudComponent *point_component =
- geometry_set.get_component_for_read<PointCloudComponent>();
- if (point_component == nullptr) {
+ const PointCloud *points = geometry_set.get_pointcloud_for_read();
+ if (points == nullptr) {
geometry_set.remove_geometry_during_modify();
return;
}
-
- GeometryComponentFieldContext field_context{*point_component, ATTR_DOMAIN_POINT};
- const int domain_num = point_component->attribute_domain_size(ATTR_DOMAIN_POINT);
- if (domain_num == 0) {
+ if (points->totpoint == 0) {
geometry_set.remove_geometry_during_modify();
return;
}
- fn::FieldEvaluator selection_evaluator{field_context, domain_num};
+ bke::PointCloudFieldContext field_context{*points};
+ fn::FieldEvaluator selection_evaluator{field_context, points->totpoint};
selection_evaluator.add(selection_field);
selection_evaluator.evaluate();
const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
@@ -47,16 +46,16 @@ static void geometry_set_points_to_vertices(GeometrySet &geometry_set,
Mesh *mesh = BKE_mesh_new_nomain(selection.size(), 0, 0, 0, 0);
geometry_set.replace_mesh(mesh);
- MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
+
+ const AttributeAccessor src_attributes = points->attributes();
+ MutableAttributeAccessor dst_attributes = mesh->attributes_for_write();
for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
const AttributeIDRef attribute_id = entry.key;
const eCustomDataType data_type = entry.value.data_type;
- GVArray src = point_component->attributes()->lookup_or_default(
+ GVArray src = src_attributes.lookup_or_default(attribute_id, ATTR_DOMAIN_POINT, data_type);
+ GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span(
attribute_id, ATTR_DOMAIN_POINT, data_type);
- GSpanAttributeWriter dst =
- mesh_component.attributes_for_write()->lookup_or_add_for_write_only_span(
- attribute_id, ATTR_DOMAIN_POINT, data_type);
if (dst && src) {
src.materialize_compressed_to_uninitialized(selection, dst.span.data());
dst.finish();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
index 4a3048e5f4a..45f6820f2e5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
@@ -43,14 +43,14 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Volume"));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "resolution_mode", 0, IFACE_("Resolution"), ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryPointsToVolume *data = MEM_cnew<NodeGeometryPointsToVolume>(__func__);
data->resolution_mode = GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT;
@@ -83,7 +83,7 @@ struct ParticleList {
size_t size() const
{
- return (size_t)positions.size();
+ return size_t(positions.size());
}
void getPos(size_t n, openvdb::Vec3R &xyz) const
@@ -170,7 +170,7 @@ static void gather_point_data_from_component(GeoNodeExecParams &params,
"position", ATTR_DOMAIN_POINT, {0, 0, 0});
Field<float> radius_field = params.get_input<Field<float>>("Radius");
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
+ bke::GeometryFieldContext field_context{component, ATTR_DOMAIN_POINT};
const int domain_num = component.attribute_domain_size(ATTR_DOMAIN_POINT);
r_positions.resize(r_positions.size() + domain_num);
@@ -215,7 +215,7 @@ static void initialize_volume_component_from_points(GeoNodeExecParams &params,
return;
}
- Volume *volume = (Volume *)BKE_id_new_nomain(ID_VO, nullptr);
+ Volume *volume = reinterpret_cast<Volume *>(BKE_id_new_nomain(ID_VO, nullptr));
BKE_volume_init_grids(volume);
const float density = params.get_input<float>("Density");
@@ -231,17 +231,16 @@ static void initialize_volume_component_from_points(GeoNodeExecParams &params,
static void node_geo_exec(GeoNodeExecParams params)
{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Points");
-
#ifdef WITH_OPENVDB
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Points");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
initialize_volume_component_from_points(params, geometry_set);
});
params.set_output("Volume", std::move(geometry_set));
#else
+ params.set_default_remaining_outputs();
params.error_message_add(NodeWarningType::Error,
TIP_("Disabled, Blender was compiled without OpenVDB"));
- params.set_default_remaining_outputs();
#endif
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_proximity.cc b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc
index d5233ee35a4..21f4449baee 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_proximity.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc
@@ -22,17 +22,17 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Geometry>(N_("Target"))
.only_realized_data()
.supported_type({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD});
- b.add_input<decl::Vector>(N_("Source Position")).implicit_field();
+ b.add_input<decl::Vector>(N_("Source Position")).implicit_field(implicit_field_inputs::position);
b.add_output<decl::Vector>(N_("Position")).dependent_field();
b.add_output<decl::Float>(N_("Distance")).dependent_field();
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "target_element", 0, "", ICON_NONE);
}
-static void geo_proximity_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void geo_proximity_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryProximity *node_storage = MEM_cnew<NodeGeometryProximity>(__func__);
node_storage->target_element = GEO_NODE_PROX_TARGET_FACES;
@@ -151,7 +151,7 @@ class ProximityFunction : public fn::MultiFunction {
return signature.build();
}
- void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext /*context*/) const override
{
const VArray<float3> &src_positions = params.readonly_single_input<float3>(0,
"Source Position");
@@ -211,8 +211,7 @@ static void node_geo_exec(GeoNodeExecParams params)
Field<float3> position_field = params.extract_input<Field<float3>>("Source Position");
auto proximity_fn = std::make_unique<ProximityFunction>(
- std::move(geometry_set_target),
- static_cast<GeometryNodeProximityTargetType>(storage.target_element));
+ std::move(geometry_set_target), GeometryNodeProximityTargetType(storage.target_element));
auto proximity_op = std::make_shared<FieldOperation>(
FieldOperation(std::move(proximity_fn), {std::move(position_field)}));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
index f81748da587..d248bc539b1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
@@ -31,7 +31,7 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Bool>(N_("Attribute"), "Attribute_003").hide_value().supports_field();
b.add_input<decl::Int>(N_("Attribute"), "Attribute_004").hide_value().supports_field();
- b.add_input<decl::Vector>(N_("Source Position")).implicit_field();
+ b.add_input<decl::Vector>(N_("Source Position")).implicit_field(implicit_field_inputs::position);
b.add_input<decl::Vector>(N_("Ray Direction"))
.default_value({0.0f, 0.0f, -1.0f})
.supports_field();
@@ -53,13 +53,13 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Int>(N_("Attribute"), "Attribute_004").dependent_field({1, 2, 3, 4, 5, 6});
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
uiItemR(layout, ptr, "mapping", 0, "", ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryRaycast *data = MEM_cnew<NodeGeometryRaycast>(__func__);
data->mapping = GEO_NODE_RAYCAST_INTERPOLATED;
@@ -70,9 +70,9 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeGeometryRaycast &storage = node_storage(*node);
- const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
+ const eCustomDataType data_type = eCustomDataType(storage.data_type);
- bNodeSocket *socket_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
+ bNodeSocket *socket_vector = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 1));
bNodeSocket *socket_float = socket_vector->next;
bNodeSocket *socket_color4f = socket_float->next;
bNodeSocket *socket_boolean = socket_color4f->next;
@@ -84,7 +84,7 @@ static void node_update(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, socket_boolean, data_type == CD_PROP_BOOL);
nodeSetSocketAvailability(ntree, socket_int32, data_type == CD_PROP_INT32);
- bNodeSocket *out_socket_vector = (bNodeSocket *)BLI_findlink(&node->outputs, 4);
+ bNodeSocket *out_socket_vector = static_cast<bNodeSocket *>(BLI_findlink(&node->outputs, 4));
bNodeSocket *out_socket_float = out_socket_vector->next;
bNodeSocket *out_socket_color4f = out_socket_float->next;
bNodeSocket *out_socket_boolean = out_socket_color4f->next;
@@ -208,7 +208,7 @@ class RaycastFunction : public fn::MultiFunction {
GeometryNodeRaycastMapMode mapping_;
/** The field for data evaluated on the target geometry. */
- std::optional<GeometryComponentFieldContext> target_context_;
+ std::optional<bke::MeshFieldContext> target_context_;
std::unique_ptr<FieldEvaluator> target_evaluator_;
const GVArray *target_data_ = nullptr;
@@ -245,7 +245,7 @@ class RaycastFunction : public fn::MultiFunction {
return signature.build();
}
- void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext /*context*/) const override
{
/* Hit positions are always necessary for retrieving the attribute from the target if that
* output is required, so always retrieve a span from the evaluator in that case (it's
@@ -310,9 +310,9 @@ class RaycastFunction : public fn::MultiFunction {
if (!src_field) {
return;
}
- const MeshComponent &mesh_component = *target_.get_component_for_read<MeshComponent>();
- target_context_.emplace(GeometryComponentFieldContext{mesh_component, domain_});
- const int domain_size = mesh_component.attribute_domain_size(domain_);
+ const Mesh &mesh = *target_.get_mesh_for_read();
+ target_context_.emplace(bke::MeshFieldContext{mesh, domain_});
+ const int domain_size = mesh.attributes().domain_size(domain_);
target_evaluator_ = std::make_unique<FieldEvaluator>(*target_context_, domain_size);
target_evaluator_->add(std::move(src_field));
target_evaluator_->evaluate();
@@ -386,8 +386,8 @@ static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet target = params.extract_input<GeometrySet>("Target Geometry");
const NodeGeometryRaycast &storage = node_storage(params.node());
- const GeometryNodeRaycastMapMode mapping = (GeometryNodeRaycastMapMode)storage.mapping;
- const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
+ const GeometryNodeRaycastMapMode mapping = GeometryNodeRaycastMapMode(storage.mapping);
+ const eCustomDataType data_type = eCustomDataType(storage.data_type);
if (target.is_empty()) {
params.set_default_remaining_outputs();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc
index 1c72d73d151..3ccc8afb0a7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc
@@ -15,7 +15,7 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "legacy_behavior", 0, nullptr, ICON_NONE);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc
index ee279ba58f9..1b398f63691 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc
@@ -55,7 +55,7 @@ static void node_geo_exec(GeoNodeExecParams params)
});
if (attribute_exists && !cannot_delete) {
- params.used_named_attribute(name, eNamedAttrUsage::Remove);
+ params.used_named_attribute(name, NamedAttributeUsage::Remove);
}
if (!attribute_exists) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
index d414bb1fa1d..fac92a7500c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
@@ -2,6 +2,8 @@
#include "BLI_task.hh"
+#include "BKE_instances.hh"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_rotate_instances_cc {
@@ -16,12 +18,10 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Instances"));
}
-static void rotate_instances(GeoNodeExecParams &params, InstancesComponent &instances_component)
+static void rotate_instances(GeoNodeExecParams &params, bke::Instances &instances)
{
- GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE};
- const int domain_num = instances_component.instances_num();
-
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ const bke::InstancesFieldContext context{instances};
+ fn::FieldEvaluator evaluator{context, instances.instances_num()};
evaluator.set_selection(params.extract_input<Field<bool>>("Selection"));
evaluator.add(params.extract_input<Field<float3>>("Rotation"));
evaluator.add(params.extract_input<Field<float3>>("Pivot Point"));
@@ -33,14 +33,14 @@ static void rotate_instances(GeoNodeExecParams &params, InstancesComponent &inst
const VArray<float3> pivots = evaluator.get_evaluated<float3>(1);
const VArray<bool> local_spaces = evaluator.get_evaluated<bool>(2);
- MutableSpan<float4x4> instance_transforms = instances_component.instance_transforms();
+ MutableSpan<float4x4> transforms = instances.transforms();
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
for (const int i_selection : range) {
const int i = selection[i_selection];
const float3 pivot = pivots[i];
const float3 euler = rotations[i];
- float4x4 &instance_transform = instance_transforms[i];
+ float4x4 &instance_transform = transforms[i];
float4x4 rotation_matrix;
float3 used_pivot;
@@ -83,9 +83,8 @@ static void rotate_instances(GeoNodeExecParams &params, InstancesComponent &inst
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances");
- if (geometry_set.has_instances()) {
- InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
- rotate_instances(params, instances);
+ if (bke::Instances *instances = geometry_set.get_instances_for_write()) {
+ rotate_instances(params, *instances);
}
params.set_output("Instances", std::move(geometry_set));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_sample_index.cc b/source/blender/nodes/geometry/nodes/node_geo_sample_index.cc
new file mode 100644
index 00000000000..4d2db059798
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_sample_index.cc
@@ -0,0 +1,337 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BLI_task.hh"
+
+#include "BKE_attribute_math.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "NOD_socket_search_link.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_sample_index_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometrySampleIndex);
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry"))
+ .supported_type({GEO_COMPONENT_TYPE_MESH,
+ GEO_COMPONENT_TYPE_POINT_CLOUD,
+ GEO_COMPONENT_TYPE_CURVE,
+ GEO_COMPONENT_TYPE_INSTANCES});
+
+ b.add_input<decl::Float>(N_("Value"), "Value_Float").hide_value().supports_field();
+ b.add_input<decl::Int>(N_("Value"), "Value_Int").hide_value().supports_field();
+ b.add_input<decl::Vector>(N_("Value"), "Value_Vector").hide_value().supports_field();
+ b.add_input<decl::Color>(N_("Value"), "Value_Color").hide_value().supports_field();
+ b.add_input<decl::Bool>(N_("Value"), "Value_Bool").hide_value().supports_field();
+ b.add_input<decl::Int>(N_("Index"))
+ .supports_field()
+ .description(N_("Which element to retrieve a value from on the geometry"));
+
+ b.add_output<decl::Float>(N_("Value"), "Value_Float").dependent_field({6});
+ b.add_output<decl::Int>(N_("Value"), "Value_Int").dependent_field({6});
+ b.add_output<decl::Vector>(N_("Value"), "Value_Vector").dependent_field({6});
+ b.add_output<decl::Color>(N_("Value"), "Value_Color").dependent_field({6});
+ b.add_output<decl::Bool>(N_("Value"), "Value_Bool").dependent_field({6});
+}
+
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "clamp", 0, nullptr, ICON_NONE);
+}
+
+static void node_init(bNodeTree * /*tree*/, bNode *node)
+{
+ NodeGeometrySampleIndex *data = MEM_cnew<NodeGeometrySampleIndex>(__func__);
+ data->data_type = CD_PROP_FLOAT;
+ data->domain = ATTR_DOMAIN_POINT;
+ data->clamp = 0;
+ node->storage = data;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ const eCustomDataType data_type = eCustomDataType(node_storage(*node).data_type);
+
+ bNodeSocket *in_socket_geometry = static_cast<bNodeSocket *>(node->inputs.first);
+ bNodeSocket *in_socket_float = in_socket_geometry->next;
+ bNodeSocket *in_socket_int32 = in_socket_float->next;
+ bNodeSocket *in_socket_vector = in_socket_int32->next;
+ bNodeSocket *in_socket_color4f = in_socket_vector->next;
+ bNodeSocket *in_socket_bool = in_socket_color4f->next;
+
+ nodeSetSocketAvailability(ntree, in_socket_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, in_socket_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, in_socket_color4f, data_type == CD_PROP_COLOR);
+ nodeSetSocketAvailability(ntree, in_socket_bool, data_type == CD_PROP_BOOL);
+ nodeSetSocketAvailability(ntree, in_socket_int32, data_type == CD_PROP_INT32);
+
+ bNodeSocket *out_socket_float = static_cast<bNodeSocket *>(node->outputs.first);
+ bNodeSocket *out_socket_int32 = out_socket_float->next;
+ bNodeSocket *out_socket_vector = out_socket_int32->next;
+ bNodeSocket *out_socket_color4f = out_socket_vector->next;
+ bNodeSocket *out_socket_bool = out_socket_color4f->next;
+
+ nodeSetSocketAvailability(ntree, out_socket_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, out_socket_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, out_socket_color4f, data_type == CD_PROP_COLOR);
+ nodeSetSocketAvailability(ntree, out_socket_bool, data_type == CD_PROP_BOOL);
+ nodeSetSocketAvailability(ntree, out_socket_int32, data_type == CD_PROP_INT32);
+}
+
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ search_link_ops_for_declarations(params, declaration.inputs().take_back(1));
+ search_link_ops_for_declarations(params, declaration.inputs().take_front(1));
+
+ const std::optional<eCustomDataType> type = node_data_type_to_custom_data_type(
+ (eNodeSocketDatatype)params.other_socket().type);
+ if (type && *type != CD_PROP_STRING) {
+ /* The input and output sockets have the same name. */
+ params.add_item(IFACE_("Value"), [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeSampleIndex");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Value");
+ });
+ }
+}
+
+static bool component_is_available(const GeometrySet &geometry,
+ const GeometryComponentType type,
+ const eAttrDomain domain)
+{
+ if (!geometry.has(type)) {
+ return false;
+ }
+ const GeometryComponent &component = *geometry.get_component_for_read(type);
+ if (component.is_empty()) {
+ return false;
+ }
+ return component.attribute_domain_size(domain) != 0;
+}
+
+static const GeometryComponent *find_source_component(const GeometrySet &geometry,
+ const eAttrDomain domain)
+{
+ /* Choose the other component based on a consistent order, rather than some more complicated
+ * heuristic. This is the same order visible in the spreadsheet and used in the ray-cast node. */
+ static const Array<GeometryComponentType> supported_types = {GEO_COMPONENT_TYPE_MESH,
+ GEO_COMPONENT_TYPE_POINT_CLOUD,
+ GEO_COMPONENT_TYPE_CURVE,
+ GEO_COMPONENT_TYPE_INSTANCES};
+ for (const GeometryComponentType src_type : supported_types) {
+ if (component_is_available(geometry, src_type, domain)) {
+ return geometry.get_component_for_read(src_type);
+ }
+ }
+
+ return nullptr;
+}
+
+template<typename T>
+void copy_with_indices(const VArray<T> &src,
+ const VArray<int> &indices,
+ const IndexMask mask,
+ MutableSpan<T> dst)
+{
+ const IndexRange src_range = src.index_range();
+ devirtualize_varray2(src, indices, [&](const auto src, const auto indices) {
+ threading::parallel_for(mask.index_range(), 4096, [&](IndexRange range) {
+ for (const int i : mask.slice(range)) {
+ const int index = indices[i];
+ if (src_range.contains(index)) {
+ dst[i] = src[index];
+ }
+ else {
+ dst[i] = {};
+ }
+ }
+ });
+ });
+}
+
+template<typename T>
+void copy_with_clamped_indices(const VArray<T> &src,
+ const VArray<int> &indices,
+ const IndexMask mask,
+ MutableSpan<T> dst)
+{
+ const int last_index = src.index_range().last();
+ devirtualize_varray2(src, indices, [&](const auto src, const auto indices) {
+ threading::parallel_for(mask.index_range(), 4096, [&](IndexRange range) {
+ for (const int i : mask.slice(range)) {
+ const int index = indices[i];
+ dst[i] = src[std::clamp(index, 0, last_index)];
+ }
+ });
+ });
+}
+
+/**
+ * The index-based transfer theoretically does not need realized data when there is only one
+ * instance geometry set in the source. A future optimization could be removing that limitation
+ * internally.
+ */
+class SampleIndexFunction : public fn::MultiFunction {
+ GeometrySet src_geometry_;
+ GField src_field_;
+ eAttrDomain domain_;
+ bool clamp_;
+
+ fn::MFSignature signature_;
+
+ std::optional<bke::GeometryFieldContext> geometry_context_;
+ std::unique_ptr<FieldEvaluator> evaluator_;
+ const GVArray *src_data_ = nullptr;
+
+ public:
+ SampleIndexFunction(GeometrySet geometry,
+ GField src_field,
+ const eAttrDomain domain,
+ const bool clamp)
+ : src_geometry_(std::move(geometry)),
+ src_field_(std::move(src_field)),
+ domain_(domain),
+ clamp_(clamp)
+ {
+ src_geometry_.ensure_owns_direct_data();
+
+ signature_ = this->create_signature();
+ this->set_signature(&signature_);
+
+ this->evaluate_field();
+ }
+
+ fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"Sample Index"};
+ signature.single_input<int>("Index");
+ signature.single_output("Value", src_field_.cpp_type());
+ return signature.build();
+ }
+
+ void evaluate_field()
+ {
+ const GeometryComponent *component = find_source_component(src_geometry_, domain_);
+ if (component == nullptr) {
+ return;
+ }
+ const int domain_num = component->attribute_domain_size(domain_);
+ geometry_context_.emplace(bke::GeometryFieldContext(*component, domain_));
+ evaluator_ = std::make_unique<FieldEvaluator>(*geometry_context_, domain_num);
+ evaluator_->add(src_field_);
+ evaluator_->evaluate();
+ src_data_ = &evaluator_->get_evaluated(0);
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext /*context*/) const override
+ {
+ const VArray<int> &indices = params.readonly_single_input<int>(0, "Index");
+ GMutableSpan dst = params.uninitialized_single_output(1, "Value");
+
+ const CPPType &type = dst.type();
+ if (src_data_ == nullptr) {
+ type.value_initialize_indices(dst.data(), mask);
+ return;
+ }
+
+ attribute_math::convert_to_static_type(type, [&](auto dummy) {
+ using T = decltype(dummy);
+ if (clamp_) {
+ copy_with_clamped_indices(src_data_->typed<T>(), indices, mask, dst.typed<T>());
+ }
+ else {
+ copy_with_indices(src_data_->typed<T>(), indices, mask, dst.typed<T>());
+ }
+ });
+ }
+};
+
+static GField get_input_attribute_field(GeoNodeExecParams &params, const eCustomDataType data_type)
+{
+ switch (data_type) {
+ case CD_PROP_FLOAT:
+ return params.extract_input<Field<float>>("Value_Float");
+ case CD_PROP_FLOAT3:
+ return params.extract_input<Field<float3>>("Value_Vector");
+ case CD_PROP_COLOR:
+ return params.extract_input<Field<ColorGeometry4f>>("Value_Color");
+ case CD_PROP_BOOL:
+ return params.extract_input<Field<bool>>("Value_Bool");
+ case CD_PROP_INT32:
+ return params.extract_input<Field<int>>("Value_Int");
+ default:
+ BLI_assert_unreachable();
+ }
+ return {};
+}
+
+static void output_attribute_field(GeoNodeExecParams &params, GField field)
+{
+ switch (bke::cpp_type_to_custom_data_type(field.cpp_type())) {
+ case CD_PROP_FLOAT: {
+ params.set_output("Value_Float", Field<float>(field));
+ break;
+ }
+ case CD_PROP_FLOAT3: {
+ params.set_output("Value_Vector", Field<float3>(field));
+ break;
+ }
+ case CD_PROP_COLOR: {
+ params.set_output("Value_Color", Field<ColorGeometry4f>(field));
+ break;
+ }
+ case CD_PROP_BOOL: {
+ params.set_output("Value_Bool", Field<bool>(field));
+ break;
+ }
+ case CD_PROP_INT32: {
+ params.set_output("Value_Int", Field<int>(field));
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry = params.extract_input<GeometrySet>("Geometry");
+ const NodeGeometrySampleIndex &storage = node_storage(params.node());
+ const eCustomDataType data_type = eCustomDataType(storage.data_type);
+ const eAttrDomain domain = eAttrDomain(storage.domain);
+
+ auto fn = std::make_shared<SampleIndexFunction>(std::move(geometry),
+ get_input_attribute_field(params, data_type),
+ domain,
+ bool(storage.clamp));
+ auto op = FieldOperation::Create(std::move(fn), {params.extract_input<Field<int>>("Index")});
+ output_attribute_field(params, GField(std::move(op)));
+}
+
+} // namespace blender::nodes::node_geo_sample_index_cc
+
+void register_node_type_geo_sample_index()
+{
+ namespace file_ns = blender::nodes::node_geo_sample_index_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_SAMPLE_INDEX, "Sample Index", NODE_CLASS_GEOMETRY);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.declare = file_ns::node_declare;
+ node_type_storage(
+ &ntype, "NodeGeometrySampleIndex", node_free_standard_storage, node_copy_standard_storage);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_sample_nearest.cc b/source/blender/nodes/geometry/nodes/node_geo_sample_nearest.cc
new file mode 100644
index 00000000000..8c5dad3a1c5
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_sample_nearest.cc
@@ -0,0 +1,342 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "DNA_pointcloud_types.h"
+
+#include "BKE_bvhutils.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes {
+
+void get_closest_in_bvhtree(BVHTreeFromMesh &tree_data,
+ const VArray<float3> &positions,
+ const IndexMask mask,
+ const MutableSpan<int> r_indices,
+ const MutableSpan<float> r_distances_sq,
+ const MutableSpan<float3> r_positions)
+{
+ BLI_assert(positions.size() >= r_indices.size());
+ BLI_assert(positions.size() >= r_distances_sq.size());
+ BLI_assert(positions.size() >= r_positions.size());
+
+ for (const int i : mask) {
+ BVHTreeNearest nearest;
+ nearest.dist_sq = FLT_MAX;
+ const float3 position = positions[i];
+ BLI_bvhtree_find_nearest(
+ tree_data.tree, position, &nearest, tree_data.nearest_callback, &tree_data);
+ if (!r_indices.is_empty()) {
+ r_indices[i] = nearest.index;
+ }
+ if (!r_distances_sq.is_empty()) {
+ r_distances_sq[i] = nearest.dist_sq;
+ }
+ if (!r_positions.is_empty()) {
+ r_positions[i] = nearest.co;
+ }
+ }
+}
+
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_sample_nearest_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry"))
+ .supported_type({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD});
+ b.add_input<decl::Vector>(N_("Sample Position")).implicit_field(implicit_field_inputs::position);
+ b.add_output<decl::Int>(N_("Index")).dependent_field({1});
+}
+
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree * /*tree*/, bNode *node)
+{
+ node->custom1 = CD_PROP_FLOAT;
+ node->custom2 = ATTR_DOMAIN_POINT;
+}
+
+static void get_closest_pointcloud_points(const PointCloud &pointcloud,
+ const VArray<float3> &positions,
+ const IndexMask mask,
+ const MutableSpan<int> r_indices,
+ const MutableSpan<float> r_distances_sq)
+{
+ BLI_assert(positions.size() >= r_indices.size());
+ BLI_assert(pointcloud.totpoint > 0);
+
+ BVHTreeFromPointCloud tree_data;
+ BKE_bvhtree_from_pointcloud_get(&tree_data, &pointcloud, 2);
+
+ for (const int i : mask) {
+ BVHTreeNearest nearest;
+ nearest.dist_sq = FLT_MAX;
+ const float3 position = positions[i];
+ BLI_bvhtree_find_nearest(
+ tree_data.tree, position, &nearest, tree_data.nearest_callback, &tree_data);
+ r_indices[i] = nearest.index;
+ if (!r_distances_sq.is_empty()) {
+ r_distances_sq[i] = nearest.dist_sq;
+ }
+ }
+
+ free_bvhtree_from_pointcloud(&tree_data);
+}
+
+static void get_closest_mesh_points(const Mesh &mesh,
+ const VArray<float3> &positions,
+ const IndexMask mask,
+ const MutableSpan<int> r_point_indices,
+ const MutableSpan<float> r_distances_sq,
+ const MutableSpan<float3> r_positions)
+{
+ BLI_assert(mesh.totvert > 0);
+ BVHTreeFromMesh tree_data;
+ BKE_bvhtree_from_mesh_get(&tree_data, &mesh, BVHTREE_FROM_VERTS, 2);
+ get_closest_in_bvhtree(tree_data, positions, mask, r_point_indices, r_distances_sq, r_positions);
+ free_bvhtree_from_mesh(&tree_data);
+}
+
+static void get_closest_mesh_edges(const Mesh &mesh,
+ const VArray<float3> &positions,
+ const IndexMask mask,
+ const MutableSpan<int> r_edge_indices,
+ const MutableSpan<float> r_distances_sq,
+ const MutableSpan<float3> r_positions)
+{
+ BLI_assert(mesh.totedge > 0);
+ BVHTreeFromMesh tree_data;
+ BKE_bvhtree_from_mesh_get(&tree_data, &mesh, BVHTREE_FROM_EDGES, 2);
+ get_closest_in_bvhtree(tree_data, positions, mask, r_edge_indices, r_distances_sq, r_positions);
+ free_bvhtree_from_mesh(&tree_data);
+}
+
+static void get_closest_mesh_looptris(const Mesh &mesh,
+ const VArray<float3> &positions,
+ const IndexMask mask,
+ const MutableSpan<int> r_looptri_indices,
+ const MutableSpan<float> r_distances_sq,
+ const MutableSpan<float3> r_positions)
+{
+ BLI_assert(mesh.totpoly > 0);
+ BVHTreeFromMesh tree_data;
+ BKE_bvhtree_from_mesh_get(&tree_data, &mesh, BVHTREE_FROM_LOOPTRI, 2);
+ get_closest_in_bvhtree(
+ tree_data, positions, mask, r_looptri_indices, r_distances_sq, r_positions);
+ free_bvhtree_from_mesh(&tree_data);
+}
+
+static void get_closest_mesh_polys(const Mesh &mesh,
+ const VArray<float3> &positions,
+ const IndexMask mask,
+ const MutableSpan<int> r_poly_indices,
+ const MutableSpan<float> r_distances_sq,
+ const MutableSpan<float3> r_positions)
+{
+ BLI_assert(mesh.totpoly > 0);
+
+ Array<int> looptri_indices(positions.size());
+ get_closest_mesh_looptris(mesh, positions, mask, looptri_indices, r_distances_sq, r_positions);
+
+ const Span<MLoopTri> looptris = mesh.looptris();
+
+ for (const int i : mask) {
+ const MLoopTri &looptri = looptris[looptri_indices[i]];
+ r_poly_indices[i] = looptri.poly;
+ }
+}
+
+/* The closest corner is defined to be the closest corner on the closest face. */
+static void get_closest_mesh_corners(const Mesh &mesh,
+ const VArray<float3> &positions,
+ const IndexMask mask,
+ const MutableSpan<int> r_corner_indices,
+ const MutableSpan<float> r_distances_sq,
+ const MutableSpan<float3> r_positions)
+{
+ const Span<MVert> verts = mesh.verts();
+ const Span<MPoly> polys = mesh.polys();
+ const Span<MLoop> loops = mesh.loops();
+
+ BLI_assert(mesh.totloop > 0);
+ Array<int> poly_indices(positions.size());
+ get_closest_mesh_polys(mesh, positions, mask, poly_indices, {}, {});
+
+ for (const int i : mask) {
+ const float3 position = positions[i];
+ const int poly_index = poly_indices[i];
+ const MPoly &poly = polys[poly_index];
+
+ /* Find the closest vertex in the polygon. */
+ float min_distance_sq = FLT_MAX;
+ const MVert *closest_mvert;
+ int closest_loop_index = 0;
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const MLoop &loop = loops[loop_index];
+ const int vertex_index = loop.v;
+ const MVert &mvert = verts[vertex_index];
+ const float distance_sq = math::distance_squared(position, float3(mvert.co));
+ if (distance_sq < min_distance_sq) {
+ min_distance_sq = distance_sq;
+ closest_loop_index = loop_index;
+ closest_mvert = &mvert;
+ }
+ }
+ if (!r_corner_indices.is_empty()) {
+ r_corner_indices[i] = closest_loop_index;
+ }
+ if (!r_positions.is_empty()) {
+ r_positions[i] = closest_mvert->co;
+ }
+ if (!r_distances_sq.is_empty()) {
+ r_distances_sq[i] = min_distance_sq;
+ }
+ }
+}
+
+static bool component_is_available(const GeometrySet &geometry,
+ const GeometryComponentType type,
+ const eAttrDomain domain)
+{
+ if (!geometry.has(type)) {
+ return false;
+ }
+ const GeometryComponent &component = *geometry.get_component_for_read(type);
+ if (component.is_empty()) {
+ return false;
+ }
+ return component.attribute_domain_size(domain) != 0;
+}
+
+static const GeometryComponent *find_source_component(const GeometrySet &geometry,
+ const eAttrDomain domain)
+{
+ /* Choose the other component based on a consistent order, rather than some more complicated
+ * heuristic. This is the same order visible in the spreadsheet and used in the ray-cast node. */
+ static const Array<GeometryComponentType> supported_types = {GEO_COMPONENT_TYPE_MESH,
+ GEO_COMPONENT_TYPE_POINT_CLOUD,
+ GEO_COMPONENT_TYPE_CURVE,
+ GEO_COMPONENT_TYPE_INSTANCES};
+ for (const GeometryComponentType src_type : supported_types) {
+ if (component_is_available(geometry, src_type, domain)) {
+ return geometry.get_component_for_read(src_type);
+ }
+ }
+
+ return nullptr;
+}
+
+class SampleNearestFunction : public fn::MultiFunction {
+ GeometrySet source_;
+ eAttrDomain domain_;
+
+ const GeometryComponent *src_component_;
+
+ fn::MFSignature signature_;
+
+ public:
+ SampleNearestFunction(GeometrySet geometry, eAttrDomain domain)
+ : source_(std::move(geometry)), domain_(domain)
+ {
+ source_.ensure_owns_direct_data();
+ signature_ = this->create_signature();
+ this->set_signature(&signature_);
+
+ this->src_component_ = find_source_component(source_, domain_);
+ }
+
+ fn::MFSignature create_signature()
+ {
+ blender::fn::MFSignatureBuilder signature{"Sample Nearest"};
+ signature.single_input<float3>("Position");
+ signature.single_output<int>("Index");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext /*context*/) const override
+ {
+ const VArray<float3> &positions = params.readonly_single_input<float3>(0, "Position");
+ MutableSpan<int> indices = params.uninitialized_single_output<int>(1, "Index");
+ if (!src_component_) {
+ indices.fill_indices(mask, 0);
+ return;
+ }
+
+ switch (src_component_->type()) {
+ case GEO_COMPONENT_TYPE_MESH: {
+ const MeshComponent &component = *static_cast<const MeshComponent *>(src_component_);
+ const Mesh &mesh = *component.get_for_read();
+ Array<float> distances(mask.min_array_size());
+ switch (domain_) {
+ case ATTR_DOMAIN_POINT:
+ get_closest_mesh_points(mesh, positions, mask, indices, distances, {});
+ break;
+ case ATTR_DOMAIN_EDGE:
+ get_closest_mesh_edges(mesh, positions, mask, indices, distances, {});
+ break;
+ case ATTR_DOMAIN_FACE:
+ get_closest_mesh_polys(mesh, positions, mask, indices, distances, {});
+ break;
+ case ATTR_DOMAIN_CORNER:
+ get_closest_mesh_corners(mesh, positions, mask, indices, distances, {});
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case GEO_COMPONENT_TYPE_POINT_CLOUD: {
+ const PointCloudComponent &component = *static_cast<const PointCloudComponent *>(
+ src_component_);
+ const PointCloud &points = *component.get_for_read();
+ Array<float> distances(mask.min_array_size());
+ get_closest_pointcloud_points(points, positions, mask, indices, distances);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry = params.extract_input<GeometrySet>("Geometry");
+ const eAttrDomain domain = eAttrDomain(params.node().custom2);
+ if (geometry.has_curves() && !geometry.has_mesh() && !geometry.has_pointcloud()) {
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("The source geometry must contain a mesh or a point cloud"));
+ params.set_default_remaining_outputs();
+ return;
+ }
+
+ Field<float3> positions = params.extract_input<Field<float3>>("Sample Position");
+ auto fn = std::make_shared<SampleNearestFunction>(std::move(geometry), domain);
+ auto op = FieldOperation::Create(std::move(fn), {std::move(positions)});
+ params.set_output<Field<int>>("Index", Field<int>(std::move(op)));
+}
+
+} // namespace blender::nodes::node_geo_sample_nearest_cc
+
+void register_node_type_geo_sample_nearest()
+{
+ namespace file_ns = blender::nodes::node_geo_sample_nearest_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_SAMPLE_NEAREST, "Sample Nearest", NODE_CLASS_GEOMETRY);
+ node_type_init(&ntype, file_ns::node_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc
new file mode 100644
index 00000000000..95bf7199d63
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc
@@ -0,0 +1,278 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_bvhutils.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_sample.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "NOD_socket_search_link.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_sample_nearest_surface_cc {
+
+using namespace blender::bke::mesh_surface_sample;
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
+
+ b.add_input<decl::Float>(N_("Value"), "Value_Float").hide_value().supports_field();
+ b.add_input<decl::Int>(N_("Value"), "Value_Int").hide_value().supports_field();
+ b.add_input<decl::Vector>(N_("Value"), "Value_Vector").hide_value().supports_field();
+ b.add_input<decl::Color>(N_("Value"), "Value_Color").hide_value().supports_field();
+ b.add_input<decl::Bool>(N_("Value"), "Value_Bool").hide_value().supports_field();
+
+ b.add_input<decl::Vector>(N_("Sample Position")).implicit_field(implicit_field_inputs::position);
+
+ b.add_output<decl::Float>(N_("Value"), "Value_Float").dependent_field({6});
+ b.add_output<decl::Int>(N_("Value"), "Value_Int").dependent_field({6});
+ b.add_output<decl::Vector>(N_("Value"), "Value_Vector").dependent_field({6});
+ b.add_output<decl::Color>(N_("Value"), "Value_Color").dependent_field({6});
+ b.add_output<decl::Bool>(N_("Value"), "Value_Bool").dependent_field({6});
+}
+
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree * /*tree*/, bNode *node)
+{
+ node->custom1 = CD_PROP_FLOAT;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ const eCustomDataType data_type = eCustomDataType(node->custom1);
+
+ bNodeSocket *in_socket_mesh = static_cast<bNodeSocket *>(node->inputs.first);
+ bNodeSocket *in_socket_float = in_socket_mesh->next;
+ bNodeSocket *in_socket_int32 = in_socket_float->next;
+ bNodeSocket *in_socket_vector = in_socket_int32->next;
+ bNodeSocket *in_socket_color4f = in_socket_vector->next;
+ bNodeSocket *in_socket_bool = in_socket_color4f->next;
+
+ nodeSetSocketAvailability(ntree, in_socket_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, in_socket_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, in_socket_color4f, data_type == CD_PROP_COLOR);
+ nodeSetSocketAvailability(ntree, in_socket_bool, data_type == CD_PROP_BOOL);
+ nodeSetSocketAvailability(ntree, in_socket_int32, data_type == CD_PROP_INT32);
+
+ bNodeSocket *out_socket_float = static_cast<bNodeSocket *>(node->outputs.first);
+ bNodeSocket *out_socket_int32 = out_socket_float->next;
+ bNodeSocket *out_socket_vector = out_socket_int32->next;
+ bNodeSocket *out_socket_color4f = out_socket_vector->next;
+ bNodeSocket *out_socket_bool = out_socket_color4f->next;
+
+ nodeSetSocketAvailability(ntree, out_socket_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, out_socket_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, out_socket_color4f, data_type == CD_PROP_COLOR);
+ nodeSetSocketAvailability(ntree, out_socket_bool, data_type == CD_PROP_BOOL);
+ nodeSetSocketAvailability(ntree, out_socket_int32, data_type == CD_PROP_INT32);
+}
+
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ search_link_ops_for_declarations(params, declaration.inputs().take_back(2));
+ search_link_ops_for_declarations(params, declaration.inputs().take_front(1));
+
+ const std::optional<eCustomDataType> type = node_data_type_to_custom_data_type(
+ (eNodeSocketDatatype)params.other_socket().type);
+ if (type && *type != CD_PROP_STRING) {
+ /* The input and output sockets have the same name. */
+ params.add_item(IFACE_("Value"), [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeSampleNearestSurface");
+ node.custom1 = *type;
+ params.update_and_connect_available_socket(node, "Value");
+ });
+ }
+}
+
+static void get_closest_mesh_looptris(const Mesh &mesh,
+ const VArray<float3> &positions,
+ const IndexMask mask,
+ const MutableSpan<int> r_looptri_indices,
+ const MutableSpan<float> r_distances_sq,
+ const MutableSpan<float3> r_positions)
+{
+ BLI_assert(mesh.totpoly > 0);
+ BVHTreeFromMesh tree_data;
+ BKE_bvhtree_from_mesh_get(&tree_data, &mesh, BVHTREE_FROM_LOOPTRI, 2);
+ get_closest_in_bvhtree(
+ tree_data, positions, mask, r_looptri_indices, r_distances_sq, r_positions);
+ free_bvhtree_from_mesh(&tree_data);
+}
+
+/**
+ * \note Multi-threading for this function is provided by the field evaluator. Since the #call
+ * function could be called many times, calculate the data from the source geometry once and store
+ * it for later.
+ */
+class SampleNearestSurfaceFunction : public fn::MultiFunction {
+ GeometrySet source_;
+ GField src_field_;
+
+ /**
+ * This function is meant to sample the surface of a mesh rather than take the value from
+ * individual elements, so use the most complex domain, ensuring no information is lost. In the
+ * future, it should be possible to use the most complex domain required by the field inputs, to
+ * simplify sampling and avoid domain conversions.
+ */
+ eAttrDomain domain_ = ATTR_DOMAIN_CORNER;
+
+ fn::MFSignature signature_;
+
+ std::optional<bke::MeshFieldContext> source_context_;
+ std::unique_ptr<FieldEvaluator> source_evaluator_;
+ const GVArray *source_data_;
+
+ public:
+ SampleNearestSurfaceFunction(GeometrySet geometry, GField src_field)
+ : source_(std::move(geometry)), src_field_(std::move(src_field))
+ {
+ source_.ensure_owns_direct_data();
+ signature_ = this->create_signature();
+ this->set_signature(&signature_);
+ this->evaluate_source_field();
+ }
+
+ fn::MFSignature create_signature()
+ {
+ blender::fn::MFSignatureBuilder signature{"Sample Nearest Surface"};
+ signature.single_input<float3>("Position");
+ signature.single_output("Value", src_field_.cpp_type());
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext /*context*/) const override
+ {
+ const VArray<float3> &positions = params.readonly_single_input<float3>(0, "Position");
+ GMutableSpan dst = params.uninitialized_single_output_if_required(1, "Value");
+
+ const MeshComponent &mesh_component = *source_.get_component_for_read<MeshComponent>();
+ BLI_assert(mesh_component.has_mesh());
+ const Mesh &mesh = *mesh_component.get_for_read();
+ BLI_assert(mesh.totpoly > 0);
+
+ /* Find closest points on the mesh surface. */
+ Array<int> looptri_indices(mask.min_array_size());
+ Array<float3> sampled_positions(mask.min_array_size());
+ get_closest_mesh_looptris(mesh, positions, mask, looptri_indices, {}, sampled_positions);
+
+ MeshAttributeInterpolator interp(&mesh, mask, sampled_positions, looptri_indices);
+ interp.sample_data(*source_data_, domain_, eAttributeMapMode::INTERPOLATED, dst);
+ }
+
+ private:
+ void evaluate_source_field()
+ {
+ const Mesh &mesh = *source_.get_mesh_for_read();
+ source_context_.emplace(bke::MeshFieldContext{mesh, domain_});
+ const int domain_size = mesh.attributes().domain_size(domain_);
+ source_evaluator_ = std::make_unique<FieldEvaluator>(*source_context_, domain_size);
+ source_evaluator_->add(src_field_);
+ source_evaluator_->evaluate();
+ source_data_ = &source_evaluator_->get_evaluated(0);
+ }
+};
+
+static GField get_input_attribute_field(GeoNodeExecParams &params, const eCustomDataType data_type)
+{
+ switch (data_type) {
+ case CD_PROP_FLOAT:
+ return params.extract_input<Field<float>>("Value_Float");
+ case CD_PROP_FLOAT3:
+ return params.extract_input<Field<float3>>("Value_Vector");
+ case CD_PROP_COLOR:
+ return params.extract_input<Field<ColorGeometry4f>>("Value_Color");
+ case CD_PROP_BOOL:
+ return params.extract_input<Field<bool>>("Value_Bool");
+ case CD_PROP_INT32:
+ return params.extract_input<Field<int>>("Value_Int");
+ default:
+ BLI_assert_unreachable();
+ }
+ return {};
+}
+
+static void output_attribute_field(GeoNodeExecParams &params, GField field)
+{
+ switch (bke::cpp_type_to_custom_data_type(field.cpp_type())) {
+ case CD_PROP_FLOAT: {
+ params.set_output("Value_Float", Field<float>(field));
+ break;
+ }
+ case CD_PROP_FLOAT3: {
+ params.set_output("Value_Vector", Field<float3>(field));
+ break;
+ }
+ case CD_PROP_COLOR: {
+ params.set_output("Value_Color", Field<ColorGeometry4f>(field));
+ break;
+ }
+ case CD_PROP_BOOL: {
+ params.set_output("Value_Bool", Field<bool>(field));
+ break;
+ }
+ case CD_PROP_INT32: {
+ params.set_output("Value_Int", Field<int>(field));
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry = params.extract_input<GeometrySet>("Mesh");
+ const eCustomDataType data_type = eCustomDataType(params.node().custom1);
+ const Mesh *mesh = geometry.get_mesh_for_read();
+ if (mesh == nullptr) {
+ params.set_default_remaining_outputs();
+ return;
+ }
+ if (mesh->totvert == 0) {
+ params.set_default_remaining_outputs();
+ return;
+ }
+ if (mesh->totpoly == 0) {
+ params.error_message_add(NodeWarningType::Error, TIP_("The source mesh must have faces"));
+ params.set_default_remaining_outputs();
+ return;
+ }
+
+ Field<float3> positions = params.extract_input<Field<float3>>("Sample Position");
+ GField field = get_input_attribute_field(params, data_type);
+ auto fn = std::make_shared<SampleNearestSurfaceFunction>(std::move(geometry), std::move(field));
+ auto op = FieldOperation::Create(std::move(fn), {std::move(positions)});
+ output_attribute_field(params, GField(std::move(op)));
+}
+
+} // namespace blender::nodes::node_geo_sample_nearest_surface_cc
+
+void register_node_type_geo_sample_nearest_surface()
+{
+ namespace file_ns = blender::nodes::node_geo_sample_nearest_surface_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_SAMPLE_NEAREST_SURFACE, "Sample Nearest Surface", NODE_CLASS_GEOMETRY);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.declare = file_ns::node_declare;
+ node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_sample_uv_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_sample_uv_surface.cc
new file mode 100644
index 00000000000..2e8446ba559
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_sample_uv_surface.cc
@@ -0,0 +1,294 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_attribute_math.hh"
+#include "BKE_mesh.h"
+#include "BKE_type_conversions.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "GEO_reverse_uv_sampler.hh"
+
+#include "NOD_socket_search_link.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_sample_uv_surface_cc {
+
+using geometry::ReverseUVSampler;
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
+
+ b.add_input<decl::Float>(N_("Value"), "Value_Float").hide_value().supports_field();
+ b.add_input<decl::Int>(N_("Value"), "Value_Int").hide_value().supports_field();
+ b.add_input<decl::Vector>(N_("Value"), "Value_Vector").hide_value().supports_field();
+ b.add_input<decl::Color>(N_("Value"), "Value_Color").hide_value().supports_field();
+ b.add_input<decl::Bool>(N_("Value"), "Value_Bool").hide_value().supports_field();
+
+ b.add_input<decl::Vector>(N_("Source UV Map"))
+ .hide_value()
+ .supports_field()
+ .description(N_("The mesh UV map to sample. Should not have overlapping faces"));
+ b.add_input<decl::Vector>(N_("Sample UV"))
+ .supports_field()
+ .description(N_("The coordinates to sample within the UV map"));
+
+ b.add_output<decl::Float>(N_("Value"), "Value_Float").dependent_field({7});
+ b.add_output<decl::Int>(N_("Value"), "Value_Int").dependent_field({7});
+ b.add_output<decl::Vector>(N_("Value"), "Value_Vector").dependent_field({7});
+ b.add_output<decl::Color>(N_("Value"), "Value_Color").dependent_field({7});
+ b.add_output<decl::Bool>(N_("Value"), "Value_Bool").dependent_field({7});
+
+ b.add_output<decl::Bool>(N_("Is Valid"))
+ .dependent_field({7})
+ .description(N_("Whether the node could find a single face to sample at the UV coordinate"));
+}
+
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree * /*tree*/, bNode *node)
+{
+ node->custom1 = CD_PROP_FLOAT;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ const eCustomDataType data_type = eCustomDataType(node->custom1);
+
+ bNodeSocket *in_socket_mesh = static_cast<bNodeSocket *>(node->inputs.first);
+ bNodeSocket *in_socket_float = in_socket_mesh->next;
+ bNodeSocket *in_socket_int32 = in_socket_float->next;
+ bNodeSocket *in_socket_vector = in_socket_int32->next;
+ bNodeSocket *in_socket_color4f = in_socket_vector->next;
+ bNodeSocket *in_socket_bool = in_socket_color4f->next;
+
+ nodeSetSocketAvailability(ntree, in_socket_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, in_socket_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, in_socket_color4f, data_type == CD_PROP_COLOR);
+ nodeSetSocketAvailability(ntree, in_socket_bool, data_type == CD_PROP_BOOL);
+ nodeSetSocketAvailability(ntree, in_socket_int32, data_type == CD_PROP_INT32);
+
+ bNodeSocket *out_socket_float = static_cast<bNodeSocket *>(node->outputs.first);
+ bNodeSocket *out_socket_int32 = out_socket_float->next;
+ bNodeSocket *out_socket_vector = out_socket_int32->next;
+ bNodeSocket *out_socket_color4f = out_socket_vector->next;
+ bNodeSocket *out_socket_bool = out_socket_color4f->next;
+
+ nodeSetSocketAvailability(ntree, out_socket_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, out_socket_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, out_socket_color4f, data_type == CD_PROP_COLOR);
+ nodeSetSocketAvailability(ntree, out_socket_bool, data_type == CD_PROP_BOOL);
+ nodeSetSocketAvailability(ntree, out_socket_int32, data_type == CD_PROP_INT32);
+}
+
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ search_link_ops_for_declarations(params, declaration.inputs().take_back(2));
+ search_link_ops_for_declarations(params, declaration.inputs().take_front(1));
+ search_link_ops_for_declarations(params, declaration.outputs().take_back(1));
+
+ const std::optional<eCustomDataType> type = node_data_type_to_custom_data_type(
+ eNodeSocketDatatype(params.other_socket().type));
+ if (type && *type != CD_PROP_STRING) {
+ /* The input and output sockets have the same name. */
+ params.add_item(IFACE_("Value"), [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeSampleUVSurface");
+ node.custom1 = *type;
+ params.update_and_connect_available_socket(node, "Value");
+ });
+ }
+}
+
+class SampleUVSurfaceFunction : public fn::MultiFunction {
+ GeometrySet source_;
+ Field<float2> src_uv_map_field_;
+ GField src_field_;
+
+ /**
+ * Use the most complex domain for now ensuring no information is lost. In the future, it should
+ * be possible to use the most complex domain required by the field inputs, to simplify sampling
+ * and avoid domain conversions.
+ */
+ eAttrDomain domain_ = ATTR_DOMAIN_CORNER;
+
+ fn::MFSignature signature_;
+
+ std::optional<bke::MeshFieldContext> source_context_;
+ std::unique_ptr<FieldEvaluator> source_evaluator_;
+ const GVArray *source_data_;
+ VArraySpan<float2> source_uv_map_;
+
+ std::optional<ReverseUVSampler> reverse_uv_sampler_;
+
+ public:
+ SampleUVSurfaceFunction(GeometrySet geometry, Field<float2> src_uv_map_field, GField src_field)
+ : source_(std::move(geometry)),
+ src_uv_map_field_(std::move(src_uv_map_field)),
+ src_field_(std::move(src_field))
+ {
+ source_.ensure_owns_direct_data();
+ signature_ = this->create_signature();
+ this->set_signature(&signature_);
+ this->evaluate_source();
+ }
+
+ fn::MFSignature create_signature()
+ {
+ blender::fn::MFSignatureBuilder signature{"Sample UV Surface"};
+ signature.single_input<float2>("Sample UV");
+ signature.single_output("Value", src_field_.cpp_type());
+ signature.single_output<bool>("Is Valid");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext /*context*/) const override
+ {
+ const VArray<float2> &sample_uvs = params.readonly_single_input<float2>(0, "Sample UV");
+ GMutableSpan dst = params.uninitialized_single_output_if_required(1, "Value");
+ MutableSpan<bool> valid_dst = params.uninitialized_single_output_if_required<bool>(2,
+ "Is Valid");
+
+ const CPPType &type = src_field_.cpp_type();
+ attribute_math::convert_to_static_type(type, [&](auto dummy) {
+ using T = decltype(dummy);
+ const VArray<T> src_typed = source_data_->typed<T>();
+ MutableSpan<T> dst_typed = dst.typed<T>();
+ for (const int i : mask) {
+ const float2 sample_uv = sample_uvs[i];
+ const ReverseUVSampler::Result result = reverse_uv_sampler_->sample(sample_uv);
+ const bool valid = result.type == ReverseUVSampler::ResultType::Ok;
+ if (!dst_typed.is_empty()) {
+ if (valid) {
+ dst_typed[i] = attribute_math::mix3(result.bary_weights,
+ src_typed[result.looptri->tri[0]],
+ src_typed[result.looptri->tri[1]],
+ src_typed[result.looptri->tri[2]]);
+ }
+ else {
+ dst_typed[i] = {};
+ }
+ }
+ if (!valid_dst.is_empty()) {
+ valid_dst[i] = valid;
+ }
+ }
+ });
+ }
+
+ private:
+ void evaluate_source()
+ {
+ const Mesh &mesh = *source_.get_mesh_for_read();
+ source_context_.emplace(bke::MeshFieldContext{mesh, domain_});
+ const int domain_size = mesh.attributes().domain_size(domain_);
+ source_evaluator_ = std::make_unique<FieldEvaluator>(*source_context_, domain_size);
+ source_evaluator_->add(src_uv_map_field_);
+ source_evaluator_->add(src_field_);
+ source_evaluator_->evaluate();
+ source_uv_map_ = source_evaluator_->get_evaluated<float2>(0);
+ source_data_ = &source_evaluator_->get_evaluated(1);
+
+ reverse_uv_sampler_.emplace(source_uv_map_, mesh.looptris());
+ }
+};
+
+static GField get_input_attribute_field(GeoNodeExecParams &params, const eCustomDataType data_type)
+{
+ switch (data_type) {
+ case CD_PROP_FLOAT:
+ return params.extract_input<Field<float>>("Value_Float");
+ case CD_PROP_FLOAT3:
+ return params.extract_input<Field<float3>>("Value_Vector");
+ case CD_PROP_COLOR:
+ return params.extract_input<Field<ColorGeometry4f>>("Value_Color");
+ case CD_PROP_BOOL:
+ return params.extract_input<Field<bool>>("Value_Bool");
+ case CD_PROP_INT32:
+ return params.extract_input<Field<int>>("Value_Int");
+ default:
+ BLI_assert_unreachable();
+ }
+ return {};
+}
+
+static void output_attribute_field(GeoNodeExecParams &params, GField field)
+{
+ switch (bke::cpp_type_to_custom_data_type(field.cpp_type())) {
+ case CD_PROP_FLOAT: {
+ params.set_output("Value_Float", Field<float>(field));
+ break;
+ }
+ case CD_PROP_FLOAT3: {
+ params.set_output("Value_Vector", Field<float3>(field));
+ break;
+ }
+ case CD_PROP_COLOR: {
+ params.set_output("Value_Color", Field<ColorGeometry4f>(field));
+ break;
+ }
+ case CD_PROP_BOOL: {
+ params.set_output("Value_Bool", Field<bool>(field));
+ break;
+ }
+ case CD_PROP_INT32: {
+ params.set_output("Value_Int", Field<int>(field));
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry = params.extract_input<GeometrySet>("Mesh");
+ const eCustomDataType data_type = eCustomDataType(params.node().custom1);
+ const Mesh *mesh = geometry.get_mesh_for_read();
+ if (mesh == nullptr) {
+ params.set_default_remaining_outputs();
+ return;
+ }
+ if (mesh->totpoly == 0 && mesh->totvert != 0) {
+ params.error_message_add(NodeWarningType::Error, TIP_("The source mesh must have faces"));
+ params.set_default_remaining_outputs();
+ return;
+ }
+
+ const CPPType &float2_type = CPPType::get<float2>();
+
+ const bke::DataTypeConversions &conversions = bke::get_implicit_type_conversions();
+ Field<float2> source_uv_map = conversions.try_convert(
+ params.extract_input<Field<float3>>("Source UV Map"), float2_type);
+ GField field = get_input_attribute_field(params, data_type);
+ Field<float2> sample_uvs = conversions.try_convert(
+ params.extract_input<Field<float3>>("Sample UV"), float2_type);
+ auto fn = std::make_shared<SampleUVSurfaceFunction>(
+ std::move(geometry), std::move(source_uv_map), std::move(field));
+ auto op = FieldOperation::Create(std::move(fn), {std::move(sample_uvs)});
+ output_attribute_field(params, GField(op, 0));
+ params.set_output("Is Valid", Field<bool>(op, 1));
+}
+
+} // namespace blender::nodes::node_geo_sample_uv_surface_cc
+
+void register_node_type_geo_sample_uv_surface()
+{
+ namespace file_ns = blender::nodes::node_geo_sample_uv_surface_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_SAMPLE_UV_SURFACE, "Sample UV Surface", NODE_CLASS_GEOMETRY);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc
index d674f611c9f..5f1baa23511 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc
@@ -25,7 +25,7 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Float>(N_("Scale"), "Scale").default_value(1.0f).min(0.0f).supports_field();
b.add_input<decl::Vector>(N_("Center"))
.subtype(PROP_TRANSLATION)
- .implicit_field()
+ .implicit_field(implicit_field_inputs::position)
.description(N_("Origin of the scaling for each element. If multiple elements are "
"connected, their center is averaged"));
b.add_input<decl::Vector>(N_("Axis"))
@@ -36,13 +36,13 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
};
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
uiItemR(layout, ptr, "scale_mode", 0, "", ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
node->custom1 = ATTR_DOMAIN_FACE;
node->custom2 = GEO_NODE_SCALE_ELEMENTS_UNIFORM;
@@ -56,8 +56,7 @@ static void node_update(bNodeTree *ntree, bNode *node)
bNodeSocket *center_socket = scale_float_socket->next;
bNodeSocket *axis_socket = center_socket->next;
- const GeometryNodeScaleElementsMode mode = static_cast<GeometryNodeScaleElementsMode>(
- node->custom2);
+ const GeometryNodeScaleElementsMode mode = GeometryNodeScaleElementsMode(node->custom2);
const bool use_single_axis = mode == GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS;
nodeSetSocketAvailability(ntree, axis_socket, use_single_axis);
@@ -147,14 +146,22 @@ static float4x4 create_single_axis_transform(const float3 &center,
return transform;
}
-using GetVertexIndicesFn =
- FunctionRef<void(const Mesh &mesh, int element_index, VectorSet<int> &r_vertex_indices)>;
+using GetVertexIndicesFn = FunctionRef<void(Span<MEdge> edges,
+ Span<MPoly> polys,
+ Span<MLoop> loops,
+ int element_index,
+ VectorSet<int> &r_vertex_indices)>;
static void scale_vertex_islands_uniformly(Mesh &mesh,
const Span<ElementIsland> islands,
const UniformScaleParams &params,
const GetVertexIndicesFn get_vertex_indices)
{
+ MutableSpan<MVert> verts = mesh.verts_for_write();
+ const Span<MEdge> edges = mesh.edges();
+ const Span<MPoly> polys = mesh.polys();
+ const Span<MLoop> loops = mesh.loops();
+
threading::parallel_for(islands.index_range(), 256, [&](const IndexRange range) {
for (const int island_index : range) {
const ElementIsland &island = islands[island_index];
@@ -164,7 +171,7 @@ static void scale_vertex_islands_uniformly(Mesh &mesh,
VectorSet<int> vertex_indices;
for (const int poly_index : island.element_indices) {
- get_vertex_indices(mesh, poly_index, vertex_indices);
+ get_vertex_indices(edges, polys, loops, poly_index, vertex_indices);
center += params.centers[poly_index];
scale += params.scales[poly_index];
}
@@ -175,7 +182,7 @@ static void scale_vertex_islands_uniformly(Mesh &mesh,
center *= f;
for (const int vert_index : vertex_indices) {
- MVert &vert = mesh.mvert[vert_index];
+ MVert &vert = verts[vert_index];
const float3 old_position = vert.co;
const float3 new_position = transform_with_uniform_scale(old_position, center, scale);
copy_v3_v3(vert.co, new_position);
@@ -191,6 +198,11 @@ static void scale_vertex_islands_on_axis(Mesh &mesh,
const AxisScaleParams &params,
const GetVertexIndicesFn get_vertex_indices)
{
+ MutableSpan<MVert> verts = mesh.verts_for_write();
+ const Span<MEdge> edges = mesh.edges();
+ const Span<MPoly> polys = mesh.polys();
+ const Span<MLoop> loops = mesh.loops();
+
threading::parallel_for(islands.index_range(), 256, [&](const IndexRange range) {
for (const int island_index : range) {
const ElementIsland &island = islands[island_index];
@@ -201,7 +213,7 @@ static void scale_vertex_islands_on_axis(Mesh &mesh,
VectorSet<int> vertex_indices;
for (const int poly_index : island.element_indices) {
- get_vertex_indices(mesh, poly_index, vertex_indices);
+ get_vertex_indices(edges, polys, loops, poly_index, vertex_indices);
center += params.centers[poly_index];
scale += params.scales[poly_index];
axis += params.axis_vectors[poly_index];
@@ -219,7 +231,7 @@ static void scale_vertex_islands_on_axis(Mesh &mesh,
const float4x4 transform = create_single_axis_transform(center, axis, scale);
for (const int vert_index : vertex_indices) {
- MVert &vert = mesh.mvert[vert_index];
+ MVert &vert = verts[vert_index];
const float3 old_position = vert.co;
const float3 new_position = transform * old_position;
copy_v3_v3(vert.co, new_position);
@@ -232,11 +244,14 @@ static void scale_vertex_islands_on_axis(Mesh &mesh,
static Vector<ElementIsland> prepare_face_islands(const Mesh &mesh, const IndexMask face_selection)
{
+ const Span<MPoly> polys = mesh.polys();
+ const Span<MLoop> loops = mesh.loops();
+
/* Use the disjoint set data structure to determine which vertices have to be scaled together. */
DisjointSet disjoint_set(mesh.totvert);
for (const int poly_index : face_selection) {
- const MPoly &poly = mesh.mpoly[poly_index];
- const Span<MLoop> poly_loops{mesh.mloop + poly.loopstart, poly.totloop};
+ const MPoly &poly = polys[poly_index];
+ const Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
for (const int loop_index : IndexRange(poly.totloop - 1)) {
const int v1 = poly_loops[loop_index].v;
const int v2 = poly_loops[loop_index + 1].v;
@@ -252,8 +267,8 @@ static Vector<ElementIsland> prepare_face_islands(const Mesh &mesh, const IndexM
/* Gather all of the face indices in each island into separate vectors. */
for (const int poly_index : face_selection) {
- const MPoly &poly = mesh.mpoly[poly_index];
- const Span<MLoop> poly_loops{mesh.mloop + poly.loopstart, poly.totloop};
+ const MPoly &poly = polys[poly_index];
+ const Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
const int island_id = disjoint_set.find_root(poly_loops[0].v);
const int island_index = island_ids.index_of_or_add(island_id);
if (island_index == islands.size()) {
@@ -266,10 +281,14 @@ static Vector<ElementIsland> prepare_face_islands(const Mesh &mesh, const IndexM
return islands;
}
-static void get_face_vertices(const Mesh &mesh, int face_index, VectorSet<int> &r_vertex_indices)
+static void get_face_verts(const Span<MEdge> /*edges*/,
+ const Span<MPoly> polys,
+ const Span<MLoop> loops,
+ int face_index,
+ VectorSet<int> &r_vertex_indices)
{
- const MPoly &poly = mesh.mpoly[face_index];
- const Span<MLoop> poly_loops{mesh.mloop + poly.loopstart, poly.totloop};
+ const MPoly &poly = polys[face_index];
+ const Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
for (const MLoop &loop : poly_loops) {
r_vertex_indices.add(loop.v);
}
@@ -288,18 +307,14 @@ static AxisScaleParams evaluate_axis_scale_fields(FieldEvaluator &evaluator,
return out;
}
-static void scale_faces_on_axis(MeshComponent &mesh_component, const AxisScaleFields &fields)
+static void scale_faces_on_axis(Mesh &mesh, const AxisScaleFields &fields)
{
- Mesh &mesh = *mesh_component.get_for_write();
- mesh.mvert = static_cast<MVert *>(
- CustomData_duplicate_referenced_layer(&mesh.vdata, CD_MVERT, mesh.totvert));
-
- GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_FACE};
+ bke::MeshFieldContext field_context{mesh, ATTR_DOMAIN_FACE};
FieldEvaluator evaluator{field_context, mesh.totpoly};
AxisScaleParams params = evaluate_axis_scale_fields(evaluator, fields);
Vector<ElementIsland> island = prepare_face_islands(mesh, params.selection);
- scale_vertex_islands_on_axis(mesh, island, params, get_face_vertices);
+ scale_vertex_islands_on_axis(mesh, island, params, get_face_verts);
}
static UniformScaleParams evaluate_uniform_scale_fields(FieldEvaluator &evaluator,
@@ -314,26 +329,24 @@ static UniformScaleParams evaluate_uniform_scale_fields(FieldEvaluator &evaluato
return out;
}
-static void scale_faces_uniformly(MeshComponent &mesh_component, const UniformScaleFields &fields)
+static void scale_faces_uniformly(Mesh &mesh, const UniformScaleFields &fields)
{
- Mesh &mesh = *mesh_component.get_for_write();
- mesh.mvert = static_cast<MVert *>(
- CustomData_duplicate_referenced_layer(&mesh.vdata, CD_MVERT, mesh.totvert));
-
- GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_FACE};
+ bke::MeshFieldContext field_context{mesh, ATTR_DOMAIN_FACE};
FieldEvaluator evaluator{field_context, mesh.totpoly};
UniformScaleParams params = evaluate_uniform_scale_fields(evaluator, fields);
Vector<ElementIsland> island = prepare_face_islands(mesh, params.selection);
- scale_vertex_islands_uniformly(mesh, island, params, get_face_vertices);
+ scale_vertex_islands_uniformly(mesh, island, params, get_face_verts);
}
static Vector<ElementIsland> prepare_edge_islands(const Mesh &mesh, const IndexMask edge_selection)
{
+ const Span<MEdge> edges = mesh.edges();
+
/* Use the disjoint set data structure to determine which vertices have to be scaled together. */
DisjointSet disjoint_set(mesh.totvert);
for (const int edge_index : edge_selection) {
- const MEdge &edge = mesh.medge[edge_index];
+ const MEdge &edge = edges[edge_index];
disjoint_set.join(edge.v1, edge.v2);
}
@@ -344,7 +357,7 @@ static Vector<ElementIsland> prepare_edge_islands(const Mesh &mesh, const IndexM
/* Gather all of the edge indices in each island into separate vectors. */
for (const int edge_index : edge_selection) {
- const MEdge &edge = mesh.medge[edge_index];
+ const MEdge &edge = edges[edge_index];
const int island_id = disjoint_set.find_root(edge.v1);
const int island_index = island_ids.index_of_or_add(island_id);
if (island_index == islands.size()) {
@@ -357,47 +370,42 @@ static Vector<ElementIsland> prepare_edge_islands(const Mesh &mesh, const IndexM
return islands;
}
-static void get_edge_vertices(const Mesh &mesh, int edge_index, VectorSet<int> &r_vertex_indices)
+static void get_edge_verts(const Span<MEdge> edges,
+ const Span<MPoly> /*polys*/,
+ const Span<MLoop> /*loops*/,
+ int edge_index,
+ VectorSet<int> &r_vertex_indices)
{
- const MEdge &edge = mesh.medge[edge_index];
+ const MEdge &edge = edges[edge_index];
r_vertex_indices.add(edge.v1);
r_vertex_indices.add(edge.v2);
}
-static void scale_edges_uniformly(MeshComponent &mesh_component, const UniformScaleFields &fields)
+static void scale_edges_uniformly(Mesh &mesh, const UniformScaleFields &fields)
{
- Mesh &mesh = *mesh_component.get_for_write();
- mesh.mvert = static_cast<MVert *>(
- CustomData_duplicate_referenced_layer(&mesh.vdata, CD_MVERT, mesh.totvert));
-
- GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_EDGE};
+ bke::MeshFieldContext field_context{mesh, ATTR_DOMAIN_EDGE};
FieldEvaluator evaluator{field_context, mesh.totedge};
UniformScaleParams params = evaluate_uniform_scale_fields(evaluator, fields);
Vector<ElementIsland> island = prepare_edge_islands(mesh, params.selection);
- scale_vertex_islands_uniformly(mesh, island, params, get_edge_vertices);
+ scale_vertex_islands_uniformly(mesh, island, params, get_edge_verts);
}
-static void scale_edges_on_axis(MeshComponent &mesh_component, const AxisScaleFields &fields)
+static void scale_edges_on_axis(Mesh &mesh, const AxisScaleFields &fields)
{
- Mesh &mesh = *mesh_component.get_for_write();
- mesh.mvert = static_cast<MVert *>(
- CustomData_duplicate_referenced_layer(&mesh.vdata, CD_MVERT, mesh.totvert));
-
- GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_EDGE};
+ bke::MeshFieldContext field_context{mesh, ATTR_DOMAIN_EDGE};
FieldEvaluator evaluator{field_context, mesh.totedge};
AxisScaleParams params = evaluate_axis_scale_fields(evaluator, fields);
Vector<ElementIsland> island = prepare_edge_islands(mesh, params.selection);
- scale_vertex_islands_on_axis(mesh, island, params, get_edge_vertices);
+ scale_vertex_islands_on_axis(mesh, island, params, get_edge_verts);
}
static void node_geo_exec(GeoNodeExecParams params)
{
const bNode &node = params.node();
- const eAttrDomain domain = static_cast<eAttrDomain>(node.custom1);
- const GeometryNodeScaleElementsMode scale_mode = static_cast<GeometryNodeScaleElementsMode>(
- node.custom2);
+ const eAttrDomain domain = eAttrDomain(node.custom1);
+ const GeometryNodeScaleElementsMode scale_mode = GeometryNodeScaleElementsMode(node.custom2);
GeometrySet geometry = params.extract_input<GeometrySet>("Geometry");
@@ -410,42 +418,38 @@ static void node_geo_exec(GeoNodeExecParams params)
}
geometry.modify_geometry_sets([&](GeometrySet &geometry) {
- if (!geometry.has_mesh()) {
- return;
- }
- MeshComponent &mesh_component = geometry.get_component_for_write<MeshComponent>();
- switch (domain) {
- case ATTR_DOMAIN_FACE: {
- switch (scale_mode) {
- case GEO_NODE_SCALE_ELEMENTS_UNIFORM: {
- scale_faces_uniformly(mesh_component, {selection_field, scale_field, center_field});
- break;
- }
- case GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS: {
- scale_faces_on_axis(mesh_component,
- {selection_field, scale_field, center_field, axis_field});
- break;
+ if (Mesh *mesh = geometry.get_mesh_for_write()) {
+ switch (domain) {
+ case ATTR_DOMAIN_FACE: {
+ switch (scale_mode) {
+ case GEO_NODE_SCALE_ELEMENTS_UNIFORM: {
+ scale_faces_uniformly(*mesh, {selection_field, scale_field, center_field});
+ break;
+ }
+ case GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS: {
+ scale_faces_on_axis(*mesh, {selection_field, scale_field, center_field, axis_field});
+ break;
+ }
}
+ break;
}
- break;
- }
- case ATTR_DOMAIN_EDGE: {
- switch (scale_mode) {
- case GEO_NODE_SCALE_ELEMENTS_UNIFORM: {
- scale_edges_uniformly(mesh_component, {selection_field, scale_field, center_field});
- break;
- }
- case GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS: {
- scale_edges_on_axis(mesh_component,
- {selection_field, scale_field, center_field, axis_field});
- break;
+ case ATTR_DOMAIN_EDGE: {
+ switch (scale_mode) {
+ case GEO_NODE_SCALE_ELEMENTS_UNIFORM: {
+ scale_edges_uniformly(*mesh, {selection_field, scale_field, center_field});
+ break;
+ }
+ case GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS: {
+ scale_edges_on_axis(*mesh, {selection_field, scale_field, center_field, axis_field});
+ break;
+ }
}
+ break;
}
- break;
+ default:
+ BLI_assert_unreachable();
+ break;
}
- default:
- BLI_assert_unreachable();
- break;
}
});
diff --git a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
index 7156feb37d7..dacb130337f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
@@ -2,6 +2,8 @@
#include "BLI_task.hh"
+#include "BKE_instances.hh"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_scale_instances_cc {
@@ -19,11 +21,10 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Instances"));
}
-static void scale_instances(GeoNodeExecParams &params, InstancesComponent &instances_component)
+static void scale_instances(GeoNodeExecParams &params, bke::Instances &instances)
{
- GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE};
-
- fn::FieldEvaluator evaluator{field_context, instances_component.instances_num()};
+ const bke::InstancesFieldContext context{instances};
+ fn::FieldEvaluator evaluator{context, instances.instances_num()};
evaluator.set_selection(params.extract_input<Field<bool>>("Selection"));
evaluator.add(params.extract_input<Field<float3>>("Scale"));
evaluator.add(params.extract_input<Field<float3>>("Center"));
@@ -35,13 +36,13 @@ static void scale_instances(GeoNodeExecParams &params, InstancesComponent &insta
const VArray<float3> pivots = evaluator.get_evaluated<float3>(1);
const VArray<bool> local_spaces = evaluator.get_evaluated<bool>(2);
- MutableSpan<float4x4> instance_transforms = instances_component.instance_transforms();
+ MutableSpan<float4x4> transforms = instances.transforms();
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
for (const int i_selection : range) {
const int i = selection[i_selection];
const float3 pivot = pivots[i];
- float4x4 &instance_transform = instance_transforms[i];
+ float4x4 &instance_transform = transforms[i];
if (local_spaces[i]) {
instance_transform *= float4x4::from_location(pivot);
@@ -62,9 +63,8 @@ static void scale_instances(GeoNodeExecParams &params, InstancesComponent &insta
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances");
- if (geometry_set.has_instances()) {
- InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
- scale_instances(params, instances);
+ if (bke::Instances *instances = geometry_set.get_instances_for_write()) {
+ scale_instances(params, *instances);
}
params.set_output("Instances", std::move(geometry_set));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_self_object.cc b/source/blender/nodes/geometry/nodes/node_geo_self_object.cc
new file mode 100644
index 00000000000..7b33afdb4a0
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_self_object.cc
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_self_object_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Object>(N_("Self Object"));
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ params.set_output("Self Object", const_cast<Object *>(params.self_object()));
+}
+
+} // namespace blender::nodes::node_geo_self_object_cc
+
+void register_node_type_geo_self_object()
+{
+ namespace file_ns = blender::nodes::node_geo_self_object_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_SELF_OBJECT, "Self Object", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
index d785694f253..44d12466d9e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
@@ -23,12 +23,12 @@ static void node_declare(NodeDeclarationBuilder &b)
.description(N_("The parts of the geometry not in the selection"));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometrySeparateGeometry *data = MEM_cnew<NodeGeometrySeparateGeometry>(__func__);
data->domain = ATTR_DOMAIN_POINT;
@@ -43,7 +43,7 @@ static void node_geo_exec(GeoNodeExecParams params)
const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
const NodeGeometrySeparateGeometry &storage = node_storage(params.node());
- const eAttrDomain domain = static_cast<eAttrDomain>(storage.domain);
+ const eAttrDomain domain = eAttrDomain(storage.domain);
auto separate_geometry_maybe_recursively = [&](GeometrySet &geometry_set,
const Field<bool> &selection) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
index fc3cb7006bb..c143203337a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
@@ -17,17 +17,21 @@ static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
- b.add_input<decl::Vector>(N_("Position")).implicit_field();
+ b.add_input<decl::Vector>(N_("Position")).implicit_field([](const bNode &node, void *r_value) {
+ const StringRef side = node_storage(node).mode == GEO_NODE_CURVE_HANDLE_LEFT ? "handle_left" :
+ "handle_right";
+ new (r_value) ValueOrField<float3>(bke::AttributeFieldInput::Create<float3>(side));
+ });
b.add_input<decl::Vector>(N_("Offset")).default_value(float3(0.0f, 0.0f, 0.0f)).supports_field();
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometrySetCurveHandlePositions *data = MEM_cnew<NodeGeometrySetCurveHandlePositions>(
__func__);
@@ -68,19 +72,18 @@ static void update_handle_types_for_movement(int8_t &type, int8_t &other)
}
}
-static void set_position_in_component(CurveComponent &component,
+static void set_position_in_component(bke::CurvesGeometry &curves,
const GeometryNodeCurveHandleMode mode,
const Field<bool> &selection_field,
const Field<float3> &position_field,
const Field<float3> &offset_field)
{
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
- if (domain_size == 0) {
+ if (curves.points_num() == 0) {
return;
}
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ bke::CurvesFieldContext field_context{curves, ATTR_DOMAIN_POINT};
+ fn::FieldEvaluator evaluator{field_context, curves.points_num()};
evaluator.set_selection(selection_field);
evaluator.add(position_field);
evaluator.add(offset_field);
@@ -89,9 +92,6 @@ static void set_position_in_component(CurveComponent &component,
const VArray<float3> new_positions = evaluator.get_evaluated<float3>(0);
const VArray<float3> new_offsets = evaluator.get_evaluated<float3>(1);
- Curves &curves_id = *component.get_for_write();
- bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
-
Span<float3> positions = curves.positions();
const bool use_left = mode == GEO_NODE_CURVE_HANDLE_LEFT;
@@ -141,22 +141,17 @@ static void node_geo_exec(GeoNodeExecParams params)
std::atomic<bool> has_bezier = false;
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (!geometry_set.has_curves()) {
- return;
- }
- has_curves = true;
- const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
- const AttributeAccessor attributes = *component.attributes();
- if (!attributes.contains("handle_left") || !attributes.contains("handle_right")) {
- return;
- }
- has_bezier = true;
+ if (Curves *curves_id = geometry_set.get_curves_for_write()) {
+ bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
+ has_curves = true;
+ const AttributeAccessor attributes = curves.attributes();
+ if (!attributes.contains("handle_left") || !attributes.contains("handle_right")) {
+ return;
+ }
+ has_bezier = true;
- set_position_in_component(geometry_set.get_component_for_write<CurveComponent>(),
- mode,
- selection_field,
- position_field,
- offset_field);
+ set_position_in_component(curves, mode, selection_field, position_field, offset_field);
+ }
});
if (has_curves && !has_bezier) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_normal.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_normal.cc
new file mode 100644
index 00000000000..e2169966f5a
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_normal.cc
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_curves.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_set_curve_normal_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_output<decl::Geometry>(N_("Curve"));
+}
+
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree * /*tree*/, bNode *node)
+{
+ node->custom1 = NORMAL_MODE_MINIMUM_TWIST;
+}
+
+static void set_normal_mode(bke::CurvesGeometry &curves,
+ const NormalMode mode,
+ const Field<bool> &selection_field)
+{
+ bke::CurvesFieldContext field_context{curves, ATTR_DOMAIN_CURVE};
+ fn::FieldEvaluator evaluator{field_context, curves.curves_num()};
+ evaluator.set_selection(selection_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ curves.normal_mode_for_write().fill_indices(selection, mode);
+ curves.tag_normals_changed();
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const NormalMode mode = static_cast<NormalMode>(params.node().custom1);
+
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
+ Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (Curves *curves_id = geometry_set.get_curves_for_write()) {
+ bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
+ set_normal_mode(curves, mode, selection_field);
+ }
+ });
+
+ params.set_output("Curve", std::move(geometry_set));
+}
+
+} // namespace blender::nodes::node_geo_set_curve_normal_cc
+
+void register_node_type_geo_set_curve_normal()
+{
+ namespace file_ns = blender::nodes::node_geo_set_curve_normal_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_SET_CURVE_NORMAL, "Set Curve Normal", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
+ ntype.draw_buttons = file_ns::node_layout;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc
index e4fae95b5a5..0d361090068 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc
@@ -1,5 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "BKE_curves.hh"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_set_curve_radius_cc {
@@ -16,21 +18,19 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void set_radius_in_component(GeometryComponent &component,
- const Field<bool> &selection_field,
- const Field<float> &radius_field)
+static void set_radius(bke::CurvesGeometry &curves,
+ const Field<bool> &selection_field,
+ const Field<float> &radius_field)
{
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
- if (domain_size == 0) {
+ if (curves.points_num() == 0) {
return;
}
- MutableAttributeAccessor attributes = *component.attributes_for_write();
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
-
+ MutableAttributeAccessor attributes = curves.attributes_for_write();
AttributeWriter<float> radii = attributes.lookup_or_add_for_write<float>("radius",
ATTR_DOMAIN_POINT);
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ bke::CurvesFieldContext field_context{curves, ATTR_DOMAIN_POINT};
+ fn::FieldEvaluator evaluator{field_context, curves.points_num()};
evaluator.set_selection(selection_field);
evaluator.add_with_destination(radius_field, radii.varray);
evaluator.evaluate();
@@ -45,9 +45,8 @@ static void node_geo_exec(GeoNodeExecParams params)
Field<float> radii_field = params.extract_input<Field<float>>("Radius");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (geometry_set.has_curves()) {
- set_radius_in_component(
- geometry_set.get_component_for_write<CurveComponent>(), selection_field, radii_field);
+ if (Curves *curves_id = geometry_set.get_curves_for_write()) {
+ set_radius(bke::CurvesGeometry::wrap(curves_id->geometry), selection_field, radii_field);
}
});
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc
index 2211ac62727..8c1fb883f46 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc
@@ -1,5 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "BKE_curves.hh"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_set_curve_tilt_cc {
@@ -12,22 +14,19 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void set_tilt_in_component(GeometryComponent &component,
- const Field<bool> &selection_field,
- const Field<float> &tilt_field)
+static void set_tilt(bke::CurvesGeometry &curves,
+ const Field<bool> &selection_field,
+ const Field<float> &tilt_field)
{
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
- if (domain_size == 0) {
+ if (curves.points_num() == 0) {
return;
}
- MutableAttributeAccessor attributes = *component.attributes_for_write();
-
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
-
+ MutableAttributeAccessor attributes = curves.attributes_for_write();
AttributeWriter<float> tilts = attributes.lookup_or_add_for_write<float>("tilt",
ATTR_DOMAIN_POINT);
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ bke::CurvesFieldContext field_context{curves, ATTR_DOMAIN_POINT};
+ fn::FieldEvaluator evaluator{field_context, curves.points_num()};
evaluator.set_selection(selection_field);
evaluator.add_with_destination(tilt_field, tilts.varray);
evaluator.evaluate();
@@ -42,9 +41,8 @@ static void node_geo_exec(GeoNodeExecParams params)
Field<float> tilt_field = params.extract_input<Field<float>>("Tilt");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (geometry_set.has_curves()) {
- set_tilt_in_component(
- geometry_set.get_component_for_write<CurveComponent>(), selection_field, tilt_field);
+ if (Curves *curves_id = geometry_set.get_curves_for_write()) {
+ set_tilt(bke::CurvesGeometry::wrap(curves_id->geometry), selection_field, tilt_field);
}
});
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
index fbb2ecbb799..e308371b1c2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
@@ -8,7 +8,7 @@ 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();
- b.add_input<decl::Int>(N_("ID")).implicit_field();
+ b.add_input<decl::Int>(N_("ID")).implicit_field(implicit_field_inputs::index);
b.add_output<decl::Geometry>(N_("Geometry"));
}
@@ -24,7 +24,7 @@ static void set_id_in_component(GeometryComponent &component,
return;
}
MutableAttributeAccessor attributes = *component.attributes_for_write();
- GeometryComponentFieldContext field_context{component, domain};
+ bke::GeometryFieldContext field_context{component, domain};
fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.set_selection(selection_field);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_material.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc
index 507c6e81b1f..8d00d82664b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_material.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc
@@ -12,6 +12,7 @@
#include "DNA_volume_types.h"
#include "BKE_material.h"
+#include "BKE_mesh.h"
namespace blender::nodes::node_geo_set_material_cc {
@@ -49,11 +50,11 @@ static void assign_material_to_faces(Mesh &mesh, const IndexMask selection, Mate
BKE_id_material_eval_assign(&mesh.id, new_material_index + 1, material);
}
- mesh.mpoly = (MPoly *)CustomData_duplicate_referenced_layer(&mesh.pdata, CD_MPOLY, mesh.totpoly);
- for (const int i : selection) {
- MPoly &poly = mesh.mpoly[i];
- poly.mat_nr = new_material_index;
- }
+ MutableAttributeAccessor attributes = mesh.attributes_for_write();
+ SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_span<int>(
+ "material_index", ATTR_DOMAIN_FACE);
+ material_indices.span.fill_indices(selection, new_material_index);
+ material_indices.finish();
}
static void node_geo_exec(GeoNodeExecParams params)
@@ -72,8 +73,8 @@ static void node_geo_exec(GeoNodeExecParams params)
if (geometry_set.has_mesh()) {
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
Mesh &mesh = *mesh_component.get_for_write();
- GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_FACE};
+ bke::MeshFieldContext field_context{mesh, ATTR_DOMAIN_FACE};
fn::FieldEvaluator selection_evaluator{field_context, mesh.totpoly};
selection_evaluator.add(selection_field);
selection_evaluator.evaluate();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc
index 0dc89bb7ef4..bb9ac9b5d4c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc
@@ -14,21 +14,23 @@ static void node_declare(NodeDeclarationBuilder &b)
static void set_material_index_in_component(GeometryComponent &component,
const Field<bool> &selection_field,
- const Field<int> &index_field)
+ const Field<int> &index_field,
+ const eAttrDomain domain)
{
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
+ const int domain_size = component.attribute_domain_size(domain);
if (domain_size == 0) {
return;
}
MutableAttributeAccessor attributes = *component.attributes_for_write();
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE};
+ bke::GeometryFieldContext field_context{component, domain};
- AttributeWriter<int> indices = attributes.lookup_or_add_for_write<int>("material_index",
- ATTR_DOMAIN_FACE);
+ const bke::AttributeValidator validator = attributes.lookup_validator("material_index");
+ AttributeWriter<int> indices = attributes.lookup_or_add_for_write<int>("material_index", domain);
fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.set_selection(selection_field);
- evaluator.add_with_destination(index_field, indices.varray);
+ evaluator.add_with_destination(validator.validate_field_if_necessary(index_field),
+ indices.varray);
evaluator.evaluate();
indices.finish();
}
@@ -41,8 +43,10 @@ static void node_geo_exec(GeoNodeExecParams params)
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
if (geometry_set.has_mesh()) {
- set_material_index_in_component(
- geometry_set.get_component_for_write<MeshComponent>(), selection_field, index_field);
+ set_material_index_in_component(geometry_set.get_component_for_write<MeshComponent>(),
+ selection_field,
+ index_field,
+ ATTR_DOMAIN_FACE);
}
});
params.set_output("Geometry", std::move(geometry_set));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc
index da7977a4fb4..28d07b31218 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc
@@ -1,5 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "DNA_pointcloud_types.h"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_set_point_radius_cc {
@@ -16,21 +18,19 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Points"));
}
-static void set_radius_in_component(GeometryComponent &component,
+static void set_radius_in_component(PointCloud &pointcloud,
const Field<bool> &selection_field,
const Field<float> &radius_field)
{
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
- if (domain_size == 0) {
+ if (pointcloud.totpoint == 0) {
return;
}
- MutableAttributeAccessor attributes = *component.attributes_for_write();
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
-
+ MutableAttributeAccessor attributes = pointcloud.attributes_for_write();
AttributeWriter<float> radii = attributes.lookup_or_add_for_write<float>("radius",
ATTR_DOMAIN_POINT);
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ bke::PointCloudFieldContext field_context{pointcloud};
+ fn::FieldEvaluator evaluator{field_context, pointcloud.totpoint};
evaluator.set_selection(selection_field);
evaluator.add_with_destination(radius_field, radii.varray);
evaluator.evaluate();
@@ -45,10 +45,8 @@ static void node_geo_exec(GeoNodeExecParams params)
Field<float> radii_field = params.extract_input<Field<float>>("Radius");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (geometry_set.has_pointcloud()) {
- set_radius_in_component(geometry_set.get_component_for_write<PointCloudComponent>(),
- selection_field,
- radii_field);
+ if (PointCloud *pointcloud = geometry_set.get_pointcloud_for_write()) {
+ set_radius_in_component(*pointcloud, selection_field, radii_field);
}
});
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
index 880252de4fa..e243fe3614c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
@@ -8,6 +8,7 @@
#include "DNA_meshdata_types.h"
#include "BKE_curves.hh"
+#include "BKE_mesh.h"
#include "node_geometry_util.hh"
@@ -17,7 +18,7 @@ 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();
- b.add_input<decl::Vector>(N_("Position")).implicit_field();
+ b.add_input<decl::Vector>(N_("Position")).implicit_field(implicit_field_inputs::position);
b.add_input<decl::Vector>(N_("Offset")).supports_field().subtype(PROP_TRANSLATION);
b.add_output<decl::Geometry>(N_("Geometry"));
}
@@ -35,14 +36,14 @@ static void set_computed_position_and_offset(GeometryComponent &component,
switch (component.type()) {
case GEO_COMPONENT_TYPE_MESH: {
Mesh *mesh = static_cast<MeshComponent &>(component).get_for_write();
- MutableSpan<MVert> mverts{mesh->mvert, mesh->totvert};
+ MutableSpan<MVert> verts = mesh->verts_for_write();
if (in_positions.is_same(positions.varray)) {
devirtualize_varray(in_offsets, [&](const auto in_offsets) {
threading::parallel_for(
selection.index_range(), grain_size, [&](const IndexRange range) {
for (const int i : selection.slice(range)) {
const float3 offset = in_offsets[i];
- add_v3_v3(mverts[i].co, offset);
+ add_v3_v3(verts[i].co, offset);
}
});
});
@@ -54,7 +55,7 @@ static void set_computed_position_and_offset(GeometryComponent &component,
selection.index_range(), grain_size, [&](const IndexRange range) {
for (const int i : selection.slice(range)) {
const float3 new_position = in_positions[i] + in_offsets[i];
- copy_v3_v3(mverts[i].co, new_position);
+ copy_v3_v3(verts[i].co, new_position);
}
});
});
@@ -136,7 +137,7 @@ static void set_position_in_component(GeometryComponent &component,
{
eAttrDomain domain = component.type() == GEO_COMPONENT_TYPE_INSTANCES ? ATTR_DOMAIN_INSTANCE :
ATTR_DOMAIN_POINT;
- GeometryComponentFieldContext field_context{component, domain};
+ bke::GeometryFieldContext field_context{component, domain};
const int domain_size = component.attribute_domain_size(domain);
if (domain_size == 0) {
return;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc
index e0cf0f98d58..0df51e49827 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc
@@ -1,5 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "DNA_mesh_types.h"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_set_shade_smooth_cc {
@@ -12,27 +14,25 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void set_smooth_in_component(GeometryComponent &component,
- const Field<bool> &selection_field,
- const Field<bool> &shade_field)
+static void set_smooth(Mesh &mesh,
+ const Field<bool> &selection_field,
+ const Field<bool> &shade_field)
{
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
- if (domain_size == 0) {
+ if (mesh.totpoly == 0) {
return;
}
- MutableAttributeAccessor attributes = *component.attributes_for_write();
-
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE};
- AttributeWriter<bool> shades = attributes.lookup_or_add_for_write<bool>("shade_smooth",
+ MutableAttributeAccessor attributes = mesh.attributes_for_write();
+ AttributeWriter<bool> smooth = attributes.lookup_or_add_for_write<bool>("shade_smooth",
ATTR_DOMAIN_FACE);
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ bke::MeshFieldContext field_context{mesh, ATTR_DOMAIN_FACE};
+ fn::FieldEvaluator evaluator{field_context, mesh.totpoly};
evaluator.set_selection(selection_field);
- evaluator.add_with_destination(shade_field, shades.varray);
+ evaluator.add_with_destination(shade_field, smooth.varray);
evaluator.evaluate();
- shades.finish();
+ smooth.finish();
}
static void node_geo_exec(GeoNodeExecParams params)
@@ -42,9 +42,8 @@ static void node_geo_exec(GeoNodeExecParams params)
Field<bool> shade_field = params.extract_input<Field<bool>>("Shade Smooth");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (geometry_set.has_mesh()) {
- set_smooth_in_component(
- geometry_set.get_component_for_write<MeshComponent>(), selection_field, shade_field);
+ if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
+ set_smooth(*mesh, selection_field, shade_field);
}
});
params.set_output("Geometry", std::move(geometry_set));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc
index a35d8d66558..d8faa154477 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc
@@ -1,5 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "BKE_curves.hh"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_set_spline_cyclic_cc {
@@ -12,22 +14,19 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void set_cyclic_in_component(GeometryComponent &component,
- const Field<bool> &selection_field,
- const Field<bool> &cyclic_field)
+static void set_cyclic(bke::CurvesGeometry &curves,
+ const Field<bool> &selection_field,
+ const Field<bool> &cyclic_field)
{
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
- if (domain_size == 0) {
+ if (curves.curves_num() == 0) {
return;
}
- MutableAttributeAccessor attributes = *component.attributes_for_write();
-
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
-
+ MutableAttributeAccessor attributes = curves.attributes_for_write();
AttributeWriter<bool> cyclics = attributes.lookup_or_add_for_write<bool>("cyclic",
ATTR_DOMAIN_CURVE);
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ bke::CurvesFieldContext field_context{curves, ATTR_DOMAIN_CURVE};
+ fn::FieldEvaluator evaluator{field_context, curves.curves_num()};
evaluator.set_selection(selection_field);
evaluator.add_with_destination(cyclic_field, cyclics.varray);
evaluator.evaluate();
@@ -42,9 +41,8 @@ static void node_geo_exec(GeoNodeExecParams params)
Field<bool> cyclic_field = params.extract_input<Field<bool>>("Cyclic");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (geometry_set.has_curves()) {
- set_cyclic_in_component(
- geometry_set.get_component_for_write<CurveComponent>(), selection_field, cyclic_field);
+ if (Curves *curves_id = geometry_set.get_curves_for_write()) {
+ set_cyclic(bke::CurvesGeometry::wrap(curves_id->geometry), selection_field, cyclic_field);
}
});
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc
index fcebc1116d7..d46ceac92ba 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc
@@ -1,5 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "BKE_curves.hh"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_set_spline_resolution_cc {
@@ -12,22 +14,19 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void set_resolution_in_component(GeometryComponent &component,
- const Field<bool> &selection_field,
- const Field<int> &resolution_field)
+static void set_resolution(bke::CurvesGeometry &curves,
+ const Field<bool> &selection_field,
+ const Field<int> &resolution_field)
{
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
- if (domain_size == 0) {
+ if (curves.curves_num() == 0) {
return;
}
- MutableAttributeAccessor attributes = *component.attributes_for_write();
-
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
-
+ MutableAttributeAccessor attributes = curves.attributes_for_write();
AttributeWriter<int> resolutions = attributes.lookup_or_add_for_write<int>("resolution",
ATTR_DOMAIN_CURVE);
- fn::FieldEvaluator evaluator{field_context, domain_size};
+ bke::CurvesFieldContext field_context{curves, ATTR_DOMAIN_CURVE};
+ fn::FieldEvaluator evaluator{field_context, curves.curves_num()};
evaluator.set_selection(selection_field);
evaluator.add_with_destination(resolution_field, resolutions.varray);
evaluator.evaluate();
@@ -38,12 +37,13 @@ static void set_resolution_in_component(GeometryComponent &component,
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
- Field<int> resolution_field = params.extract_input<Field<int>>("Resolution");
+ Field<bool> selection = params.extract_input<Field<bool>>("Selection");
+ Field<int> resolution = params.extract_input<Field<int>>("Resolution");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- set_resolution_in_component(
- geometry_set.get_component_for_write<CurveComponent>(), selection_field, resolution_field);
+ if (Curves *curves_id = geometry_set.get_curves_for_write()) {
+ set_resolution(bke::CurvesGeometry::wrap(curves_id->geometry), selection, resolution);
+ }
});
params.set_output("Geometry", std::move(geometry_set));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc
index 70c33ad6a96..3c85fd459e1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc
@@ -30,7 +30,7 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -38,7 +38,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryStoreNamedAttribute *data = MEM_cnew<NodeGeometryStoreNamedAttribute>(__func__);
data->data_type = CD_PROP_FLOAT;
@@ -49,9 +49,9 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeGeometryStoreNamedAttribute &storage = node_storage(*node);
- const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
+ const eCustomDataType data_type = eCustomDataType(storage.data_type);
- bNodeSocket *socket_geometry = (bNodeSocket *)node->inputs.first;
+ bNodeSocket *socket_geometry = static_cast<bNodeSocket *>(node->inputs.first);
bNodeSocket *socket_name = socket_geometry->next;
bNodeSocket *socket_vector = socket_name->next;
bNodeSocket *socket_float = socket_vector->next;
@@ -71,10 +71,11 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
{
const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
search_link_ops_for_declarations(params, declaration.inputs().take_front(2));
+ search_link_ops_for_declarations(params, declaration.outputs().take_front(1));
if (params.in_out() == SOCK_IN) {
const std::optional<eCustomDataType> type = node_data_type_to_custom_data_type(
- static_cast<eNodeSocketDatatype>(params.other_socket().type));
+ eNodeSocketDatatype(params.other_socket().type));
if (type && *type != CD_PROP_STRING) {
/* The input and output sockets have the same name. */
params.add_item(IFACE_("Value"), [type](LinkSearchOpParams &params) {
@@ -86,54 +87,6 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
}
}
-static void try_capture_field_on_geometry(GeometryComponent &component,
- const StringRef name,
- const eAttrDomain domain,
- const GField &field,
- std::atomic<bool> &r_failure)
-{
- MutableAttributeAccessor attributes = *component.attributes_for_write();
- const int domain_size = attributes.domain_size(domain);
- if (domain_size == 0) {
- return;
- }
-
- GeometryComponentFieldContext field_context{component, domain};
- const IndexMask mask{IndexMask(domain_size)};
-
- const CPPType &type = field.cpp_type();
- const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(type);
-
- /* Could avoid allocating a new buffer if:
- * - We are writing to an attribute that exists already with the correct domain and type.
- * - The field does not depend on that attribute (we can't easily check for that yet). */
- void *buffer = MEM_mallocN(type.size() * domain_size, __func__);
-
- fn::FieldEvaluator evaluator{field_context, &mask};
- evaluator.add_with_destination(field, GMutableSpan{type, buffer, domain_size});
- evaluator.evaluate();
-
- if (GAttributeWriter attribute = attributes.lookup_for_write(name)) {
- if (attribute.domain == domain && attribute.varray.type() == type) {
- attribute.varray.set_all(buffer);
- attribute.finish();
- type.destruct_n(buffer, domain_size);
- MEM_freeN(buffer);
- return;
- }
- }
- attributes.remove(name);
- if (attributes.add(name, domain, data_type, bke::AttributeInitMove{buffer})) {
- return;
- }
-
- /* If the name corresponds to a builtin attribute, removing the attribute might fail if
- * it's required, and adding the attribute might fail if the domain or type is incorrect. */
- type.destruct_n(buffer, domain_size);
- MEM_freeN(buffer);
- r_failure = true;
-}
-
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
@@ -149,11 +102,11 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
- params.used_named_attribute(name, eNamedAttrUsage::Write);
+ params.used_named_attribute(name, NamedAttributeUsage::Write);
const NodeGeometryStoreNamedAttribute &storage = node_storage(params.node());
- const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
- const eAttrDomain domain = static_cast<eAttrDomain>(storage.domain);
+ const eCustomDataType data_type = eCustomDataType(storage.data_type);
+ const eAttrDomain domain = eAttrDomain(storage.domain);
GField field;
switch (data_type) {
@@ -189,7 +142,9 @@ static void node_geo_exec(GeoNodeExecParams params)
if (geometry_set.has_instances()) {
GeometryComponent &component = geometry_set.get_component_for_write(
GEO_COMPONENT_TYPE_INSTANCES);
- try_capture_field_on_geometry(component, name, domain, field, failure);
+ if (!bke::try_capture_field_on_geometry(component, name, domain, field)) {
+ failure.store(true);
+ }
}
}
else {
@@ -198,7 +153,9 @@ static void node_geo_exec(GeoNodeExecParams params)
{GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}) {
if (geometry_set.has(type)) {
GeometryComponent &component = geometry_set.get_component_for_write(type);
- try_capture_field_on_geometry(component, name, domain, field, failure);
+ if (!bke::try_capture_field_on_geometry(component, name, domain, field)) {
+ failure.store(true);
+ }
}
}
});
diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_join.cc b/source/blender/nodes/geometry/nodes/node_geo_string_join.cc
index bb33430a02f..09c01b8c627 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_string_join.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_string_join.cc
@@ -13,12 +13,13 @@ static void node_declare(NodeDeclarationBuilder &b)
static void node_geo_exec(GeoNodeExecParams params)
{
- Vector<std::string> strings = params.extract_multi_input<std::string>("Strings");
+ Vector<fn::ValueOrField<std::string>> strings =
+ params.extract_input<Vector<fn::ValueOrField<std::string>>>("Strings");
const std::string delim = params.extract_input<std::string>("Delimiter");
std::string output;
for (const int i : strings.index_range()) {
- output += strings[i];
+ output += strings[i].as_value();
if (i < (strings.size() - 1)) {
output += delim;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
index afd7db6604d..769a63f58cf 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
@@ -6,6 +6,7 @@
#include "BKE_curve.h"
#include "BKE_curve_legacy_convert.hh"
#include "BKE_curves.hh"
+#include "BKE_instances.hh"
#include "BKE_vfont.h"
#include "BLI_hash.h"
@@ -76,7 +77,7 @@ static void node_layout(uiLayout *layout, struct bContext *C, PointerRNA *ptr)
uiItemR(layout, ptr, "pivot_mode", 0, IFACE_("Pivot Point"), ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryStringToCurves *data = MEM_cnew<NodeGeometryStringToCurves>(__func__);
@@ -85,7 +86,7 @@ static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
data->align_y = GEO_NODE_STRING_TO_CURVES_ALIGN_Y_TOP_BASELINE;
data->pivot_mode = GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_BOTTOM_LEFT;
node->storage = data;
- node->id = (ID *)BKE_vfont_builtin_get();
+ node->id = reinterpret_cast<ID *>(BKE_vfont_builtin_get());
}
static void node_update(bNodeTree *ntree, bNode *node)
@@ -93,11 +94,11 @@ static void node_update(bNodeTree *ntree, bNode *node)
const NodeGeometryStringToCurves &storage = node_storage(*node);
const GeometryNodeStringToCurvesOverflowMode overflow = (GeometryNodeStringToCurvesOverflowMode)
storage.overflow;
- bNodeSocket *socket_remainder = ((bNodeSocket *)node->outputs.first)->next;
+ bNodeSocket *socket_remainder = static_cast<bNodeSocket *>(node->outputs.first)->next;
nodeSetSocketAvailability(
ntree, socket_remainder, overflow == GEO_NODE_STRING_TO_CURVES_MODE_TRUNCATE);
- bNodeSocket *height_socket = (bNodeSocket *)node->inputs.last;
+ bNodeSocket *height_socket = static_cast<bNodeSocket *>(node->inputs.last);
nodeSetSocketAvailability(
ntree, height_socket, overflow != GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW);
}
@@ -203,7 +204,7 @@ static std::optional<TextLayout> get_text_layout(GeoNodeExecParams &params)
cu.linedist = line_spacing;
cu.vfont = vfont;
cu.overflow = overflow;
- cu.tb = (TextBox *)MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), __func__);
+ cu.tb = static_cast<TextBox *>(MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), __func__));
cu.tb->w = textbox_w;
cu.tb->h = textbox_h;
cu.totbox = 1;
@@ -213,8 +214,8 @@ static std::optional<TextLayout> get_text_layout(GeoNodeExecParams &params)
cu.len = len_bytes;
cu.pos = len_chars;
/* The reason for the additional character here is unknown, but reflects other code elsewhere. */
- cu.str = (char *)MEM_mallocN(len_bytes + sizeof(char32_t), __func__);
- cu.strinfo = (CharInfo *)MEM_callocN((len_chars + 1) * sizeof(CharInfo), __func__);
+ cu.str = static_cast<char *>(MEM_mallocN(len_bytes + sizeof(char32_t), __func__));
+ cu.strinfo = static_cast<CharInfo *>(MEM_callocN((len_chars + 1) * sizeof(CharInfo), __func__));
BLI_strncpy(cu.str, layout.text.c_str(), len_bytes + 1);
struct CharTrans *chartransdata = nullptr;
@@ -226,7 +227,7 @@ static std::optional<TextLayout> get_text_layout(GeoNodeExecParams &params)
nullptr, &cu, FO_DUPLI, nullptr, &r_text, &text_len, &text_free, &chartransdata);
if (text_free) {
- MEM_freeN((void *)r_text);
+ MEM_freeN(const_cast<char32_t *>(r_text));
}
Span<CharInfo> info{cu.strinfo, text_len};
@@ -270,9 +271,9 @@ static std::optional<TextLayout> get_text_layout(GeoNodeExecParams &params)
/* Returns a mapping of UTF-32 character code to instance handle. */
static Map<int, int> create_curve_instances(GeoNodeExecParams &params,
TextLayout &layout,
- InstancesComponent &instances)
+ bke::Instances &instances)
{
- VFont *vfont = (VFont *)params.node().id;
+ VFont *vfont = reinterpret_cast<VFont *>(params.node().id);
Map<int, int> handles;
bool pivot_required = params.output_is_required("Pivot Point");
@@ -315,13 +316,13 @@ static Map<int, int> create_curve_instances(GeoNodeExecParams &params,
return handles;
}
-static void add_instances_from_handles(InstancesComponent &instances,
+static void add_instances_from_handles(bke::Instances &instances,
const Map<int, int> &char_handles,
const TextLayout &layout)
{
instances.resize(layout.positions.size());
- MutableSpan<int> handles = instances.instance_reference_handles();
- MutableSpan<float4x4> transforms = instances.instance_transforms();
+ MutableSpan<int> handles = instances.reference_handles();
+ MutableSpan<float4x4> transforms = instances.transforms();
threading::parallel_for(IndexRange(layout.positions.size()), 256, [&](IndexRange range) {
for (const int i : range) {
@@ -333,9 +334,9 @@ static void add_instances_from_handles(InstancesComponent &instances,
static void create_attributes(GeoNodeExecParams &params,
const TextLayout &layout,
- InstancesComponent &instances)
+ bke::Instances &instances)
{
- MutableAttributeAccessor attributes = *instances.attributes_for_write();
+ MutableAttributeAccessor attributes = instances.attributes_for_write();
if (params.output_is_required("Line")) {
StrongAnonymousAttributeID line_id = StrongAnonymousAttributeID("Line");
@@ -385,13 +386,12 @@ static void node_geo_exec(GeoNodeExecParams params)
}
/* Create and add instances. */
- GeometrySet geometry_set_out;
- InstancesComponent &instances = geometry_set_out.get_component_for_write<InstancesComponent>();
- Map<int, int> char_handles = create_curve_instances(params, *layout, instances);
- add_instances_from_handles(instances, char_handles, *layout);
- create_attributes(params, *layout, instances);
+ std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>();
+ Map<int, int> char_handles = create_curve_instances(params, *layout, *instances);
+ add_instances_from_handles(*instances, char_handles, *layout);
+ create_attributes(params, *layout, *instances);
- params.set_output("Curve Instances", std::move(geometry_set_out));
+ params.set_output("Curve Instances", GeometrySet::create_with_instances(instances.release()));
}
} // namespace blender::nodes::node_geo_string_to_curves_cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
index eda6a51d412..2e6ad02bfd5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
@@ -39,13 +39,13 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "uv_smooth", 0, "", ICON_NONE);
uiItemR(layout, ptr, "boundary_smooth", 0, "", ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometrySubdivisionSurface *data = MEM_cnew<NodeGeometrySubdivisionSurface>(__func__);
data->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES;
@@ -73,7 +73,7 @@ static void write_vertex_creases(Mesh &mesh, const VArray<float> &crease_varray)
}
else {
crease = static_cast<float *>(
- CustomData_add_layer(&mesh.vdata, CD_CREASE, CD_DEFAULT, nullptr, mesh.totvert));
+ CustomData_add_layer(&mesh.vdata, CD_CREASE, CD_CONSTRUCT, nullptr, mesh.totvert));
}
materialize_and_clamp_creases(crease_varray, {crease, mesh.totvert});
}
@@ -119,21 +119,19 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
- const MeshComponent &mesh_component = *geometry_set.get_component_for_read<MeshComponent>();
- const int verts_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
- const int edges_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_EDGE);
- if (verts_num == 0 || edges_num == 0) {
+ const Mesh &mesh = *geometry_set.get_mesh_for_read();
+ if (mesh.totvert == 0 || mesh.totedge == 0) {
return;
}
- GeometryComponentFieldContext point_context{mesh_component, ATTR_DOMAIN_POINT};
- FieldEvaluator point_evaluator(point_context, verts_num);
+ bke::MeshFieldContext point_context{mesh, ATTR_DOMAIN_POINT};
+ FieldEvaluator point_evaluator(point_context, mesh.totvert);
point_evaluator.add(vertex_crease_field);
point_evaluator.evaluate();
const VArray<float> vertex_creases = point_evaluator.get_evaluated<float>(0);
- GeometryComponentFieldContext edge_context{mesh_component, ATTR_DOMAIN_EDGE};
- FieldEvaluator edge_evaluator(edge_context, edges_num);
+ bke::MeshFieldContext edge_context{mesh, ATTR_DOMAIN_EDGE};
+ FieldEvaluator edge_evaluator(edge_context, mesh.totedge);
edge_evaluator.add(edge_crease_field);
edge_evaluator.evaluate();
const VArray<float> edge_creases = edge_evaluator.get_evaluated<float>(0);
@@ -162,17 +160,15 @@ static void node_geo_exec(GeoNodeExecParams params)
subdiv_settings.fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth(
uv_smooth);
- const Mesh &mesh_in = *geometry_set.get_mesh_for_read();
-
/* Apply subdivision to mesh. */
- Subdiv *subdiv = BKE_subdiv_update_from_mesh(nullptr, &subdiv_settings, &mesh_in);
+ Subdiv *subdiv = BKE_subdiv_update_from_mesh(nullptr, &subdiv_settings, &mesh);
/* In case of bad topology, skip to input mesh. */
if (subdiv == nullptr) {
return;
}
- Mesh *mesh_out = BKE_subdiv_to_mesh(subdiv, &mesh_settings, &mesh_in);
+ Mesh *mesh_out = BKE_subdiv_to_mesh(subdiv, &mesh_settings, &mesh);
geometry_set.replace_mesh(mesh_out);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_switch.cc b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
index ddc87e3dac4..36be68f1a22 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_switch.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
@@ -73,12 +73,12 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Image>(N_("Output"), "Output_011");
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "input_type", 0, "", ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeSwitch *data = MEM_cnew<NodeSwitch>(__func__);
data->input_type = SOCK_GEOMETRY;
@@ -89,8 +89,8 @@ static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeSwitch &storage = node_storage(*node);
int index = 0;
- bNodeSocket *field_switch = (bNodeSocket *)node->inputs.first;
- bNodeSocket *non_field_switch = (bNodeSocket *)field_switch->next;
+ bNodeSocket *field_switch = static_cast<bNodeSocket *>(node->inputs.first);
+ bNodeSocket *non_field_switch = static_cast<bNodeSocket *>(field_switch->next);
const bool fields_type = ELEM(
storage.input_type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA, SOCK_STRING);
@@ -222,7 +222,7 @@ template<typename T> void switch_no_fields(GeoNodeExecParams &params, const Stri
static void node_geo_exec(GeoNodeExecParams params)
{
const NodeSwitch &storage = node_storage(params.node());
- const eNodeSocketDatatype data_type = static_cast<eNodeSocketDatatype>(storage.input_type);
+ const eNodeSocketDatatype data_type = eNodeSocketDatatype(storage.input_type);
switch (data_type) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
deleted file mode 100644
index cd75822f665..00000000000
--- a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
+++ /dev/null
@@ -1,826 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BLI_generic_array.hh"
-#include "BLI_kdopbvh.h"
-#include "BLI_task.hh"
-
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_pointcloud_types.h"
-
-#include "BKE_attribute_math.hh"
-#include "BKE_bvhutils.h"
-#include "BKE_mesh_runtime.h"
-#include "BKE_mesh_sample.hh"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "NOD_socket_search_link.hh"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_transfer_attribute_cc {
-
-using namespace blender::bke::mesh_surface_sample;
-
-NODE_STORAGE_FUNCS(NodeGeometryTransferAttribute)
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Source"))
- .supported_type({GEO_COMPONENT_TYPE_MESH,
- GEO_COMPONENT_TYPE_POINT_CLOUD,
- GEO_COMPONENT_TYPE_CURVE,
- GEO_COMPONENT_TYPE_INSTANCES});
-
- b.add_input<decl::Vector>(N_("Attribute")).hide_value().supports_field();
- b.add_input<decl::Float>(N_("Attribute"), "Attribute_001").hide_value().supports_field();
- b.add_input<decl::Color>(N_("Attribute"), "Attribute_002").hide_value().supports_field();
- b.add_input<decl::Bool>(N_("Attribute"), "Attribute_003").hide_value().supports_field();
- b.add_input<decl::Int>(N_("Attribute"), "Attribute_004").hide_value().supports_field();
-
- b.add_input<decl::Vector>(N_("Source Position"))
- .implicit_field()
- .make_available([](bNode &node) {
- node_storage(node).mode = GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED;
- });
- b.add_input<decl::Int>(N_("Index")).implicit_field().make_available([](bNode &node) {
- node_storage(node).mode = GEO_NODE_ATTRIBUTE_TRANSFER_INDEX;
- });
-
- b.add_output<decl::Vector>(N_("Attribute")).dependent_field({6, 7});
- b.add_output<decl::Float>(N_("Attribute"), "Attribute_001").dependent_field({6, 7});
- b.add_output<decl::Color>(N_("Attribute"), "Attribute_002").dependent_field({6, 7});
- b.add_output<decl::Bool>(N_("Attribute"), "Attribute_003").dependent_field({6, 7});
- b.add_output<decl::Int>(N_("Attribute"), "Attribute_004").dependent_field({6, 7});
-}
-
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- const bNode &node = *static_cast<const bNode *>(ptr->data);
- const NodeGeometryTransferAttribute &storage = node_storage(node);
- const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode)
- storage.mode;
-
- uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "mapping", 0, "", ICON_NONE);
- if (mapping != GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED) {
- uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
- }
-}
-
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
-{
- NodeGeometryTransferAttribute *data = MEM_cnew<NodeGeometryTransferAttribute>(__func__);
- data->data_type = CD_PROP_FLOAT;
- data->mode = GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED;
- node->storage = data;
-}
-
-static void node_update(bNodeTree *ntree, bNode *node)
-{
- const NodeGeometryTransferAttribute &storage = node_storage(*node);
- const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
- const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode)
- storage.mode;
-
- bNodeSocket *socket_geometry = (bNodeSocket *)node->inputs.first;
- bNodeSocket *socket_vector = socket_geometry->next;
- bNodeSocket *socket_float = socket_vector->next;
- bNodeSocket *socket_color4f = socket_float->next;
- bNodeSocket *socket_boolean = socket_color4f->next;
- bNodeSocket *socket_int32 = socket_boolean->next;
-
- bNodeSocket *socket_positions = socket_int32->next;
- bNodeSocket *socket_indices = socket_positions->next;
-
- nodeSetSocketAvailability(ntree, socket_vector, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(ntree, socket_float, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(ntree, socket_color4f, data_type == CD_PROP_COLOR);
- nodeSetSocketAvailability(ntree, socket_boolean, data_type == CD_PROP_BOOL);
- nodeSetSocketAvailability(ntree, socket_int32, data_type == CD_PROP_INT32);
-
- nodeSetSocketAvailability(ntree, socket_positions, mapping != GEO_NODE_ATTRIBUTE_TRANSFER_INDEX);
- nodeSetSocketAvailability(ntree, socket_indices, mapping == GEO_NODE_ATTRIBUTE_TRANSFER_INDEX);
-
- bNodeSocket *out_socket_vector = (bNodeSocket *)node->outputs.first;
- bNodeSocket *out_socket_float = out_socket_vector->next;
- bNodeSocket *out_socket_color4f = out_socket_float->next;
- bNodeSocket *out_socket_boolean = out_socket_color4f->next;
- bNodeSocket *out_socket_int32 = out_socket_boolean->next;
-
- nodeSetSocketAvailability(ntree, out_socket_vector, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(ntree, out_socket_float, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(ntree, out_socket_color4f, data_type == CD_PROP_COLOR);
- nodeSetSocketAvailability(ntree, out_socket_boolean, data_type == CD_PROP_BOOL);
- nodeSetSocketAvailability(ntree, out_socket_int32, data_type == CD_PROP_INT32);
-}
-
-static void node_gather_link_searches(GatherLinkSearchOpParams &params)
-{
- const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
- search_link_ops_for_declarations(params, declaration.inputs().take_back(2));
- search_link_ops_for_declarations(params, declaration.inputs().take_front(1));
-
- const std::optional<eCustomDataType> type = node_data_type_to_custom_data_type(
- (eNodeSocketDatatype)params.other_socket().type);
- if (type && *type != CD_PROP_STRING) {
- /* The input and output sockets have the same name. */
- params.add_item(IFACE_("Attribute"), [type](LinkSearchOpParams &params) {
- bNode &node = params.add_node("GeometryNodeAttributeTransfer");
- node_storage(node).data_type = *type;
- params.update_and_connect_available_socket(node, "Attribute");
- });
- }
-}
-
-static void get_closest_in_bvhtree(BVHTreeFromMesh &tree_data,
- const VArray<float3> &positions,
- const IndexMask mask,
- const MutableSpan<int> r_indices,
- const MutableSpan<float> r_distances_sq,
- const MutableSpan<float3> r_positions)
-{
- BLI_assert(positions.size() >= r_indices.size());
- BLI_assert(positions.size() >= r_distances_sq.size());
- BLI_assert(positions.size() >= r_positions.size());
-
- for (const int i : mask) {
- BVHTreeNearest nearest;
- nearest.dist_sq = FLT_MAX;
- const float3 position = positions[i];
- BLI_bvhtree_find_nearest(
- tree_data.tree, position, &nearest, tree_data.nearest_callback, &tree_data);
- if (!r_indices.is_empty()) {
- r_indices[i] = nearest.index;
- }
- if (!r_distances_sq.is_empty()) {
- r_distances_sq[i] = nearest.dist_sq;
- }
- if (!r_positions.is_empty()) {
- r_positions[i] = nearest.co;
- }
- }
-}
-
-static void get_closest_pointcloud_points(const PointCloud &pointcloud,
- const VArray<float3> &positions,
- const IndexMask mask,
- const MutableSpan<int> r_indices,
- const MutableSpan<float> r_distances_sq)
-{
- BLI_assert(positions.size() >= r_indices.size());
- BLI_assert(pointcloud.totpoint > 0);
-
- BVHTreeFromPointCloud tree_data;
- BKE_bvhtree_from_pointcloud_get(&tree_data, &pointcloud, 2);
-
- for (const int i : mask) {
- BVHTreeNearest nearest;
- nearest.dist_sq = FLT_MAX;
- const float3 position = positions[i];
- BLI_bvhtree_find_nearest(
- tree_data.tree, position, &nearest, tree_data.nearest_callback, &tree_data);
- r_indices[i] = nearest.index;
- if (!r_distances_sq.is_empty()) {
- r_distances_sq[i] = nearest.dist_sq;
- }
- }
-
- free_bvhtree_from_pointcloud(&tree_data);
-}
-
-static void get_closest_mesh_points(const Mesh &mesh,
- const VArray<float3> &positions,
- const IndexMask mask,
- const MutableSpan<int> r_point_indices,
- const MutableSpan<float> r_distances_sq,
- const MutableSpan<float3> r_positions)
-{
- BLI_assert(mesh.totvert > 0);
- BVHTreeFromMesh tree_data;
- BKE_bvhtree_from_mesh_get(&tree_data, &mesh, BVHTREE_FROM_VERTS, 2);
- get_closest_in_bvhtree(tree_data, positions, mask, r_point_indices, r_distances_sq, r_positions);
- free_bvhtree_from_mesh(&tree_data);
-}
-
-static void get_closest_mesh_edges(const Mesh &mesh,
- const VArray<float3> &positions,
- const IndexMask mask,
- const MutableSpan<int> r_edge_indices,
- const MutableSpan<float> r_distances_sq,
- const MutableSpan<float3> r_positions)
-{
- BLI_assert(mesh.totedge > 0);
- BVHTreeFromMesh tree_data;
- BKE_bvhtree_from_mesh_get(&tree_data, &mesh, BVHTREE_FROM_EDGES, 2);
- get_closest_in_bvhtree(tree_data, positions, mask, r_edge_indices, r_distances_sq, r_positions);
- free_bvhtree_from_mesh(&tree_data);
-}
-
-static void get_closest_mesh_looptris(const Mesh &mesh,
- const VArray<float3> &positions,
- const IndexMask mask,
- const MutableSpan<int> r_looptri_indices,
- const MutableSpan<float> r_distances_sq,
- const MutableSpan<float3> r_positions)
-{
- BLI_assert(mesh.totpoly > 0);
- BVHTreeFromMesh tree_data;
- BKE_bvhtree_from_mesh_get(&tree_data, &mesh, BVHTREE_FROM_LOOPTRI, 2);
- get_closest_in_bvhtree(
- tree_data, positions, mask, r_looptri_indices, r_distances_sq, r_positions);
- free_bvhtree_from_mesh(&tree_data);
-}
-
-static void get_closest_mesh_polygons(const Mesh &mesh,
- const VArray<float3> &positions,
- const IndexMask mask,
- const MutableSpan<int> r_poly_indices,
- const MutableSpan<float> r_distances_sq,
- const MutableSpan<float3> r_positions)
-{
- BLI_assert(mesh.totpoly > 0);
-
- Array<int> looptri_indices(positions.size());
- get_closest_mesh_looptris(mesh, positions, mask, looptri_indices, r_distances_sq, r_positions);
-
- const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
- BKE_mesh_runtime_looptri_len(&mesh)};
-
- for (const int i : mask) {
- const MLoopTri &looptri = looptris[looptri_indices[i]];
- r_poly_indices[i] = looptri.poly;
- }
-}
-
-/* The closest corner is defined to be the closest corner on the closest face. */
-static void get_closest_mesh_corners(const Mesh &mesh,
- const VArray<float3> &positions,
- const IndexMask mask,
- const MutableSpan<int> r_corner_indices,
- const MutableSpan<float> r_distances_sq,
- const MutableSpan<float3> r_positions)
-{
- BLI_assert(mesh.totloop > 0);
- Array<int> poly_indices(positions.size());
- get_closest_mesh_polygons(mesh, positions, mask, poly_indices, {}, {});
-
- for (const int i : mask) {
- const float3 position = positions[i];
- const int poly_index = poly_indices[i];
- const MPoly &poly = mesh.mpoly[poly_index];
-
- /* Find the closest vertex in the polygon. */
- float min_distance_sq = FLT_MAX;
- const MVert *closest_mvert;
- int closest_loop_index = 0;
- for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- const MLoop &loop = mesh.mloop[loop_index];
- const int vertex_index = loop.v;
- const MVert &mvert = mesh.mvert[vertex_index];
- const float distance_sq = math::distance_squared(position, float3(mvert.co));
- if (distance_sq < min_distance_sq) {
- min_distance_sq = distance_sq;
- closest_loop_index = loop_index;
- closest_mvert = &mvert;
- }
- }
- if (!r_corner_indices.is_empty()) {
- r_corner_indices[i] = closest_loop_index;
- }
- if (!r_positions.is_empty()) {
- r_positions[i] = closest_mvert->co;
- }
- if (!r_distances_sq.is_empty()) {
- r_distances_sq[i] = min_distance_sq;
- }
- }
-}
-
-template<typename T>
-void copy_with_indices(const VArray<T> &src,
- const IndexMask mask,
- const Span<int> indices,
- const MutableSpan<T> dst)
-{
- if (src.is_empty()) {
- return;
- }
- for (const int i : mask) {
- dst[i] = src[indices[i]];
- }
-}
-
-template<typename T>
-void copy_with_indices_clamped(const VArray<T> &src,
- const IndexMask mask,
- const VArray<int> &indices,
- const MutableSpan<T> dst)
-{
- if (src.is_empty()) {
- return;
- }
- const int max_index = src.size() - 1;
- threading::parallel_for(mask.index_range(), 4096, [&](IndexRange range) {
- for (const int i : range) {
- const int index = mask[i];
- dst[index] = src[std::clamp(indices[index], 0, max_index)];
- }
- });
-}
-
-template<typename T>
-void copy_with_indices_and_comparison(const VArray<T> &src_1,
- const VArray<T> &src_2,
- const Span<float> distances_1,
- const Span<float> distances_2,
- const IndexMask mask,
- const Span<int> indices_1,
- const Span<int> indices_2,
- const MutableSpan<T> dst)
-{
- if (src_1.is_empty() || src_2.is_empty()) {
- return;
- }
- for (const int i : mask) {
- if (distances_1[i] < distances_2[i]) {
- dst[i] = src_1[indices_1[i]];
- }
- else {
- dst[i] = src_2[indices_2[i]];
- }
- }
-}
-
-static bool component_is_available(const GeometrySet &geometry,
- const GeometryComponentType type,
- const eAttrDomain domain)
-{
- if (!geometry.has(type)) {
- return false;
- }
- const GeometryComponent &component = *geometry.get_component_for_read(type);
- if (component.is_empty()) {
- return false;
- }
- return component.attribute_domain_size(domain) != 0;
-}
-
-/**
- * \note Multi-threading for this function is provided by the field evaluator. Since the #call
- * function could be called many times, calculate the data from the source geometry once and store
- * it for later.
- */
-class NearestInterpolatedTransferFunction : public fn::MultiFunction {
- GeometrySet source_;
- GField src_field_;
-
- /**
- * This function is meant to sample the surface of a mesh rather than take the value from
- * individual elements, so use the most complex domain, ensuring no information is lost. In the
- * future, it should be possible to use the most complex domain required by the field inputs, to
- * simplify sampling and avoid domain conversions.
- */
- eAttrDomain domain_ = ATTR_DOMAIN_CORNER;
-
- fn::MFSignature signature_;
-
- std::optional<GeometryComponentFieldContext> source_context_;
- std::unique_ptr<FieldEvaluator> source_evaluator_;
- const GVArray *source_data_;
-
- public:
- NearestInterpolatedTransferFunction(GeometrySet geometry, GField src_field)
- : source_(std::move(geometry)), src_field_(std::move(src_field))
- {
- source_.ensure_owns_direct_data();
- signature_ = this->create_signature();
- this->set_signature(&signature_);
- this->evaluate_source_field();
- }
-
- fn::MFSignature create_signature()
- {
- blender::fn::MFSignatureBuilder signature{"Attribute Transfer Nearest Interpolated"};
- signature.single_input<float3>("Position");
- signature.single_output("Attribute", src_field_.cpp_type());
- return signature.build();
- }
-
- void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
- {
- const VArray<float3> &positions = params.readonly_single_input<float3>(0, "Position");
- GMutableSpan dst = params.uninitialized_single_output_if_required(1, "Attribute");
-
- const MeshComponent &mesh_component = *source_.get_component_for_read<MeshComponent>();
- BLI_assert(mesh_component.has_mesh());
- const Mesh &mesh = *mesh_component.get_for_read();
- BLI_assert(mesh.totpoly > 0);
-
- /* Find closest points on the mesh surface. */
- Array<int> looptri_indices(mask.min_array_size());
- Array<float3> sampled_positions(mask.min_array_size());
- get_closest_mesh_looptris(mesh, positions, mask, looptri_indices, {}, sampled_positions);
-
- MeshAttributeInterpolator interp(&mesh, mask, sampled_positions, looptri_indices);
- interp.sample_data(*source_data_, domain_, eAttributeMapMode::INTERPOLATED, dst);
- }
-
- private:
- void evaluate_source_field()
- {
- const MeshComponent &mesh_component = *source_.get_component_for_read<MeshComponent>();
- source_context_.emplace(GeometryComponentFieldContext{mesh_component, domain_});
- const int domain_num = mesh_component.attribute_domain_size(domain_);
- source_evaluator_ = std::make_unique<FieldEvaluator>(*source_context_, domain_num);
- source_evaluator_->add(src_field_);
- source_evaluator_->evaluate();
- source_data_ = &source_evaluator_->get_evaluated(0);
- }
-};
-
-/**
- * \note Multi-threading for this function is provided by the field evaluator. Since the #call
- * function could be called many times, calculate the data from the source geometry once and store
- * it for later.
- */
-class NearestTransferFunction : public fn::MultiFunction {
- GeometrySet source_;
- GField src_field_;
- eAttrDomain domain_;
-
- fn::MFSignature signature_;
-
- bool use_mesh_;
- bool use_points_;
-
- /* Store data from the source as a virtual array, since we may only access a few indices. */
- std::optional<GeometryComponentFieldContext> mesh_context_;
- std::unique_ptr<FieldEvaluator> mesh_evaluator_;
- const GVArray *mesh_data_;
-
- std::optional<GeometryComponentFieldContext> point_context_;
- std::unique_ptr<FieldEvaluator> point_evaluator_;
- const GVArray *point_data_;
-
- public:
- NearestTransferFunction(GeometrySet geometry, GField src_field, eAttrDomain domain)
- : source_(std::move(geometry)), src_field_(std::move(src_field)), domain_(domain)
- {
- source_.ensure_owns_direct_data();
- signature_ = this->create_signature();
- this->set_signature(&signature_);
-
- this->use_mesh_ = component_is_available(source_, GEO_COMPONENT_TYPE_MESH, domain_);
- this->use_points_ = component_is_available(source_, GEO_COMPONENT_TYPE_POINT_CLOUD, domain_);
-
- this->evaluate_source_field();
- }
-
- fn::MFSignature create_signature()
- {
- blender::fn::MFSignatureBuilder signature{"Attribute Transfer Nearest"};
- signature.single_input<float3>("Position");
- signature.single_output("Attribute", src_field_.cpp_type());
- return signature.build();
- }
-
- void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
- {
- const VArray<float3> &positions = params.readonly_single_input<float3>(0, "Position");
- GMutableSpan dst = params.uninitialized_single_output_if_required(1, "Attribute");
-
- if (!use_mesh_ && !use_points_) {
- dst.type().value_initialize_indices(dst.data(), mask);
- return;
- }
-
- const Mesh *mesh = use_mesh_ ? source_.get_mesh_for_read() : nullptr;
- const PointCloud *pointcloud = use_points_ ? source_.get_pointcloud_for_read() : nullptr;
-
- const int tot_samples = mask.min_array_size();
-
- Array<int> point_indices;
- Array<float> point_distances;
-
- /* Depending on where what domain the source attribute lives, these indices are either vertex,
- * corner, edge or polygon indices. */
- Array<int> mesh_indices;
- Array<float> mesh_distances;
-
- /* If there is a point cloud, find the closest points. */
- if (use_points_) {
- point_indices.reinitialize(tot_samples);
- if (use_mesh_) {
- point_distances.reinitialize(tot_samples);
- }
- get_closest_pointcloud_points(*pointcloud, positions, mask, point_indices, point_distances);
- }
-
- /* If there is a mesh, find the closest mesh elements. */
- if (use_mesh_) {
- mesh_indices.reinitialize(tot_samples);
- if (use_points_) {
- mesh_distances.reinitialize(tot_samples);
- }
- switch (domain_) {
- case ATTR_DOMAIN_POINT: {
- get_closest_mesh_points(*mesh, positions, mask, mesh_indices, mesh_distances, {});
- break;
- }
- case ATTR_DOMAIN_EDGE: {
- get_closest_mesh_edges(*mesh, positions, mask, mesh_indices, mesh_distances, {});
- break;
- }
- case ATTR_DOMAIN_FACE: {
- get_closest_mesh_polygons(*mesh, positions, mask, mesh_indices, mesh_distances, {});
- break;
- }
- case ATTR_DOMAIN_CORNER: {
- get_closest_mesh_corners(*mesh, positions, mask, mesh_indices, mesh_distances, {});
- break;
- }
- default: {
- break;
- }
- }
- }
-
- attribute_math::convert_to_static_type(dst.type(), [&](auto dummy) {
- using T = decltype(dummy);
- if (use_mesh_ && use_points_) {
- VArray<T> src_mesh = mesh_data_->typed<T>();
- VArray<T> src_point = point_data_->typed<T>();
- copy_with_indices_and_comparison(src_mesh,
- src_point,
- mesh_distances,
- point_distances,
- mask,
- mesh_indices,
- point_indices,
- dst.typed<T>());
- }
- else if (use_points_) {
- VArray<T> src_point = point_data_->typed<T>();
- copy_with_indices(src_point, mask, point_indices, dst.typed<T>());
- }
- else if (use_mesh_) {
- VArray<T> src_mesh = mesh_data_->typed<T>();
- copy_with_indices(src_mesh, mask, mesh_indices, dst.typed<T>());
- }
- });
- }
-
- private:
- void evaluate_source_field()
- {
- if (use_mesh_) {
- const MeshComponent &mesh = *source_.get_component_for_read<MeshComponent>();
- const int domain_num = mesh.attribute_domain_size(domain_);
- mesh_context_.emplace(GeometryComponentFieldContext(mesh, domain_));
- mesh_evaluator_ = std::make_unique<FieldEvaluator>(*mesh_context_, domain_num);
- mesh_evaluator_->add(src_field_);
- mesh_evaluator_->evaluate();
- mesh_data_ = &mesh_evaluator_->get_evaluated(0);
- }
-
- if (use_points_) {
- const PointCloudComponent &points = *source_.get_component_for_read<PointCloudComponent>();
- const int domain_num = points.attribute_domain_size(domain_);
- point_context_.emplace(GeometryComponentFieldContext(points, domain_));
- point_evaluator_ = std::make_unique<FieldEvaluator>(*point_context_, domain_num);
- point_evaluator_->add(src_field_);
- point_evaluator_->evaluate();
- point_data_ = &point_evaluator_->get_evaluated(0);
- }
- }
-};
-
-static const GeometryComponent *find_source_component(const GeometrySet &geometry,
- const eAttrDomain domain)
-{
- /* Choose the other component based on a consistent order, rather than some more complicated
- * heuristic. This is the same order visible in the spreadsheet and used in the ray-cast node. */
- static const Array<GeometryComponentType> supported_types = {GEO_COMPONENT_TYPE_MESH,
- GEO_COMPONENT_TYPE_POINT_CLOUD,
- GEO_COMPONENT_TYPE_CURVE,
- GEO_COMPONENT_TYPE_INSTANCES};
- for (const GeometryComponentType src_type : supported_types) {
- if (component_is_available(geometry, src_type, domain)) {
- return geometry.get_component_for_read(src_type);
- }
- }
-
- return nullptr;
-}
-
-/**
- * The index-based transfer theoretically does not need realized data when there is only one
- * instance geometry set in the source. A future optimization could be removing that limitation
- * internally.
- */
-class IndexTransferFunction : public fn::MultiFunction {
- GeometrySet src_geometry_;
- GField src_field_;
- eAttrDomain domain_;
-
- fn::MFSignature signature_;
-
- std::optional<GeometryComponentFieldContext> geometry_context_;
- std::unique_ptr<FieldEvaluator> evaluator_;
- const GVArray *src_data_ = nullptr;
-
- public:
- IndexTransferFunction(GeometrySet geometry, GField src_field, const eAttrDomain domain)
- : src_geometry_(std::move(geometry)), src_field_(std::move(src_field)), domain_(domain)
- {
- src_geometry_.ensure_owns_direct_data();
-
- signature_ = this->create_signature();
- this->set_signature(&signature_);
-
- this->evaluate_field();
- }
-
- fn::MFSignature create_signature()
- {
- fn::MFSignatureBuilder signature{"Attribute Transfer Index"};
- signature.single_input<int>("Index");
- signature.single_output("Attribute", src_field_.cpp_type());
- return signature.build();
- }
-
- void evaluate_field()
- {
- const GeometryComponent *component = find_source_component(src_geometry_, domain_);
- if (component == nullptr) {
- return;
- }
- const int domain_num = component->attribute_domain_size(domain_);
- geometry_context_.emplace(GeometryComponentFieldContext(*component, domain_));
- evaluator_ = std::make_unique<FieldEvaluator>(*geometry_context_, domain_num);
- evaluator_->add(src_field_);
- evaluator_->evaluate();
- src_data_ = &evaluator_->get_evaluated(0);
- }
-
- void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
- {
- const VArray<int> &indices = params.readonly_single_input<int>(0, "Index");
- GMutableSpan dst = params.uninitialized_single_output(1, "Attribute");
-
- const CPPType &type = dst.type();
- if (src_data_ == nullptr) {
- type.value_initialize_indices(dst.data(), mask);
- return;
- }
-
- attribute_math::convert_to_static_type(type, [&](auto dummy) {
- using T = decltype(dummy);
- copy_with_indices_clamped(src_data_->typed<T>(), mask, indices, dst.typed<T>());
- });
- }
-};
-
-static GField get_input_attribute_field(GeoNodeExecParams &params, const eCustomDataType data_type)
-{
- switch (data_type) {
- case CD_PROP_FLOAT:
- return params.extract_input<Field<float>>("Attribute_001");
- case CD_PROP_FLOAT3:
- return params.extract_input<Field<float3>>("Attribute");
- case CD_PROP_COLOR:
- return params.extract_input<Field<ColorGeometry4f>>("Attribute_002");
- case CD_PROP_BOOL:
- return params.extract_input<Field<bool>>("Attribute_003");
- case CD_PROP_INT32:
- return params.extract_input<Field<int>>("Attribute_004");
- default:
- BLI_assert_unreachable();
- }
- return {};
-}
-
-static void output_attribute_field(GeoNodeExecParams &params, GField field)
-{
- switch (bke::cpp_type_to_custom_data_type(field.cpp_type())) {
- case CD_PROP_FLOAT: {
- params.set_output("Attribute_001", Field<float>(field));
- break;
- }
- case CD_PROP_FLOAT3: {
- params.set_output("Attribute", Field<float3>(field));
- break;
- }
- case CD_PROP_COLOR: {
- params.set_output("Attribute_002", Field<ColorGeometry4f>(field));
- break;
- }
- case CD_PROP_BOOL: {
- params.set_output("Attribute_003", Field<bool>(field));
- break;
- }
- case CD_PROP_INT32: {
- params.set_output("Attribute_004", Field<int>(field));
- break;
- }
- default:
- break;
- }
-}
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- GeometrySet geometry = params.extract_input<GeometrySet>("Source");
- const NodeGeometryTransferAttribute &storage = node_storage(params.node());
- const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode)
- storage.mode;
- const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
- const eAttrDomain domain = static_cast<eAttrDomain>(storage.domain);
-
- GField field = get_input_attribute_field(params, data_type);
-
- auto return_default = [&]() {
- attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
- using T = decltype(dummy);
- output_attribute_field(params, fn::make_constant_field<T>(T()));
- });
- };
-
- GField output_field;
- switch (mapping) {
- case GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED: {
- const Mesh *mesh = geometry.get_mesh_for_read();
- if (mesh == nullptr) {
- if (!geometry.is_empty()) {
- params.error_message_add(NodeWarningType::Error,
- TIP_("The source geometry must contain a mesh"));
- }
- return return_default();
- }
- if (mesh->totpoly == 0) {
- /* Don't add a warning for empty meshes. */
- if (mesh->totvert != 0) {
- params.error_message_add(NodeWarningType::Error,
- TIP_("The source mesh must have faces"));
- }
- return return_default();
- }
- auto fn = std::make_unique<NearestInterpolatedTransferFunction>(std::move(geometry),
- std::move(field));
- auto op = std::make_shared<FieldOperation>(
- FieldOperation(std::move(fn), {params.extract_input<Field<float3>>("Source Position")}));
- output_field = GField(std::move(op));
- break;
- }
- case GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST: {
- if (geometry.has_curves() && !geometry.has_mesh() && !geometry.has_pointcloud()) {
- params.error_message_add(NodeWarningType::Error,
- TIP_("The source geometry must contain a mesh or a point cloud"));
- return return_default();
- }
- auto fn = std::make_unique<NearestTransferFunction>(
- std::move(geometry), std::move(field), domain);
- auto op = std::make_shared<FieldOperation>(
- FieldOperation(std::move(fn), {params.extract_input<Field<float3>>("Source Position")}));
- output_field = GField(std::move(op));
- break;
- }
- case GEO_NODE_ATTRIBUTE_TRANSFER_INDEX: {
- Field<int> indices = params.extract_input<Field<int>>("Index");
- auto fn = std::make_unique<IndexTransferFunction>(
- std::move(geometry), std::move(field), domain);
- auto op = std::make_shared<FieldOperation>(
- FieldOperation(std::move(fn), {std::move(indices)}));
- output_field = GField(std::move(op));
- break;
- }
- }
-
- output_attribute_field(params, std::move(output_field));
-}
-
-} // namespace blender::nodes::node_geo_transfer_attribute_cc
-
-void register_node_type_geo_transfer_attribute()
-{
- namespace file_ns = blender::nodes::node_geo_transfer_attribute_cc;
-
- static bNodeType ntype;
-
- geo_node_type_base(
- &ntype, GEO_NODE_TRANSFER_ATTRIBUTE, "Transfer Attribute", NODE_CLASS_ATTRIBUTE);
- node_type_init(&ntype, file_ns::node_init);
- node_type_update(&ntype, file_ns::node_update);
- node_type_storage(&ntype,
- "NodeGeometryTransferAttribute",
- node_free_standard_storage,
- node_copy_standard_storage);
- ntype.declare = file_ns::node_declare;
- ntype.geometry_node_execute = file_ns::node_geo_exec;
- ntype.draw_buttons = file_ns::node_layout;
- ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
index 945d5fbdcac..3c8a3f3ca76 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
@@ -11,6 +11,7 @@
#include "DNA_volume_types.h"
#include "BKE_curves.hh"
+#include "BKE_instances.hh"
#include "BKE_mesh.h"
#include "BKE_pointcloud.h"
#include "BKE_volume.h"
@@ -47,7 +48,7 @@ static void transform_mesh(Mesh &mesh, const float4x4 &transform)
static void translate_pointcloud(PointCloud &pointcloud, const float3 translation)
{
- MutableAttributeAccessor attributes = bke::pointcloud_attributes_for_write(pointcloud);
+ MutableAttributeAccessor attributes = pointcloud.attributes_for_write();
SpanAttributeWriter position = attributes.lookup_or_add_for_write_span<float3>(
"position", ATTR_DOMAIN_POINT);
for (const int i : position.span.index_range()) {
@@ -58,7 +59,7 @@ static void translate_pointcloud(PointCloud &pointcloud, const float3 translatio
static void transform_pointcloud(PointCloud &pointcloud, const float4x4 &transform)
{
- MutableAttributeAccessor attributes = bke::pointcloud_attributes_for_write(pointcloud);
+ MutableAttributeAccessor attributes = pointcloud.attributes_for_write();
SpanAttributeWriter position = attributes.lookup_or_add_for_write_span<float3>(
"position", ATTR_DOMAIN_POINT);
for (const int i : position.span.index_range()) {
@@ -67,60 +68,77 @@ static void transform_pointcloud(PointCloud &pointcloud, const float4x4 &transfo
position.finish();
}
-static void translate_instances(InstancesComponent &instances, const float3 translation)
+static void translate_instances(bke::Instances &instances, const float3 translation)
{
- MutableSpan<float4x4> transforms = instances.instance_transforms();
+ MutableSpan<float4x4> transforms = instances.transforms();
for (float4x4 &transform : transforms) {
add_v3_v3(transform.ptr()[3], translation);
}
}
-static void transform_instances(InstancesComponent &instances, const float4x4 &transform)
+static void transform_instances(bke::Instances &instances, const float4x4 &transform)
{
- MutableSpan<float4x4> instance_transforms = instances.instance_transforms();
- for (float4x4 &instance_transform : instance_transforms) {
+ MutableSpan<float4x4> transforms = instances.transforms();
+ for (float4x4 &instance_transform : transforms) {
instance_transform = transform * instance_transform;
}
}
-static void transform_volume(Volume &volume, const float4x4 &transform, const Depsgraph &depsgraph)
+static void transform_volume(GeoNodeExecParams &params,
+ Volume &volume,
+ const float4x4 &transform,
+ const Depsgraph &depsgraph)
{
#ifdef WITH_OPENVDB
- /* Scaling an axis to zero is not supported for volumes. */
- const float3 translation = transform.translation();
- const float3 rotation = transform.to_euler();
- const float3 scale = transform.scale();
- const float3 limited_scale = {
- (scale.x == 0.0f) ? FLT_EPSILON : scale.x,
- (scale.y == 0.0f) ? FLT_EPSILON : scale.y,
- (scale.z == 0.0f) ? FLT_EPSILON : scale.z,
- };
- const float4x4 scale_limited_transform = float4x4::from_loc_eul_scale(
- translation, rotation, limited_scale);
-
const Main *bmain = DEG_get_bmain(&depsgraph);
BKE_volume_load(&volume, bmain);
openvdb::Mat4s vdb_matrix;
- memcpy(vdb_matrix.asPointer(), &scale_limited_transform, sizeof(float[4][4]));
+ memcpy(vdb_matrix.asPointer(), &transform, sizeof(float[4][4]));
openvdb::Mat4d vdb_matrix_d{vdb_matrix};
+ bool found_too_small_scale = false;
const int grids_num = BKE_volume_num_grids(&volume);
for (const int i : IndexRange(grids_num)) {
VolumeGrid *volume_grid = BKE_volume_grid_get_for_write(&volume, i);
-
- openvdb::GridBase::Ptr grid = BKE_volume_grid_openvdb_for_write(&volume, volume_grid, false);
- openvdb::math::Transform &grid_transform = grid->transform();
- grid_transform.postMult(vdb_matrix_d);
+ float4x4 grid_matrix;
+ BKE_volume_grid_transform_matrix(volume_grid, grid_matrix.values);
+ mul_m4_m4_pre(grid_matrix.values, transform.values);
+ const float determinant = determinant_m4(grid_matrix.values);
+ if (!BKE_volume_grid_determinant_valid(determinant)) {
+ found_too_small_scale = true;
+ /* Clear the tree because it is too small. */
+ BKE_volume_grid_clear_tree(volume, *volume_grid);
+ if (determinant == 0) {
+ /* Reset rotation and scale. */
+ copy_v3_fl3(grid_matrix.values[0], 1, 0, 0);
+ copy_v3_fl3(grid_matrix.values[1], 0, 1, 0);
+ copy_v3_fl3(grid_matrix.values[2], 0, 0, 1);
+ }
+ else {
+ /* Keep rotation but reset scale. */
+ normalize_v3(grid_matrix.values[0]);
+ normalize_v3(grid_matrix.values[1]);
+ normalize_v3(grid_matrix.values[2]);
+ }
+ }
+ BKE_volume_grid_transform_matrix_set(volume_grid, grid_matrix.values);
+ }
+ if (found_too_small_scale) {
+ params.error_message_add(NodeWarningType::Warning,
+ TIP_("Volume scale is lower than permitted by OpenVDB"));
}
#else
- UNUSED_VARS(volume, transform, depsgraph);
+ UNUSED_VARS(params, volume, transform, depsgraph);
#endif
}
-static void translate_volume(Volume &volume, const float3 translation, const Depsgraph &depsgraph)
+static void translate_volume(GeoNodeExecParams &params,
+ Volume &volume,
+ const float3 translation,
+ const Depsgraph &depsgraph)
{
- transform_volume(volume, float4x4::from_location(translation), depsgraph);
+ transform_volume(params, volume, float4x4::from_location(translation), depsgraph);
}
static void transform_curve_edit_hints(bke::CurvesEditHints &edit_hints, const float4x4 &transform)
@@ -151,7 +169,8 @@ static void translate_curve_edit_hints(bke::CurvesEditHints &edit_hints, const f
}
}
-static void translate_geometry_set(GeometrySet &geometry,
+static void translate_geometry_set(GeoNodeExecParams &params,
+ GeometrySet &geometry,
const float3 translation,
const Depsgraph &depsgraph)
{
@@ -165,17 +184,18 @@ static void translate_geometry_set(GeometrySet &geometry,
translate_pointcloud(*pointcloud, translation);
}
if (Volume *volume = geometry.get_volume_for_write()) {
- translate_volume(*volume, translation, depsgraph);
+ translate_volume(params, *volume, translation, depsgraph);
}
- if (geometry.has_instances()) {
- translate_instances(geometry.get_component_for_write<InstancesComponent>(), translation);
+ if (bke::Instances *instances = geometry.get_instances_for_write()) {
+ translate_instances(*instances, translation);
}
if (bke::CurvesEditHints *curve_edit_hints = geometry.get_curve_edit_hints_for_write()) {
translate_curve_edit_hints(*curve_edit_hints, translation);
}
}
-void transform_geometry_set(GeometrySet &geometry,
+void transform_geometry_set(GeoNodeExecParams &params,
+ GeometrySet &geometry,
const float4x4 &transform,
const Depsgraph &depsgraph)
{
@@ -189,10 +209,10 @@ void transform_geometry_set(GeometrySet &geometry,
transform_pointcloud(*pointcloud, transform);
}
if (Volume *volume = geometry.get_volume_for_write()) {
- transform_volume(*volume, transform, depsgraph);
+ transform_volume(params, *volume, transform, depsgraph);
}
- if (geometry.has_instances()) {
- transform_instances(geometry.get_component_for_write<InstancesComponent>(), transform);
+ if (bke::Instances *instances = geometry.get_instances_for_write()) {
+ transform_instances(*instances, transform);
}
if (bke::CurvesEditHints *curve_edit_hints = geometry.get_curve_edit_hints_for_write()) {
transform_curve_edit_hints(*curve_edit_hints, transform);
@@ -230,10 +250,11 @@ static void node_geo_exec(GeoNodeExecParams params)
/* Use only translation if rotation and scale don't apply. */
if (use_translate(rotation, scale)) {
- translate_geometry_set(geometry_set, translation, *params.depsgraph());
+ translate_geometry_set(params, geometry_set, translation, *params.depsgraph());
}
else {
- transform_geometry_set(geometry_set,
+ transform_geometry_set(params,
+ geometry_set,
float4x4::from_loc_eul_scale(translation, rotation, scale),
*params.depsgraph());
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
index ae538072e65..23052abddc4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
@@ -2,6 +2,8 @@
#include "BLI_task.hh"
+#include "BKE_instances.hh"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_translate_instances_cc {
@@ -15,11 +17,10 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Instances"));
}
-static void translate_instances(GeoNodeExecParams &params, InstancesComponent &instances_component)
+static void translate_instances(GeoNodeExecParams &params, bke::Instances &instances)
{
- GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE};
-
- fn::FieldEvaluator evaluator{field_context, instances_component.instances_num()};
+ const bke::InstancesFieldContext context{instances};
+ fn::FieldEvaluator evaluator{context, instances.instances_num()};
evaluator.set_selection(params.extract_input<Field<bool>>("Selection"));
evaluator.add(params.extract_input<Field<float3>>("Translation"));
evaluator.add(params.extract_input<Field<bool>>("Local Space"));
@@ -29,16 +30,16 @@ static void translate_instances(GeoNodeExecParams &params, InstancesComponent &i
const VArray<float3> translations = evaluator.get_evaluated<float3>(0);
const VArray<bool> local_spaces = evaluator.get_evaluated<bool>(1);
- MutableSpan<float4x4> instance_transforms = instances_component.instance_transforms();
+ MutableSpan<float4x4> transforms = instances.transforms();
threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
for (const int i_selection : range) {
const int i = selection[i_selection];
if (local_spaces[i]) {
- instance_transforms[i] *= float4x4::from_location(translations[i]);
+ transforms[i] *= float4x4::from_location(translations[i]);
}
else {
- add_v3_v3(instance_transforms[i].values[3], translations[i]);
+ add_v3_v3(transforms[i].values[3], translations[i]);
}
}
});
@@ -47,9 +48,8 @@ static void translate_instances(GeoNodeExecParams &params, InstancesComponent &i
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances");
- if (geometry_set.has_instances()) {
- InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
- translate_instances(params, instances);
+ if (bke::Instances *instances = geometry_set.get_instances_for_write()) {
+ translate_instances(params, *instances);
}
params.set_output("Instances", std::move(geometry_set));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
index 992470e8279..cedc1ef845b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
@@ -23,13 +23,13 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "quad_method", 0, "", ICON_NONE);
uiItemR(layout, ptr, "ngon_method", 0, "", ICON_NONE);
}
-static void geo_triangulate_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void geo_triangulate_init(bNodeTree * /*tree*/, bNode *node)
{
node->custom1 = GEO_NODE_TRIANGULATE_QUAD_SHORTEDGE;
node->custom2 = GEO_NODE_TRIANGULATE_NGON_BEAUTY;
@@ -47,9 +47,6 @@ static Mesh *triangulate_mesh_selection(const Mesh &mesh,
BMeshFromMeshParams from_mesh_params{};
from_mesh_params.calc_face_normal = true;
from_mesh_params.calc_vert_normal = true;
- from_mesh_params.add_key_index = true;
- from_mesh_params.use_shapekey = true;
- from_mesh_params.active_shapekey = 1;
from_mesh_params.cd_mask_extra = cd_mask_extra;
BMesh *bm = BKE_mesh_to_bmesh_ex(&mesh, &create_params, &from_mesh_params);
@@ -71,21 +68,17 @@ static void node_geo_exec(GeoNodeExecParams params)
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
const int min_vertices = std::max(params.extract_input<int>("Minimum Vertices"), 4);
- GeometryNodeTriangulateQuads quad_method = static_cast<GeometryNodeTriangulateQuads>(
- params.node().custom1);
- GeometryNodeTriangulateNGons ngon_method = static_cast<GeometryNodeTriangulateNGons>(
- params.node().custom2);
+ GeometryNodeTriangulateQuads quad_method = GeometryNodeTriangulateQuads(params.node().custom1);
+ GeometryNodeTriangulateNGons ngon_method = GeometryNodeTriangulateNGons(params.node().custom2);
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
if (!geometry_set.has_mesh()) {
return;
}
- GeometryComponent &component = geometry_set.get_component_for_write<MeshComponent>();
const Mesh &mesh_in = *geometry_set.get_mesh_for_read();
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
- GeometryComponentFieldContext context{component, ATTR_DOMAIN_FACE};
- FieldEvaluator evaluator{context, domain_size};
+ bke::MeshFieldContext context{mesh_in, ATTR_DOMAIN_FACE};
+ FieldEvaluator evaluator{context, mesh_in.totpoly};
evaluator.add(selection_field);
evaluator.evaluate();
const IndexMask selection = evaluator.get_evaluated_as_mask(0);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc b/source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc
index 17413e64f7d..c2d27cffa93 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc
@@ -5,6 +5,8 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "BKE_mesh.h"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_uv_pack_islands_cc {
@@ -28,21 +30,19 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Vector>(N_("UV")).field_source();
}
-static VArray<float3> construct_uv_gvarray(const MeshComponent &component,
+static VArray<float3> construct_uv_gvarray(const Mesh &mesh,
const Field<bool> selection_field,
const Field<float3> uv_field,
const bool rotate,
const float margin,
const eAttrDomain domain)
{
- const Mesh *mesh = component.get_for_read();
- if (mesh == nullptr) {
- return {};
- }
+ const Span<MVert> verts = mesh.verts();
+ const Span<MPoly> polys = mesh.polys();
+ const Span<MLoop> loops = mesh.loops();
- const int face_num = component.attribute_domain_size(ATTR_DOMAIN_FACE);
- GeometryComponentFieldContext face_context{component, ATTR_DOMAIN_FACE};
- FieldEvaluator face_evaluator{face_context, face_num};
+ bke::MeshFieldContext face_context{mesh, ATTR_DOMAIN_FACE};
+ FieldEvaluator face_evaluator{face_context, polys.size()};
face_evaluator.add(selection_field);
face_evaluator.evaluate();
const IndexMask selection = face_evaluator.get_evaluated_as_mask(0);
@@ -50,25 +50,24 @@ static VArray<float3> construct_uv_gvarray(const MeshComponent &component,
return {};
}
- const int corner_num = component.attribute_domain_size(ATTR_DOMAIN_CORNER);
- GeometryComponentFieldContext corner_context{component, ATTR_DOMAIN_CORNER};
- FieldEvaluator evaluator{corner_context, corner_num};
- Array<float3> uv(corner_num);
+ bke::MeshFieldContext corner_context{mesh, ATTR_DOMAIN_CORNER};
+ FieldEvaluator evaluator{corner_context, mesh.totloop};
+ Array<float3> uv(mesh.totloop);
evaluator.add_with_destination(uv_field, uv.as_mutable_span());
evaluator.evaluate();
ParamHandle *handle = GEO_uv_parametrizer_construct_begin();
for (const int mp_index : selection) {
- const MPoly &mp = mesh->mpoly[mp_index];
+ const MPoly &mp = polys[mp_index];
Array<ParamKey, 16> mp_vkeys(mp.totloop);
Array<bool, 16> mp_pin(mp.totloop);
Array<bool, 16> mp_select(mp.totloop);
Array<const float *, 16> mp_co(mp.totloop);
Array<float *, 16> mp_uv(mp.totloop);
for (const int i : IndexRange(mp.totloop)) {
- const MLoop &ml = mesh->mloop[mp.loopstart + i];
+ const MLoop &ml = loops[mp.loopstart + i];
mp_vkeys[i] = ml.v;
- mp_co[i] = mesh->mvert[ml.v].co;
+ mp_co[i] = verts[ml.v].co;
mp_uv[i] = uv[mp.loopstart + i];
mp_pin[i] = false;
mp_select[i] = false;
@@ -88,11 +87,11 @@ static VArray<float3> construct_uv_gvarray(const MeshComponent &component,
GEO_uv_parametrizer_flush(handle);
GEO_uv_parametrizer_delete(handle);
- return component.attributes()->adapt_domain<float3>(
+ return mesh.attributes().adapt_domain<float3>(
VArray<float3>::ForContainer(std::move(uv)), ATTR_DOMAIN_CORNER, domain);
}
-class PackIslandsFieldInput final : public GeometryFieldInput {
+class PackIslandsFieldInput final : public bke::MeshFieldInput {
private:
const Field<bool> selection_field;
const Field<float3> uv_field;
@@ -104,7 +103,7 @@ class PackIslandsFieldInput final : public GeometryFieldInput {
const Field<float3> uv_field,
const bool rotate,
const float margin)
- : GeometryFieldInput(CPPType::get<float3>(), "Pack UV Islands Field"),
+ : bke::MeshFieldInput(CPPType::get<float3>(), "Pack UV Islands Field"),
selection_field(selection_field),
uv_field(uv_field),
rotate(rotate),
@@ -113,16 +112,16 @@ class PackIslandsFieldInput final : public GeometryFieldInput {
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
+ GVArray get_varray_for_context(const Mesh &mesh,
const eAttrDomain domain,
- IndexMask UNUSED(mask)) const final
+ const IndexMask /*mask*/) const final
{
- if (component.type() == GEO_COMPONENT_TYPE_MESH) {
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- return construct_uv_gvarray(
- mesh_component, selection_field, uv_field, rotate, margin, domain);
- }
- return {};
+ return construct_uv_gvarray(mesh, selection_field, uv_field, rotate, margin, domain);
+ }
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_CORNER;
}
};
diff --git a/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc b/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc
index 03657f3e016..e45ce6b42b4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc
@@ -5,6 +5,8 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "BKE_mesh.h"
+
#include "UI_interface.h"
#include "UI_resources.h"
@@ -38,21 +40,21 @@ static void node_declare(NodeDeclarationBuilder &b)
N_("UV coordinates between 0 and 1 for each face corner in the selected faces"));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "method", 0, "", ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryUVUnwrap *data = MEM_cnew<NodeGeometryUVUnwrap>(__func__);
data->method = GEO_NODE_UV_UNWRAP_METHOD_ANGLE_BASED;
node->storage = data;
}
-static VArray<float3> construct_uv_gvarray(const MeshComponent &component,
+static VArray<float3> construct_uv_gvarray(const Mesh &mesh,
const Field<bool> selection_field,
const Field<bool> seam_field,
const bool fill_holes,
@@ -60,14 +62,13 @@ static VArray<float3> construct_uv_gvarray(const MeshComponent &component,
const GeometryNodeUVUnwrapMethod method,
const eAttrDomain domain)
{
- const Mesh *mesh = component.get_for_read();
- if (mesh == nullptr) {
- return {};
- }
+ const Span<MVert> verts = mesh.verts();
+ const Span<MEdge> edges = mesh.edges();
+ const Span<MPoly> polys = mesh.polys();
+ const Span<MLoop> loops = mesh.loops();
- const int face_num = component.attribute_domain_size(ATTR_DOMAIN_FACE);
- GeometryComponentFieldContext face_context{component, ATTR_DOMAIN_FACE};
- FieldEvaluator face_evaluator{face_context, face_num};
+ bke::MeshFieldContext face_context{mesh, ATTR_DOMAIN_FACE};
+ FieldEvaluator face_evaluator{face_context, polys.size()};
face_evaluator.add(selection_field);
face_evaluator.evaluate();
const IndexMask selection = face_evaluator.get_evaluated_as_mask(0);
@@ -75,27 +76,26 @@ static VArray<float3> construct_uv_gvarray(const MeshComponent &component,
return {};
}
- const int edge_num = component.attribute_domain_size(ATTR_DOMAIN_EDGE);
- GeometryComponentFieldContext edge_context{component, ATTR_DOMAIN_EDGE};
- FieldEvaluator edge_evaluator{edge_context, edge_num};
+ bke::MeshFieldContext edge_context{mesh, ATTR_DOMAIN_EDGE};
+ FieldEvaluator edge_evaluator{edge_context, edges.size()};
edge_evaluator.add(seam_field);
edge_evaluator.evaluate();
const IndexMask seam = edge_evaluator.get_evaluated_as_mask(0);
- Array<float3> uv(mesh->totloop, float3(0));
+ Array<float3> uv(loops.size(), float3(0));
ParamHandle *handle = GEO_uv_parametrizer_construct_begin();
for (const int mp_index : selection) {
- const MPoly &mp = mesh->mpoly[mp_index];
+ const MPoly &mp = polys[mp_index];
Array<ParamKey, 16> mp_vkeys(mp.totloop);
Array<bool, 16> mp_pin(mp.totloop);
Array<bool, 16> mp_select(mp.totloop);
Array<const float *, 16> mp_co(mp.totloop);
Array<float *, 16> mp_uv(mp.totloop);
for (const int i : IndexRange(mp.totloop)) {
- const MLoop &ml = mesh->mloop[mp.loopstart + i];
+ const MLoop &ml = loops[mp.loopstart + i];
mp_vkeys[i] = ml.v;
- mp_co[i] = mesh->mvert[ml.v].co;
+ mp_co[i] = verts[ml.v].co;
mp_uv[i] = uv[mp.loopstart + i];
mp_pin[i] = false;
mp_select[i] = false;
@@ -110,7 +110,7 @@ static VArray<float3> construct_uv_gvarray(const MeshComponent &component,
mp_select.data());
}
for (const int i : seam) {
- const MEdge &edge = mesh->medge[i];
+ const MEdge &edge = edges[i];
ParamKey vkeys[2]{edge.v1, edge.v2};
GEO_uv_parametrizer_edge_set_seam(handle, vkeys);
}
@@ -126,11 +126,11 @@ static VArray<float3> construct_uv_gvarray(const MeshComponent &component,
GEO_uv_parametrizer_flush(handle);
GEO_uv_parametrizer_delete(handle);
- return component.attributes()->adapt_domain<float3>(
+ return mesh.attributes().adapt_domain<float3>(
VArray<float3>::ForContainer(std::move(uv)), ATTR_DOMAIN_CORNER, domain);
}
-class UnwrapFieldInput final : public GeometryFieldInput {
+class UnwrapFieldInput final : public bke::MeshFieldInput {
private:
const Field<bool> selection;
const Field<bool> seam;
@@ -144,7 +144,7 @@ class UnwrapFieldInput final : public GeometryFieldInput {
const bool fill_holes,
const float margin,
const GeometryNodeUVUnwrapMethod method)
- : GeometryFieldInput(CPPType::get<float3>(), "UV Unwrap Field"),
+ : bke::MeshFieldInput(CPPType::get<float3>(), "UV Unwrap Field"),
selection(selection),
seam(seam),
fill_holes(fill_holes),
@@ -154,16 +154,16 @@ class UnwrapFieldInput final : public GeometryFieldInput {
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
+ GVArray get_varray_for_context(const Mesh &mesh,
const eAttrDomain domain,
- IndexMask UNUSED(mask)) const final
+ const IndexMask /*mask*/) const final
{
- if (component.type() == GEO_COMPONENT_TYPE_MESH) {
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- return construct_uv_gvarray(
- mesh_component, selection, seam, fill_holes, margin, method, domain);
- }
- return {};
+ return construct_uv_gvarray(mesh, selection, seam, fill_holes, margin, method, domain);
+ }
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_CORNER;
}
};
diff --git a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
index 6979693e215..e9050f9e6a1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
@@ -6,7 +6,7 @@
#include "UI_resources.h"
#include "ED_node.h"
-#include "ED_spreadsheet.h"
+#include "ED_viewer_path.hh"
#include "NOD_socket_search_link.hh"
@@ -26,15 +26,21 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Bool>(N_("Value"), "Value_004").supports_field().hide_value();
}
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryViewer *data = MEM_cnew<NodeGeometryViewer>(__func__);
data->data_type = CD_PROP_FLOAT;
+ data->domain = ATTR_DOMAIN_AUTO;
node->storage = data;
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
+}
+
+static void node_layout_ex(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
}
@@ -61,7 +67,7 @@ static eNodeSocketDatatype custom_data_type_to_socket_type(const eCustomDataType
static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeGeometryViewer &storage = node_storage(*node);
- const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
+ const eCustomDataType data_type = eCustomDataType(storage.data_type);
const eNodeSocketDatatype socket_type = custom_data_type_to_socket_type(data_type);
LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
@@ -79,7 +85,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
SpaceNode *snode = CTX_wm_space_node(&params.C);
Main *bmain = CTX_data_main(&params.C);
ED_node_set_active(bmain, snode, &params.node_tree, &viewer_node, nullptr);
- ED_spreadsheet_context_paths_set_geometry_node(bmain, snode, &viewer_node);
+ ed::viewer_path::activate_geometry_node(*bmain, *snode, viewer_node);
};
const std::optional<eCustomDataType> type = node_socket_to_custom_data_type(
@@ -132,7 +138,9 @@ void register_node_type_geo_viewer()
node_type_update(&ntype, file_ns::node_update);
node_type_init(&ntype, file_ns::node_init);
ntype.declare = file_ns::node_declare;
- ntype.draw_buttons_ex = file_ns::node_layout;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.draw_buttons_ex = file_ns::node_layout_ex;
ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
+ ntype.no_muting = true;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc
index d7e9e38ea0d..7d439309380 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc
@@ -75,13 +75,12 @@ class Grid3DFieldContext : public FieldContext {
int64_t points_num() const
{
- return static_cast<int64_t>(resolution_.x) * static_cast<int64_t>(resolution_.y) *
- static_cast<int64_t>(resolution_.z);
+ return int64_t(resolution_.x) * int64_t(resolution_.y) * int64_t(resolution_.z);
}
GVArray get_varray_for_input(const FieldInput &field_input,
- const IndexMask UNUSED(mask),
- ResourceScope &UNUSED(scope)) const
+ const IndexMask /*mask*/,
+ ResourceScope & /*scope*/) const
{
const bke::AttributeFieldInput *attribute_field_input =
dynamic_cast<const bke::AttributeFieldInput *>(&field_input);
@@ -113,9 +112,9 @@ class Grid3DFieldContext : public FieldContext {
}
};
-#ifdef WITH_OPENVDB
static void node_geo_exec(GeoNodeExecParams params)
{
+#ifdef WITH_OPENVDB
const float3 bounds_min = params.extract_input<float3>("Min");
const float3 bounds_max = params.extract_input<float3>("Max");
@@ -137,6 +136,14 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
+ const double3 scale_fac = double3(bounds_max - bounds_min) / double3(resolution - 1);
+ if (!BKE_volume_grid_determinant_valid(scale_fac.x * scale_fac.y * scale_fac.z)) {
+ params.error_message_add(NodeWarningType::Warning,
+ TIP_("Volume scale is lower than permitted by OpenVDB"));
+ params.set_default_remaining_outputs();
+ return;
+ }
+
Field<float> input_field = params.extract_input<Field<float>>("Density");
/* Evaluate input field on a 3D grid. */
@@ -157,12 +164,11 @@ static void node_geo_exec(GeoNodeExecParams params)
openvdb::tools::copyFromDense(dense_grid, *grid, 0.0f);
grid->transform().preTranslate(openvdb::math::Vec3<float>(-0.5f));
- const float3 scale_fac = (bounds_max - bounds_min) / float3(resolution - 1);
- grid->transform().postScale(openvdb::math::Vec3<float>(scale_fac.x, scale_fac.y, scale_fac.z));
+ grid->transform().postScale(openvdb::math::Vec3<double>(scale_fac.x, scale_fac.y, scale_fac.z));
grid->transform().postTranslate(
openvdb::math::Vec3<float>(bounds_min.x, bounds_min.y, bounds_min.z));
- Volume *volume = (Volume *)BKE_id_new_nomain(ID_VO, nullptr);
+ Volume *volume = reinterpret_cast<Volume *>(BKE_id_new_nomain(ID_VO, nullptr));
BKE_volume_init_grids(volume);
BKE_volume_grid_add_vdb(*volume, "density", std::move(grid));
@@ -170,16 +176,12 @@ static void node_geo_exec(GeoNodeExecParams params)
GeometrySet r_geometry_set;
r_geometry_set.replace_volume(volume);
params.set_output("Volume", r_geometry_set);
-}
-
#else
-static void node_geo_exec(GeoNodeExecParams params)
-{
+ params.set_default_remaining_outputs();
params.error_message_add(NodeWarningType::Error,
TIP_("Disabled, Blender was compiled without OpenVDB"));
- params.set_default_remaining_outputs();
+#endif
}
-#endif /* WITH_OPENVDB */
} // namespace blender::nodes::node_geo_volume_cube_cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
index 91429560ac8..88e7718ed3c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
@@ -48,14 +48,14 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "resolution_mode", 0, IFACE_("Resolution"), ICON_NONE);
}
-static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryVolumeToMesh *data = MEM_cnew<NodeGeometryVolumeToMesh>(__func__);
data->resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_GRID;
@@ -123,9 +123,9 @@ static Mesh *create_mesh_from_volume_grids(Span<openvdb::GridBase::ConstPtr> gri
Mesh *mesh = BKE_mesh_new_nomain(vert_offset, 0, 0, loop_offset, poly_offset);
BKE_id_material_eval_ensure_default_slot(&mesh->id);
- MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
- MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop};
- MutableSpan<MPoly> polys{mesh->mpoly, mesh->totpoly};
+ MutableSpan<MVert> verts = mesh->verts_for_write();
+ MutableSpan<MPoly> polys = mesh->polys_for_write();
+ MutableSpan<MLoop> loops = mesh->loops_for_write();
for (const int i : grids.index_range()) {
const bke::OpenVDBMeshData &data = mesh_data[i];
@@ -187,20 +187,19 @@ static Mesh *create_mesh_from_volume(GeometrySet &geometry_set, GeoNodeExecParam
static void node_geo_exec(GeoNodeExecParams params)
{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Volume");
-
#ifdef WITH_OPENVDB
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Volume");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
Mesh *mesh = create_mesh_from_volume(geometry_set, params);
geometry_set.replace_mesh(mesh);
geometry_set.keep_only_during_modify({GEO_COMPONENT_TYPE_MESH});
});
+ params.set_output("Mesh", std::move(geometry_set));
#else
+ params.set_default_remaining_outputs();
params.error_message_add(NodeWarningType::Error,
TIP_("Disabled, Blender was compiled without OpenVDB"));
#endif
-
- params.set_output("Mesh", std::move(geometry_set));
}
} // namespace blender::nodes::node_geo_volume_to_mesh_cc