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:
authorHans Goudey <h.goudey@me.com>2022-09-28 07:04:21 +0300
committerHans Goudey <h.goudey@me.com>2022-09-28 07:04:21 +0300
commitc4b7ffa6f50c9680059fd221b5d7391fae6e6f29 (patch)
tree431834a347a5cab1347ff92eb7290a8cebe04079 /source/blender/nodes
parent0f36ad24b5031f78664a935a3c483751e173e308 (diff)
parent788f3d72cf89c0301721a5eb2a72da07058dfa24 (diff)
Merge branch 'master' into refactor-mesh-position-generic
Diffstat (limited to 'source/blender/nodes')
-rw-r--r--source/blender/nodes/NOD_geometry.h5
-rw-r--r--source/blender/nodes/NOD_node_declaration.hh21
-rw-r--r--source/blender/nodes/NOD_static_types.h5
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_blur.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_curves.cc3
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_dilate.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_image.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_scene_time.cc2
-rw-r--r--source/blender/nodes/function/nodes/node_fn_float_to_int.cc8
-rw-r--r--source/blender/nodes/function/nodes/node_fn_random_value.cc2
-rw-r--r--source/blender/nodes/geometry/CMakeLists.txt5
-rw-r--r--source/blender/nodes/geometry/node_geometry_tree.cc2
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.cc2
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.hh9
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_boolean.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_collection_info.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc7
-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.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc26
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc17
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc11
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_image_texture.cc22
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_control_point_neighbors.cc177
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_material.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_interpolate_domain.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc31
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc2
-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.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc11
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_volume.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_proximity.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_raycast.cc12
-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.cc344
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc280
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_id.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_position.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_switch.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc829
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_triangulate.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_viewer.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc5
-rw-r--r--source/blender/nodes/intern/geometry_nodes_lazy_function.cc67
-rw-r--r--source/blender/nodes/intern/geometry_nodes_log.cc4
-rw-r--r--source/blender/nodes/intern/node_common.cc2
-rw-r--r--source/blender/nodes/intern/node_declaration.cc27
-rw-r--r--source/blender/nodes/intern/node_socket.cc8
-rw-r--r--source/blender/nodes/shader/node_shader_tree.cc4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_brick.cc11
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_checker.cc11
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_image.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_magic.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_noise.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_sky.cc8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_wave.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc7
93 files changed, 1464 insertions, 1119 deletions
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index 7c2cec873c0..4ead6326295 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -61,6 +61,7 @@ void register_node_type_geo_field_at_index(void);
void register_node_type_geo_flip_faces(void);
void register_node_type_geo_geometry_to_instance(void);
void register_node_type_geo_image_texture(void);
+void register_node_type_geo_input_control_point_neighbors(void);
void register_node_type_geo_input_curve_handles(void);
void register_node_type_geo_input_curve_tilt(void);
void register_node_type_geo_input_id(void);
@@ -118,6 +119,9 @@ void register_node_type_geo_raycast(void);
void register_node_type_geo_realize_instances(void);
void register_node_type_geo_remove_attribute(void);
void register_node_type_geo_rotate_instances(void);
+void register_node_type_geo_sample_index(void);
+void register_node_type_geo_sample_nearest_surface(void);
+void register_node_type_geo_sample_nearest(void);
void register_node_type_geo_scale_elements(void);
void register_node_type_geo_scale_instances(void);
void register_node_type_geo_select_by_handle_type(void);
@@ -140,7 +144,6 @@ void register_node_type_geo_string_join(void);
void register_node_type_geo_string_to_curves(void);
void register_node_type_geo_subdivision_surface(void);
void register_node_type_geo_switch(void);
-void register_node_type_geo_transfer_attribute(void);
void register_node_type_geo_transform(void);
void register_node_type_geo_translate_instances(void);
void register_node_type_geo_triangulate(void);
diff --git a/source/blender/nodes/NOD_node_declaration.hh b/source/blender/nodes/NOD_node_declaration.hh
index 42755b2e8dd..13f8af4ddf5 100644
--- a/source/blender/nodes/NOD_node_declaration.hh
+++ b/source/blender/nodes/NOD_node_declaration.hh
@@ -65,6 +65,8 @@ struct FieldInferencingInterface {
Vector<OutputFieldDependency> outputs;
};
+using ImplicitInputValueFn = std::function<void(const bNode &node, void *r_value)>;
+
/**
* Describes a single input or output socket. This is subclassed for different socket types.
*/
@@ -103,6 +105,10 @@ class SocketDeclaration {
/** Utility method to make the socket available if there is a straightforward way to do so. */
std::function<void(bNode &)> make_available_fn_;
+ /** Some input sockets can have non-trivial values in the case when they are unlinked. This
+ * callback computes the default input of a values in geometry nodes when nothing is linked. */
+ std::unique_ptr<ImplicitInputValueFn> implicit_input_fn_;
+
friend NodeDeclarationBuilder;
template<typename SocketDecl> friend class SocketDeclarationBuilder;
@@ -140,6 +146,11 @@ class SocketDeclaration {
bool compositor_skip_realization() const;
bool compositor_expects_single_value() const;
+ const ImplicitInputValueFn *implicit_input_fn() const
+ {
+ return implicit_input_fn_.get();
+ }
+
protected:
void set_common_flags(bNodeSocket &socket) const;
bool matches_common_data(const bNodeSocket &socket) const;
@@ -225,10 +236,11 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
}
/** The input supports a field and is a field by default when nothing is connected. */
- Self &implicit_field()
+ Self &implicit_field(ImplicitInputValueFn fn)
{
this->hide_value();
decl_->input_field_type_ = InputSocketFieldType::Implicit;
+ decl_->implicit_input_fn_ = std::make_unique<ImplicitInputValueFn>(std::move(fn));
return *(Self *)this;
}
@@ -348,6 +360,13 @@ class NodeDeclarationBuilder {
eNodeSocketInOut in_out);
};
+namespace implicit_field_inputs {
+void position(const bNode &node, void *r_value);
+void normal(const bNode &node, void *r_value);
+void index(const bNode &node, void *r_value);
+void id_or_index(const bNode &node, void *r_value);
+} // namespace implicit_field_inputs
+
/* -------------------------------------------------------------------- */
/** \name #OutputFieldDependency Inline Methods
* \{ */
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 4b055962b58..574a8dcab96 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -319,6 +319,7 @@ DefNode(GeometryNode, GEO_NODE_FLIP_FACES, 0, "FLIP_FACES", FlipFaces, "Flip Fac
DefNode(GeometryNode, GEO_NODE_GEOMETRY_TO_INSTANCE, 0, "GEOMETRY_TO_INSTANCE", GeometryToInstance, "Geometry to Instance", "Convert each input geometry into an instance, which can be much faster than the Join Geometry node when the inputs are large")
DefNode(GeometryNode, GEO_NODE_IMAGE_TEXTURE, def_geo_image_texture, "IMAGE_TEXTURE", ImageTexture, "Image Texture", "Sample values from an image texture")
DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_HANDLES, 0, "INPUT_CURVE_HANDLES",InputCurveHandlePositions,"Curve Handle Positions", "Retrieve the position of each Bézier control point's handles")
+DefNode(GeometryNode, GEO_NODE_INPUT_CONTROL_POINT_NEIGHBORS, 0, "INPUT_CONTROL_POINT_NEIGHBORS", InputControlPointNeighbors, "Control Point Neighbors", "Offset a control point index within its curve")
DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_TILT, 0, "INPUT_CURVE_TILT", InputCurveTilt, "Curve Tilt", "Retrieve the angle at each control point used to twist the curve's normal around its tangent")
DefNode(GeometryNode, GEO_NODE_INPUT_ID, 0, "INPUT_ID", InputID, "ID", "Retrieve a stable random identifier value from the \"id\" attribute on the point domain, or the index if the attribute does not exist")
DefNode(GeometryNode, GEO_NODE_INPUT_INDEX, 0, "INDEX", InputIndex, "Index", "Retrieve an integer value indicating the position of each element in the list, starting at zero")
@@ -378,6 +379,9 @@ DefNode(GeometryNode, GEO_NODE_RESAMPLE_CURVE, def_geo_curve_resample, "RESAMPLE
DefNode(GeometryNode, GEO_NODE_REVERSE_CURVE, 0, "REVERSE_CURVE", ReverseCurve, "Reverse Curve", "Swap the start and end of splines")
DefNode(GeometryNode, GEO_NODE_ROTATE_INSTANCES, 0, "ROTATE_INSTANCES", RotateInstances, "Rotate Instances", "Rotate geometry instances in local or global space")
DefNode(GeometryNode, GEO_NODE_SAMPLE_CURVE, def_geo_curve_sample, "SAMPLE_CURVE", SampleCurve, "Sample Curve", "Retrieve data from a point on a curve at a certain distance from its start")
+DefNode(GeometryNode, GEO_NODE_SAMPLE_INDEX, def_geo_sample_index, "SAMPLE_INDEX", SampleIndex, "Sample Index", "Retrieve values from specific geometry elements")
+DefNode(GeometryNode, GEO_NODE_SAMPLE_NEAREST_SURFACE, def_geo_sample_nearest_surface, "SAMPLE_NEAREST_SURFACE", SampleNearestSurface, "Sample Nearest Surface", "Calculate the interpolated value of a mesh attribute on the closest point of its surface")
+DefNode(GeometryNode, GEO_NODE_SAMPLE_NEAREST, def_geo_sample_nearest, "SAMPLE_NEAREST", SampleNearest, "Sample Nearest", "Find the element of a geometry closest to a position")
DefNode(GeometryNode, GEO_NODE_SCALE_ELEMENTS, def_geo_scale_elements, "SCALE_ELEMENTS", ScaleElements, "Scale Elements", "Scale groups of connected edges and faces")
DefNode(GeometryNode, GEO_NODE_SCALE_INSTANCES, 0, "SCALE_INSTANCES", ScaleInstances, "Scale Instances", "Scale geometry instances in local or global space")
DefNode(GeometryNode, GEO_NODE_SEPARATE_COMPONENTS, 0, "SEPARATE_COMPONENTS",SeparateComponents, "Separate Components","Split a geometry into a separate output for each type of data in the geometry")
@@ -402,7 +406,6 @@ DefNode(GeometryNode, GEO_NODE_SUBDIVIDE_CURVE, 0, "SUBDIVIDE_CURVE", SubdivideC
DefNode(GeometryNode, GEO_NODE_SUBDIVIDE_MESH, 0, "SUBDIVIDE_MESH", SubdivideMesh, "Subdivide Mesh", "Divide mesh faces into smaller ones without changing the shape or volume, using linear interpolation to place the new vertices")
DefNode(GeometryNode, GEO_NODE_SUBDIVISION_SURFACE, def_geo_subdivision_surface, "SUBDIVISION_SURFACE",SubdivisionSurface, "Subdivision Surface","Divide mesh faces to form a smooth surface, using the Catmull-Clark subdivision method")
DefNode(GeometryNode, GEO_NODE_SWITCH, def_geo_switch, "SWITCH", Switch, "Switch", "Switch between two inputs")
-DefNode(GeometryNode, GEO_NODE_TRANSFER_ATTRIBUTE, def_geo_transfer_attribute, "ATTRIBUTE_TRANSFER", AttributeTransfer, "Transfer Attribute", "Retrieve values from a source geometry and provides them as a field by interpolating them with the context geometry")
DefNode(GeometryNode, GEO_NODE_TRANSFORM, 0, "TRANSFORM", Transform, "Transform", "Translate, rotate or scale the geometry")
DefNode(GeometryNode, GEO_NODE_TRANSLATE_INSTANCES, 0, "TRANSLATE_INSTANCES",TranslateInstances, "Translate Instances","Move top-level geometry instances in local or global space")
DefNode(GeometryNode, GEO_NODE_TRIANGULATE, def_geo_triangulate, "TRIANGULATE", Triangulate, "Triangulate", "Convert all faces in a mesh to triangular faces")
diff --git a/source/blender/nodes/composite/nodes/node_composite_blur.cc b/source/blender/nodes/composite/nodes/node_composite_blur.cc
index 630f18361e3..af7dca32c0d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_blur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_blur.cc
@@ -346,7 +346,7 @@ class BlurOperation : public NodeOperation {
Domain domain = compute_domain();
if (get_extend_bounds()) {
- domain.size.x += static_cast<int>(math::ceil(compute_blur_radius().x)) * 2;
+ domain.size.x += int(math::ceil(compute_blur_radius().x)) * 2;
}
/* We allocate an output image of a transposed size, that is, with a height equivalent to the
diff --git a/source/blender/nodes/composite/nodes/node_composite_curves.cc b/source/blender/nodes/composite/nodes/node_composite_curves.cc
index bf45e219730..70bd4d17007 100644
--- a/source/blender/nodes/composite/nodes/node_composite_curves.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_curves.cc
@@ -80,8 +80,7 @@ class TimeCurveOperation : public NodeOperation {
if (get_start_time() == get_end_time()) {
return 0.0f;
}
- return static_cast<float>(frame_number - get_start_time()) /
- static_cast<float>(get_end_time() - get_start_time());
+ return float(frame_number - get_start_time()) / float(get_end_time() - get_start_time());
}
};
diff --git a/source/blender/nodes/composite/nodes/node_composite_dilate.cc b/source/blender/nodes/composite/nodes/node_composite_dilate.cc
index 551dfacb276..0cf0c5cc80b 100644
--- a/source/blender/nodes/composite/nodes/node_composite_dilate.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_dilate.cc
@@ -393,7 +393,7 @@ class DilateErodeOperation : public NodeOperation {
/* See the discussion in the implementation for more information. */
int get_morphological_distance_threshold_radius()
{
- return static_cast<int>(math::ceil(get_inset())) + math::abs(get_distance());
+ return int(math::ceil(get_inset())) + math::abs(get_distance());
}
/* ----------------------------------------
diff --git a/source/blender/nodes/composite/nodes/node_composite_image.cc b/source/blender/nodes/composite/nodes/node_composite_image.cc
index 4d1eff0b940..4b73c1a62fb 100644
--- a/source/blender/nodes/composite/nodes/node_composite_image.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_image.cc
@@ -685,7 +685,7 @@ const char *node_cmp_rlayers_sock_to_pass(int sock_index)
}
const char *name = cmp_node_rlayers_out[sock_index].name;
/* Exception for alpha, which is derived from Combined. */
- return (STREQ(name, "Alpha")) ? RE_PASSNAME_COMBINED : name;
+ return STREQ(name, "Alpha") ? RE_PASSNAME_COMBINED : name;
}
namespace blender::nodes::node_composite_render_layer_cc {
@@ -851,7 +851,7 @@ class RenderLayerOperation : public NodeOperation {
/* Other output passes are not supported for now, so allocate them as invalid. */
for (const bNodeSocket *output : this->node()->output_sockets()) {
- if (!STREQ(output->identifier, "Image") && !STREQ(output->identifier, "Alpha")) {
+ if (!STR_ELEM(output->identifier, "Image", "Alpha")) {
get_result(output->identifier).allocate_invalid();
}
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_scene_time.cc b/source/blender/nodes/composite/nodes/node_composite_scene_time.cc
index 1f5317378bb..3a7e7dc78bd 100644
--- a/source/blender/nodes/composite/nodes/node_composite_scene_time.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_scene_time.cc
@@ -38,7 +38,7 @@ class SceneTimeOperation : public NodeOperation {
{
Result &result = get_result("Frame");
result.allocate_single_value();
- result.set_float_value(static_cast<float>(context().get_frame_number()));
+ result.set_float_value(float(context().get_frame_number()));
}
};
diff --git a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc
index aad2f532d20..452768208c5 100644
--- a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc
+++ b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc
@@ -43,13 +43,13 @@ static const fn::MultiFunction *get_multi_function(const bNode &bnode)
{
static auto exec_preset = fn::CustomMF_presets::AllSpanOrSingle();
static fn::CustomMF_SI_SO<float, int> round_fn{
- "Round", [](float a) { return (int)round(a); }, exec_preset};
+ "Round", [](float a) { return int(round(a)); }, exec_preset};
static fn::CustomMF_SI_SO<float, int> floor_fn{
- "Floor", [](float a) { return (int)floor(a); }, exec_preset};
+ "Floor", [](float a) { return int(floor(a)); }, exec_preset};
static fn::CustomMF_SI_SO<float, int> ceil_fn{
- "Ceiling", [](float a) { return (int)ceil(a); }, exec_preset};
+ "Ceiling", [](float a) { return int(ceil(a)); }, exec_preset};
static fn::CustomMF_SI_SO<float, int> trunc_fn{
- "Truncate", [](float a) { return (int)trunc(a); }, exec_preset};
+ "Truncate", [](float a) { return int(trunc(a)); }, exec_preset};
switch (static_cast<FloatToIntRoundingMode>(bnode.custom1)) {
case FN_NODE_FLOAT_TO_INT_ROUND:
diff --git a/source/blender/nodes/function/nodes/node_fn_random_value.cc b/source/blender/nodes/function/nodes/node_fn_random_value.cc
index 360695299cb..341a3fbfa75 100644
--- a/source/blender/nodes/function/nodes/node_fn_random_value.cc
+++ b/source/blender/nodes/function/nodes/node_fn_random_value.cc
@@ -33,7 +33,7 @@ static void fn_node_random_value_declare(NodeDeclarationBuilder &b)
.subtype(PROP_FACTOR)
.supports_field()
.make_available([](bNode &node) { node_storage(node).data_type = CD_PROP_BOOL; });
- b.add_input<decl::Int>(N_("ID")).implicit_field();
+ b.add_input<decl::Int>(N_("ID")).implicit_field(implicit_field_inputs::id_or_index);
b.add_input<decl::Int>(N_("Seed")).default_value(0).min(-10000).max(10000).supports_field();
b.add_output<decl::Vector>(N_("Value")).dependent_field();
diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt
index f15152fe1c4..b80e87e80ac 100644
--- a/source/blender/nodes/geometry/CMakeLists.txt
+++ b/source/blender/nodes/geometry/CMakeLists.txt
@@ -71,6 +71,7 @@ set(SRC
nodes/node_geo_flip_faces.cc
nodes/node_geo_geometry_to_instance.cc
nodes/node_geo_image_texture.cc
+ nodes/node_geo_input_control_point_neighbors.cc
nodes/node_geo_input_curve_handles.cc
nodes/node_geo_input_curve_tilt.cc
nodes/node_geo_input_id.cc
@@ -128,6 +129,9 @@ 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_surface.cc
+ nodes/node_geo_sample_nearest.cc
nodes/node_geo_scale_elements.cc
nodes/node_geo_scale_instances.cc
nodes/node_geo_separate_components.cc
@@ -149,7 +153,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
diff --git a/source/blender/nodes/geometry/node_geometry_tree.cc b/source/blender/nodes/geometry/node_geometry_tree.cc
index 1a12d2c49e6..61a416765a3 100644
--- a/source/blender/nodes/geometry/node_geometry_tree.cc
+++ b/source/blender/nodes/geometry/node_geometry_tree.cc
@@ -48,7 +48,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;
diff --git a/source/blender/nodes/geometry/node_geometry_util.cc b/source/blender/nodes/geometry/node_geometry_util.cc
index 8f673d2264e..3192459b8b5 100644
--- a/source/blender/nodes/geometry/node_geometry_util.cc
+++ b/source/blender/nodes/geometry/node_geometry_util.cc
@@ -36,7 +36,7 @@ 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
diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh
index 4db4d8bb097..5aeb68b3fdc 100644
--- a/source/blender/nodes/geometry/node_geometry_util.hh
+++ b/source/blender/nodes/geometry/node_geometry_util.hh
@@ -24,6 +24,8 @@
#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,
@@ -78,6 +80,13 @@ 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);
+
std::optional<eCustomDataType> node_data_type_to_custom_data_type(eNodeSocketDatatype type);
std::optional<eCustomDataType> node_socket_to_custom_data_type(const bNodeSocket &socket);
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 13a9cdc8600..4ad6efebfa8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc
@@ -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;
@@ -373,8 +373,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 8c11288efdd..c9df66f1eea 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
@@ -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;
@@ -165,8 +165,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);
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..a59236235a5 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
@@ -42,7 +42,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
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 af0007c2fa4..0ab0081b9cf 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
@@ -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");
diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
index c8c58945bce..341f58f176b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
@@ -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) {
@@ -148,7 +148,8 @@ 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);
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..f4e8788cb8d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
@@ -57,8 +57,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();
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 10859c4c4af..9f07c33785a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
@@ -55,7 +55,7 @@ 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
}
@@ -78,7 +78,7 @@ static Mesh *hull_from_bullet(const Mesh *mesh, Span<float3> coords)
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 = edges[edge_index];
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 8640215153b..811f6981635 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
@@ -85,7 +85,7 @@ static Mesh *cdt_to_mesh(const meshintersect::CDT_result<double> &result)
MutableSpan<MLoop> loops = mesh->loops_for_write();
for (const int i : IndexRange(result.vert.size())) {
- positions[i] = float3((float)result.vert[i].x, (float)result.vert[i].y, 0.0f);
+ positions[i] = 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 4586bb24464..50863b2031a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
@@ -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);
}
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 b34b22e995d..b1c3bbfb81e 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
@@ -97,7 +97,7 @@ class HandleTypeFieldInput final : public bke::CurvesFieldInput {
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
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..85a8ccc3192 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
@@ -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_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
index c33ba3e2a4c..12df6f76a28 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
@@ -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..9f098674fe5 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
@@ -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..9536917077e 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
@@ -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 41eafe2a741..db71371d464 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
@@ -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);
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..186c00ddda0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
@@ -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);
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 919d0056bca..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,6 +29,8 @@ 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;
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 799a65ec3d1..e05d80bd722 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
@@ -58,7 +58,7 @@ 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);
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 1576b573058..a5a82557a4f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
@@ -64,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;
@@ -95,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});
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 380f884e992..7cdb7cc55f4 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
@@ -312,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};
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 6fe65f38172..3ed7bd9edb4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
@@ -1145,7 +1145,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
const bNode *node = static_cast<bNode *>(ptr->data);
const NodeGeometryDeleteGeometry &storage = node_storage(*node);
- const 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. */
@@ -1174,7 +1174,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
index a0bd28218cc..9910ccb84fa 100644
--- 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
@@ -65,10 +65,10 @@ static void node_distribute_points_in_volume_init(bNodeTree *UNUSED(ntree), bNod
static void node_distribute_points_in_volume_update(bNodeTree *ntree, bNode *node)
{
const NodeGeometryDistributePointsInVolume &storage = node_storage(*node);
- GeometryNodeDistributePointsInVolumeMode mode =
- static_cast<GeometryNodeDistributePointsInVolumeMode>(storage.mode);
+ GeometryNodeDistributePointsInVolumeMode mode = GeometryNodeDistributePointsInVolumeMode(
+ storage.mode);
- bNodeSocket *sock_density = ((bNodeSocket *)(node->inputs.first))->next;
+ 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;
@@ -99,7 +99,7 @@ class PositionsVDBWrapper {
void add(const openvdb::Vec3R &pos)
{
- vector_.append((float3((float)pos[0], (float)pos[1], (float)pos[2]) + offset_fix_));
+ vector_.append(float3(float(pos[0]), float(pos[1]), float(pos[2])) + offset_fix_);
}
};
@@ -117,9 +117,9 @@ static void point_scatter_density_random(const openvdb::FloatGrid &grid,
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()};
+ 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);
@@ -133,9 +133,9 @@ static void point_scatter_density_grid(const openvdb::FloatGrid &grid,
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());
+ 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(),
@@ -170,7 +170,7 @@ static void point_scatter_density_grid(const openvdb::FloatGrid &grid,
/* 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()});
+ r_positions.append({float(local_pos.x()), float(local_pos.y()), float(local_pos.z())});
}
}
}
@@ -185,8 +185,8 @@ static void geo_node_distribute_points_in_volume_exec(GeoNodeExecParams params)
GeometrySet geometry_set = params.extract_input<GeometrySet>("Volume");
const NodeGeometryDistributePointsInVolume &storage = node_storage(params.node());
- const GeometryNodeDistributePointsInVolumeMode mode =
- static_cast<GeometryNodeDistributePointsInVolumeMode>(storage.mode);
+ const GeometryNodeDistributePointsInVolumeMode mode = GeometryNodeDistributePointsInVolumeMode(
+ storage.mode);
float density;
int seed;
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 11c55b262c1..e49311d07d7 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
@@ -69,8 +69,8 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
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,
@@ -107,8 +107,7 @@ static void sample_mesh_surface(const Mesh &mesh,
{
const Span<float3> positions = mesh.positions();
const Span<MLoop> loops = mesh.loops();
- 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 looptri_index : looptris.index_range()) {
const MLoopTri &looptri = looptris[looptri_index];
@@ -204,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;
@@ -352,8 +350,7 @@ BLI_NOINLINE static void compute_attribute_outputs(const Mesh &mesh,
const Span<float3> positions = mesh.positions();
const Span<MLoop> loops = mesh.loops();
- 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()) {
const int looptri_index = looptri_indices[i];
@@ -514,8 +511,8 @@ 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");
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 bd50da06f91..50e86b2df8d 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");
@@ -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);
}
@@ -1320,7 +1323,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. */
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 c8df5785fed..4d7e4b00c5a 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
@@ -44,7 +44,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;
@@ -128,7 +128,7 @@ class FieldAtIndex final : public bke::GeometryFieldInput {
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()) {
+ if (src_values.index_range().contains(index)) {
dst_array[i] = src_values[index];
}
else {
@@ -165,8 +165,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);
Field<int> index_field = params.extract_input<Field<int>>("Index");
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
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..1dd48f437bd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc
@@ -24,8 +24,8 @@ 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();
@@ -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) {
@@ -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: {
@@ -292,7 +292,7 @@ class ImageFieldsFunction : public fn::MultiFunction {
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_control_point_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_control_point_neighbors.cc
new file mode 100644
index 00000000000..b5d0c8cdd74
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_control_point_neighbors.cc
@@ -0,0 +1,177 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BLI_task.hh"
+
+#include "BKE_curves.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_control_point_neighbors_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Int>(N_("Point Index"))
+ .implicit_field(implicit_field_inputs::index)
+ .hide_value()
+ .description(
+ N_("The index of the control point to evaluate. Defaults to the current index"));
+ b.add_input<decl::Int>(N_("Offset"))
+ .dependent_field()
+ .description(N_("The number of control points along the curve to traverse"));
+ b.add_output<decl::Bool>(N_("Is Valid Offset"))
+ .field_source()
+ .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"))
+ .field_source()
+ .description(N_("The index of the control point plus the offset within the entire "
+ "curves data-block"));
+}
+
+static 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));
+}
+
+static Array<int> build_parent_curves(const bke::CurvesGeometry &curves)
+{
+ Array<int> parent_curves(curves.points_num());
+ for (const int i : curves.curves_range()) {
+ parent_curves.as_mutable_span().slice(curves.points_for_curve(i)).fill(i);
+ }
+ return parent_curves;
+}
+
+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>(), "Control Point Neighbors"),
+ 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 = build_parent_curves(curves);
+
+ 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 = build_parent_curves(curves);
+
+ 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_input_control_point_neighbors_cc
+
+void register_node_type_geo_input_control_point_neighbors()
+{
+ namespace file_ns = blender::nodes::node_geo_input_control_point_neighbors_cc;
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_INPUT_CONTROL_POINT_NEIGHBORS, "Control Point Neighbors", 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_input_material.cc b/source/blender/nodes/geometry/nodes/node_geo_input_material.cc
index 19882c4966d..6f3c6d23bd2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_material.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_material.cc
@@ -19,7 +19,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
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_face_is_planar.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc
index 1686701bc3f..cac7dade79d 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
@@ -40,7 +40,8 @@ class PlanarFieldInput final : public bke::MeshFieldInput {
const Span<float3> positions = mesh.positions();
const Span<MPoly> polys = mesh.polys();
const Span<MLoop> loops = mesh.loops();
- const Span<float3> poly_normals{(float3 *)BKE_mesh_poly_normals_ensure(&mesh), mesh.totpoly};
+ 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()};
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 da09d3650e3..8973c1db319 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
@@ -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");
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_instance_on_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
index d54d082311f..c6f214e72ac 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
@@ -25,7 +25,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"));
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 ec2f1b00e6c..d4072a05e5f 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
@@ -13,7 +13,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)
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 8e38ef14aba..df1427ac5b9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_interpolate_domain.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_interpolate_domain.cc
@@ -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;
@@ -135,8 +135,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_mesh_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
index a636c559157..400bc30d7a7 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
@@ -115,7 +115,7 @@ static Mesh *create_circle_mesh(const float radius,
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;
positions[i] = 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 e2f8f18501a..ea579396164 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
@@ -258,7 +258,7 @@ int ConeConfig::calculate_total_corners()
static void calculate_cone_verts(const MutableSpan<float3> positions, 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_verts(const MutableSpan<float3> positions, const Cone
/* 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_verts(const MutableSpan<float3> positions, const Cone
/* 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_verts(const MutableSpan<float3> positions, const Cone
/* 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)) {
@@ -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;
@@ -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);
@@ -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;
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..587999f3d00 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
@@ -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_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 b2b82c5dc16..4045b6223dc 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
@@ -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);
}
}
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 e493e4556a4..6db4c82d5cf 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
@@ -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);
@@ -309,7 +309,8 @@ static Mesh *create_uv_sphere_mesh(const float radius, const int segments, const
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(positions, vert_normals, radius, segments, rings);
BKE_mesh_vertex_normals_clear_dirty(mesh);
},
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 ce06ccbda75..ceb87c59b8e 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
@@ -24,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)
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 f6fa5c99013..de04f0561e5 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
@@ -59,24 +59,22 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(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. */
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 0990eebb903..ec9a40f8cf8 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
@@ -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
@@ -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");
diff --git a/source/blender/nodes/geometry/nodes/node_geo_proximity.cc b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc
index d5233ee35a4..f453c7cb47a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_proximity.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc
@@ -22,7 +22,7 @@ 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();
}
@@ -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 f657b128c51..118d6c2f6c7 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();
@@ -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;
@@ -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_sample_index.cc b/source/blender/nodes/geometry/nodes/node_geo_sample_index.cc
new file mode 100644
index 00000000000..bfaf9b70f13
--- /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 *UNUSED(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 *UNUSED(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 UNUSED(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..95f7c7add3a
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_sample_nearest.cc
@@ -0,0 +1,344 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BLI_task.hh"
+
+#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 *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(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 UNUSED(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..f3c182cd97a
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc
@@ -0,0 +1,280 @@
+/* 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.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_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 *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(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 UNUSED(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->totpoly == 0 && mesh->totvert != 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_scale_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc
index 20a951e65f3..3416e63f682 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"))
@@ -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);
@@ -399,9 +398,8 @@ static void scale_edges_on_axis(Mesh &mesh, const AxisScaleFields &fields)
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");
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..f40ad62a5e4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
@@ -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 e529ddddabe..5610edf7e4c 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,7 +17,11 @@ 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"));
}
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 5864401223b..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"));
}
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 61bf48449d8..50739b83a61 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
@@ -18,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"));
}
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 37e55602fb0..d0b770aadad 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
@@ -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;
@@ -75,7 +75,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
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) {
@@ -155,8 +155,8 @@ static void node_geo_exec(GeoNodeExecParams params)
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) {
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..e8913f80916 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
@@ -85,7 +85,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 +93,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 +203,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 +213,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 +226,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};
@@ -272,7 +272,7 @@ static Map<int, int> create_curve_instances(GeoNodeExecParams &params,
TextLayout &layout,
InstancesComponent &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");
diff --git a/source/blender/nodes/geometry/nodes/node_geo_switch.cc b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
index ddc87e3dac4..6dc30af4fb6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_switch.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
@@ -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 81f1155a96c..00000000000
--- a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
+++ /dev/null
@@ -1,829 +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.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_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{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)
-{
- const Span<float3> mesh_positions = mesh.positions();
- 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;
- int closest_vert;
- 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 float distance_sq = math::distance_squared(position, mesh_positions[vertex_index]);
- if (distance_sq < min_distance_sq) {
- min_distance_sq = distance_sq;
- closest_loop_index = loop_index;
- closest_vert = vertex_index;
- }
- }
- if (!r_corner_indices.is_empty()) {
- r_corner_indices[i] = closest_loop_index;
- }
- if (!r_positions.is_empty()) {
- r_positions[i] = mesh_positions[closest_vert];
- }
- 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<bke::MeshFieldContext> 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 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);
- }
-};
-
-/**
- * \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<bke::MeshFieldContext> mesh_context_;
- std::unique_ptr<FieldEvaluator> mesh_evaluator_;
- const GVArray *mesh_data_;
-
- std::optional<bke::PointCloudFieldContext> 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_polys(*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 Mesh &mesh = *source_.get_mesh_for_read();
- const int domain_size = mesh.attributes().domain_size(domain_);
- mesh_context_.emplace(bke::MeshFieldContext(mesh, domain_));
- mesh_evaluator_ = std::make_unique<FieldEvaluator>(*mesh_context_, domain_size);
- mesh_evaluator_->add(src_field_);
- mesh_evaluator_->evaluate();
- mesh_data_ = &mesh_evaluator_->get_evaluated(0);
- }
-
- if (use_points_) {
- const PointCloud &points = *source_.get_pointcloud_for_read();
- point_context_.emplace(bke::PointCloudFieldContext(points));
- point_evaluator_ = std::make_unique<FieldEvaluator>(*point_context_, points.totpoint);
- 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<bke::GeometryFieldContext> 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(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 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_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
index 57487059437..04fe7641899 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
@@ -68,10 +68,8 @@ 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()) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
index 6979693e215..2c8a70901f8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
@@ -61,7 +61,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) {
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 c102b91acb1..4018f85fc94 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc
@@ -75,8 +75,7 @@ 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,
@@ -169,7 +168,7 @@ static void node_geo_exec(GeoNodeExecParams params)
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));
diff --git a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc
index cb296cdd93f..7a78547b10b 100644
--- a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc
+++ b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc
@@ -535,6 +535,12 @@ class LazyFunctionForViewerNode : public LazyFunction {
{
GeoNodesLFUserData *user_data = dynamic_cast<GeoNodesLFUserData *>(context.user_data);
BLI_assert(user_data != nullptr);
+ if (user_data->modifier_data == nullptr) {
+ return;
+ }
+ if (user_data->modifier_data->eval_log == nullptr) {
+ return;
+ }
GeometrySet geometry = params.extract_input<GeometrySet>(0);
@@ -1188,70 +1194,27 @@ struct GeometryNodesLazyFunctionGraphBuilder {
bool try_add_implicit_input(const bNodeSocket &input_bsocket, lf::InputSocket &input_lf_socket)
{
const bNode &bnode = input_bsocket.owner_node();
- const NodeDeclaration *node_declaration = bnode.declaration();
- if (node_declaration == nullptr) {
+ const SocketDeclaration *socket_decl = input_bsocket.runtime->declaration;
+ if (socket_decl == nullptr) {
return false;
}
- const SocketDeclaration &socket_declaration =
- *node_declaration->inputs()[input_bsocket.index()];
- if (socket_declaration.input_field_type() != InputSocketFieldType::Implicit) {
+ if (socket_decl->input_field_type() != InputSocketFieldType::Implicit) {
return false;
}
- const CPPType &type = input_lf_socket.type();
- std::function<void(void *)> init_fn = this->get_implicit_input_init_function(bnode,
- input_bsocket);
- if (!init_fn) {
+ const ImplicitInputValueFn *implicit_input_fn = socket_decl->implicit_input_fn();
+ if (implicit_input_fn == nullptr) {
return false;
}
-
+ std::function<void(void *)> init_fn = [&bnode, implicit_input_fn](void *r_value) {
+ (*implicit_input_fn)(bnode, r_value);
+ };
+ const CPPType &type = input_lf_socket.type();
auto lazy_function = std::make_unique<LazyFunctionForImplicitInput>(type, std::move(init_fn));
lf::Node &lf_node = lf_graph_->add_function(*lazy_function);
lf_graph_info_->functions.append(std::move(lazy_function));
lf_graph_->add_link(lf_node.output(0), input_lf_socket);
return true;
}
-
- std::function<void(void *)> get_implicit_input_init_function(const bNode &bnode,
- const bNodeSocket &bsocket)
- {
- const bNodeSocketType &socket_type = *bsocket.typeinfo;
- if (socket_type.type == SOCK_VECTOR) {
- if (bnode.type == GEO_NODE_SET_CURVE_HANDLES) {
- StringRef side = ((NodeGeometrySetCurveHandlePositions *)bnode.storage)->mode ==
- GEO_NODE_CURVE_HANDLE_LEFT ?
- "handle_left" :
- "handle_right";
- return [side](void *r_value) {
- new (r_value) ValueOrField<float3>(bke::AttributeFieldInput::Create<float3>(side));
- };
- }
- else if (bnode.type == GEO_NODE_EXTRUDE_MESH) {
- return [](void *r_value) {
- new (r_value)
- ValueOrField<float3>(Field<float3>(std::make_shared<bke::NormalFieldInput>()));
- };
- }
- else {
- return [](void *r_value) {
- new (r_value) ValueOrField<float3>(bke::AttributeFieldInput::Create<float3>("position"));
- };
- }
- }
- else if (socket_type.type == SOCK_INT) {
- if (ELEM(bnode.type, FN_NODE_RANDOM_VALUE, GEO_NODE_INSTANCE_ON_POINTS)) {
- return [](void *r_value) {
- new (r_value)
- ValueOrField<int>(Field<int>(std::make_shared<bke::IDAttributeFieldInput>()));
- };
- }
- else {
- return [](void *r_value) {
- new (r_value) ValueOrField<int>(Field<int>(std::make_shared<fn::IndexFieldInput>()));
- };
- }
- }
- return {};
- }
};
const GeometryNodesLazyFunctionGraphInfo *ensure_geometry_nodes_lazy_function_graph(
diff --git a/source/blender/nodes/intern/geometry_nodes_log.cc b/source/blender/nodes/intern/geometry_nodes_log.cc
index 110573c9119..aadf69f10c5 100644
--- a/source/blender/nodes/intern/geometry_nodes_log.cc
+++ b/source/blender/nodes/intern/geometry_nodes_log.cc
@@ -35,8 +35,8 @@ FieldInfoLog::FieldInfoLog(const GField &field) : type(field.cpp_type())
std::sort(
field_inputs.begin(), field_inputs.end(), [](const FieldInput &a, const FieldInput &b) {
- const int index_a = (int)a.category();
- const int index_b = (int)b.category();
+ const int index_a = int(a.category());
+ const int index_b = int(b.category());
if (index_a == index_b) {
return a.socket_inspection_name().size() < b.socket_inspection_name().size();
}
diff --git a/source/blender/nodes/intern/node_common.cc b/source/blender/nodes/intern/node_common.cc
index 1f085375329..022ea3313e2 100644
--- a/source/blender/nodes/intern/node_common.cc
+++ b/source/blender/nodes/intern/node_common.cc
@@ -221,7 +221,7 @@ void node_group_update(struct bNodeTree *ntree, struct bNode *node)
if (node->id == nullptr) {
nodeRemoveAllSockets(ntree, node);
}
- else if ((ID_IS_LINKED(node->id) && (node->id->tag & LIB_TAG_MISSING))) {
+ else if (ID_IS_LINKED(node->id) && (node->id->tag & LIB_TAG_MISSING)) {
/* Missing data-block, leave sockets unchanged so that when it comes back
* the links remain valid. */
}
diff --git a/source/blender/nodes/intern/node_declaration.cc b/source/blender/nodes/intern/node_declaration.cc
index 2cd9c6000c0..f323d035668 100644
--- a/source/blender/nodes/intern/node_declaration.cc
+++ b/source/blender/nodes/intern/node_declaration.cc
@@ -2,6 +2,7 @@
#include "NOD_node_declaration.hh"
+#include "BKE_geometry_fields.hh"
#include "BKE_node.h"
namespace blender::nodes {
@@ -81,4 +82,30 @@ bool SocketDeclaration::matches_common_data(const bNodeSocket &socket) const
return true;
}
+namespace implicit_field_inputs {
+
+void position(const bNode & /*node*/, void *r_value)
+{
+ new (r_value) fn::ValueOrField<float3>(bke::AttributeFieldInput::Create<float3>("position"));
+}
+
+void normal(const bNode & /*node*/, void *r_value)
+{
+ new (r_value)
+ fn::ValueOrField<float3>(fn::Field<float3>(std::make_shared<bke::NormalFieldInput>()));
+}
+
+void index(const bNode & /*node*/, void *r_value)
+{
+ new (r_value) fn::ValueOrField<int>(fn::Field<int>(std::make_shared<fn::IndexFieldInput>()));
+}
+
+void id_or_index(const bNode & /*node*/, void *r_value)
+{
+ new (r_value)
+ fn::ValueOrField<int>(fn::Field<int>(std::make_shared<bke::IDAttributeFieldInput>()));
+}
+
+} // namespace implicit_field_inputs
+
} // namespace blender::nodes
diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc
index 098f766589d..79ce9b76e82 100644
--- a/source/blender/nodes/intern/node_socket.cc
+++ b/source/blender/nodes/intern/node_socket.cc
@@ -59,14 +59,14 @@ struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree,
}
case SOCK_INT: {
bNodeSocketValueInt *dval = (bNodeSocketValueInt *)sock->default_value;
- dval->value = (int)stemp->val1;
- dval->min = (int)stemp->min;
- dval->max = (int)stemp->max;
+ dval->value = int(stemp->val1);
+ dval->min = int(stemp->min);
+ dval->max = int(stemp->max);
break;
}
case SOCK_BOOLEAN: {
bNodeSocketValueBoolean *dval = (bNodeSocketValueBoolean *)sock->default_value;
- dval->value = (int)stemp->val1;
+ dval->value = int(stemp->val1);
break;
}
case SOCK_VECTOR: {
diff --git a/source/blender/nodes/shader/node_shader_tree.cc b/source/blender/nodes/shader/node_shader_tree.cc
index a6d2e954a0c..2edcd160345 100644
--- a/source/blender/nodes/shader/node_shader_tree.cc
+++ b/source/blender/nodes/shader/node_shader_tree.cc
@@ -300,7 +300,7 @@ static bool ntree_shader_expand_socket_default(bNodeTree *localtree,
BLI_assert(value_socket != nullptr);
src_int = static_cast<bNodeSocketValueInt *>(socket->default_value);
dst_float = static_cast<bNodeSocketValueFloat *>(value_socket->default_value);
- dst_float->value = (float)(src_int->value);
+ dst_float->value = float(src_int->value);
break;
case SOCK_FLOAT:
value_node = nodeAddStaticNode(nullptr, localtree, SH_NODE_VALUE);
@@ -563,7 +563,7 @@ static bNode *ntree_shader_copy_branch(bNodeTree *ntree,
void (*callback)(bNode *node, int user_data),
int user_data)
{
- /* Init tmp flag. */
+ /* Initialize `tmp_flag`. */
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
node->tmp_flag = -1;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc
index a0579372a15..766c926916a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc
@@ -44,7 +44,7 @@ static void node_declare(NodeDeclarationBuilder &b)
.subtype(PROP_FACTOR);
b.add_input<decl::Float>(N_("IOR")).default_value(1.55f).min(0.0f).max(1000.0f);
b.add_input<decl::Float>(N_("Offset"))
- .default_value(2.0f * ((float)M_PI) / 180.0f)
+ .default_value(2.0f * float(M_PI) / 180.0f)
.min(-M_PI_2)
.max(M_PI_2)
.subtype(PROP_ANGLE);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc b/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc
index a1c51a440d0..5a7ec408433 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc
@@ -13,7 +13,10 @@ namespace blender::nodes::node_shader_tex_brick_cc {
static void sh_node_tex_brick_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>(N_("Vector")).min(-10000.0f).max(10000.0f).implicit_field();
+ b.add_input<decl::Vector>(N_("Vector"))
+ .min(-10000.0f)
+ .max(10000.0f)
+ .implicit_field(implicit_field_inputs::position);
b.add_input<decl::Color>(N_("Color1")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
b.add_input<decl::Color>(N_("Color2")).default_value({0.2f, 0.2f, 0.2f, 1.0f});
b.add_input<decl::Color>(N_("Mortar")).default_value({0.0f, 0.0f, 0.0f, 1.0f}).no_muted_links();
@@ -147,7 +150,7 @@ class BrickFunction : public fn::MultiFunction {
n = (n + 1013) & 0x7fffffff;
n = (n >> 13) ^ n;
const uint nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
- return 0.5f * ((float)nn / 1073741824.0f);
+ return 0.5f * (float(nn) / 1073741824.0f);
}
static float smoothstepf(const float f)
@@ -169,14 +172,14 @@ class BrickFunction : public fn::MultiFunction {
{
float offset = 0.0f;
- const int rownum = (int)floorf(p.y / row_height);
+ const int rownum = int(floorf(p.y / row_height));
if (offset_frequency && squash_frequency) {
brick_width *= (rownum % squash_frequency) ? 1.0f : squash_amount;
offset = (rownum % offset_frequency) ? 0.0f : (brick_width * offset_amount);
}
- const int bricknum = (int)floorf((p.x + offset) / brick_width);
+ const int bricknum = int(floorf((p.x + offset) / brick_width));
const float x = (p.x + offset) - brick_width * bricknum;
const float y = p.y - row_height * rownum;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc b/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc
index b0e5639c893..fc231d79417 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc
@@ -8,7 +8,10 @@ namespace blender::nodes::node_shader_tex_checker_cc {
static void sh_node_tex_checker_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>(N_("Vector")).min(-10000.0f).max(10000.0f).implicit_field();
+ b.add_input<decl::Vector>(N_("Vector"))
+ .min(-10000.0f)
+ .max(10000.0f)
+ .implicit_field(implicit_field_inputs::position);
b.add_input<decl::Color>(N_("Color1")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
b.add_input<decl::Color>(N_("Color2")).default_value({0.2f, 0.2f, 0.2f, 1.0f});
b.add_input<decl::Float>(N_("Scale"))
@@ -77,9 +80,9 @@ class NodeTexChecker : public fn::MultiFunction {
/* Avoid precision issues on unit coordinates. */
const float3 p = (vector[i] * scale[i] + 0.000001f) * 0.999999f;
- const int xi = abs((int)(floorf(p.x)));
- const int yi = abs((int)(floorf(p.y)));
- const int zi = abs((int)(floorf(p.z)));
+ const int xi = abs(int(floorf(p.x)));
+ const int yi = abs(int(floorf(p.y)));
+ const int zi = abs(int(floorf(p.z)));
r_fac[i] = ((xi % 2 == yi % 2) == (zi % 2)) ? 1.0f : 0.0f;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc
index 37c72ec1f17..bc7837040b7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc
@@ -11,7 +11,9 @@ namespace blender::nodes::node_shader_tex_gradient_cc {
static void sh_node_tex_gradient_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>(N_("Vector")).hide_value().implicit_field();
+ b.add_input<decl::Vector>(N_("Vector"))
+ .hide_value()
+ .implicit_field(implicit_field_inputs::position);
b.add_output<decl::Color>(N_("Color")).no_muted_links();
b.add_output<decl::Float>(N_("Fac")).no_muted_links();
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc
index c9588949761..e70539fcf25 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc
@@ -8,7 +8,7 @@ namespace blender::nodes::node_shader_tex_image_cc {
static void sh_node_tex_image_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>(N_("Vector")).implicit_field();
+ b.add_input<decl::Vector>(N_("Vector")).implicit_field(implicit_field_inputs::position);
b.add_output<decl::Color>(N_("Color")).no_muted_links();
b.add_output<decl::Float>(N_("Alpha")).no_muted_links();
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc b/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc
index 205d3b89016..86c96cfe70b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc
@@ -11,7 +11,7 @@ namespace blender::nodes::node_shader_tex_magic_cc {
static void sh_node_tex_magic_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>(N_("Vector")).implicit_field();
+ b.add_input<decl::Vector>(N_("Vector")).implicit_field(implicit_field_inputs::position);
b.add_input<decl::Float>(N_("Scale")).min(-1000.0f).max(1000.0f).default_value(5.0f);
b.add_input<decl::Float>(N_("Distortion")).min(-1000.0f).max(1000.0f).default_value(1.0f);
b.add_output<decl::Color>(N_("Color")).no_muted_links();
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc
index a2241c2327f..86a79a3f213 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc
@@ -15,7 +15,9 @@ NODE_STORAGE_FUNCS(NodeTexMusgrave)
static void sh_node_tex_musgrave_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>(N_("Vector")).hide_value().implicit_field();
+ b.add_input<decl::Vector>(N_("Vector"))
+ .hide_value()
+ .implicit_field(implicit_field_inputs::position);
b.add_input<decl::Float>(N_("W")).min(-1000.0f).max(1000.0f).make_available([](bNode &node) {
/* Default to 1 instead of 4, because it is much faster. */
node_storage(node).dimensions = 1;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc
index 87fb1aeac29..eabe1fa774f 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc
@@ -15,7 +15,7 @@ NODE_STORAGE_FUNCS(NodeTexNoise)
static void sh_node_tex_noise_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>(N_("Vector")).implicit_field();
+ b.add_input<decl::Vector>(N_("Vector")).implicit_field(implicit_field_inputs::position);
b.add_input<decl::Float>(N_("W")).min(-1000.0f).max(1000.0f).make_available([](bNode &node) {
/* Default to 1 instead of 4, because it is much faster. */
node_storage(node).dimensions = 1;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc b/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc
index 97b7f2616ae..23fb4052c7e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc
@@ -189,12 +189,12 @@ static int node_shader_gpu_tex_sky(GPUMaterial *mat,
/* Pass sky_state->configs[3][9] as 3*(vec4+vec4)+vec3 */
float config_x07[8], config_y07[8], config_z07[8], config_xyz8[3];
for (int i = 0; i < 8; ++i) {
- config_x07[i] = (float)sky_state->configs[0][i];
- config_y07[i] = (float)sky_state->configs[1][i];
- config_z07[i] = (float)sky_state->configs[2][i];
+ config_x07[i] = float(sky_state->configs[0][i]);
+ config_y07[i] = float(sky_state->configs[1][i]);
+ config_z07[i] = float(sky_state->configs[2][i]);
}
for (int i = 0; i < 3; ++i) {
- config_xyz8[i] = (float)sky_state->configs[i][8];
+ config_xyz8[i] = float(sky_state->configs[i][8]);
}
float radiance[3];
for (int i = 0; i < 3; i++) {
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc
index fc6a5ef72b6..723cf9322f8 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc
@@ -15,7 +15,9 @@ NODE_STORAGE_FUNCS(NodeTexVoronoi)
static void sh_node_tex_voronoi_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>(N_("Vector")).hide_value().implicit_field();
+ b.add_input<decl::Vector>(N_("Vector"))
+ .hide_value()
+ .implicit_field(implicit_field_inputs::position);
b.add_input<decl::Float>(N_("W")).min(-1000.0f).max(1000.0f).make_available([](bNode &node) {
/* Default to 1 instead of 4, because it is much faster. */
node_storage(node).dimensions = 1;
@@ -173,7 +175,7 @@ static void node_shader_update_tex_voronoi(bNodeTree *ntree, bNode *node)
outWSock,
storage.feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
storage.feature != SHD_VORONOI_N_SPHERE_RADIUS &&
- (ELEM(storage.dimensions, 1, 4)));
+ ELEM(storage.dimensions, 1, 4));
nodeSetSocketAvailability(ntree, outRadiusSock, storage.feature == SHD_VORONOI_N_SPHERE_RADIUS);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc
index 8475101dbaf..d86b2d820ab 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc
@@ -13,7 +13,7 @@ namespace blender::nodes::node_shader_tex_wave_cc {
static void sh_node_tex_wave_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>(N_("Vector")).implicit_field();
+ b.add_input<decl::Vector>(N_("Vector")).implicit_field(implicit_field_inputs::position);
b.add_input<decl::Float>(N_("Scale")).min(-1000.0f).max(1000.0f).default_value(5.0f);
b.add_input<decl::Float>(N_("Distortion")).min(-1000.0f).max(1000.0f).default_value(0.0f);
b.add_input<decl::Float>(N_("Detail")).min(0.0f).max(15.0f).default_value(2.0f);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc
index 64075a903ab..d7f985d73fa 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc
@@ -13,7 +13,10 @@ namespace blender::nodes::node_shader_tex_white_noise_cc {
static void sh_node_tex_white_noise_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Vector>(N_("Vector")).min(-10000.0f).max(10000.0f).implicit_field();
+ b.add_input<decl::Vector>(N_("Vector"))
+ .min(-10000.0f)
+ .max(10000.0f)
+ .implicit_field(implicit_field_inputs::position);
b.add_input<decl::Float>(N_("W")).min(-10000.0f).max(10000.0f).make_available([](bNode &node) {
/* Default to 1 instead of 4, because it is faster. */
node.custom1 = 1;
@@ -177,7 +180,7 @@ class WhiteNoiseFunction : public fn::MultiFunction {
static void sh_node_noise_build_multi_function(NodeMultiFunctionBuilder &builder)
{
const bNode &node = builder.node();
- builder.construct_and_set_matching_fn<WhiteNoiseFunction>((int)node.custom1);
+ builder.construct_and_set_matching_fn<WhiteNoiseFunction>(int(node.custom1));
}
} // namespace blender::nodes::node_shader_tex_white_noise_cc