diff options
Diffstat (limited to 'source/blender/nodes')
315 files changed, 10426 insertions, 4839 deletions
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index e256ebcff56..5f61d13a3af 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -19,6 +19,7 @@ # ***** END GPL LICENSE BLOCK ***** add_subdirectory(geometry) +add_subdirectory(shader) set(INC . @@ -44,7 +45,6 @@ set(INC ../windowmanager ../../../intern/glew-mx ../../../intern/guardedalloc - ../../../intern/sky/include ) @@ -141,7 +141,7 @@ set(SRC function/nodes/node_fn_align_euler_to_vector.cc function/nodes/node_fn_boolean_math.cc - function/nodes/node_fn_float_compare.cc + function/nodes/node_fn_compare.cc function/nodes/node_fn_float_to_int.cc function/nodes/node_fn_input_bool.cc function/nodes/node_fn_input_color.cc @@ -157,99 +157,6 @@ set(SRC function/nodes/node_fn_value_to_string.cc function/node_function_util.cc - shader/nodes/node_shader_add_shader.c - shader/nodes/node_shader_ambient_occlusion.c - shader/nodes/node_shader_attribute.c - shader/nodes/node_shader_background.c - shader/nodes/node_shader_bevel.c - shader/nodes/node_shader_blackbody.c - shader/nodes/node_shader_brightness.c - shader/nodes/node_shader_bsdf_anisotropic.c - shader/nodes/node_shader_bsdf_diffuse.c - shader/nodes/node_shader_bsdf_glass.c - shader/nodes/node_shader_bsdf_glossy.c - shader/nodes/node_shader_bsdf_hair.c - shader/nodes/node_shader_bsdf_hair_principled.c - shader/nodes/node_shader_bsdf_principled.c - shader/nodes/node_shader_bsdf_refraction.c - shader/nodes/node_shader_bsdf_toon.c - shader/nodes/node_shader_bsdf_translucent.c - shader/nodes/node_shader_bsdf_transparent.c - shader/nodes/node_shader_bsdf_velvet.c - shader/nodes/node_shader_bump.c - shader/nodes/node_shader_camera.c - shader/nodes/node_shader_clamp.cc - shader/nodes/node_shader_common.c - shader/nodes/node_shader_curves.cc - shader/nodes/node_shader_displacement.c - shader/nodes/node_shader_eevee_specular.c - shader/nodes/node_shader_emission.c - shader/nodes/node_shader_fresnel.c - shader/nodes/node_shader_gamma.c - shader/nodes/node_shader_geometry.c - shader/nodes/node_shader_hair_info.c - shader/nodes/node_shader_holdout.c - shader/nodes/node_shader_hueSatVal.c - shader/nodes/node_shader_ies_light.c - shader/nodes/node_shader_invert.c - shader/nodes/node_shader_layer_weight.c - shader/nodes/node_shader_light_falloff.c - shader/nodes/node_shader_light_path.c - shader/nodes/node_shader_map_range.cc - shader/nodes/node_shader_mapping.c - shader/nodes/node_shader_math.cc - shader/nodes/node_shader_mixRgb.cc - shader/nodes/node_shader_mix_shader.c - shader/nodes/node_shader_normal.c - shader/nodes/node_shader_normal_map.c - shader/nodes/node_shader_object_info.c - shader/nodes/node_shader_output_aov.c - shader/nodes/node_shader_output_light.c - shader/nodes/node_shader_output_linestyle.c - shader/nodes/node_shader_output_material.c - shader/nodes/node_shader_output_world.c - shader/nodes/node_shader_particle_info.c - shader/nodes/node_shader_rgb.c - shader/nodes/node_shader_script.c - shader/nodes/node_shader_sepcombHSV.c - shader/nodes/node_shader_sepcombRGB.cc - shader/nodes/node_shader_sepcombXYZ.cc - shader/nodes/node_shader_shaderToRgb.c - shader/nodes/node_shader_squeeze.c - shader/nodes/node_shader_subsurface_scattering.c - shader/nodes/node_shader_tangent.c - shader/nodes/node_shader_tex_brick.cc - shader/nodes/node_shader_tex_checker.cc - shader/nodes/node_shader_tex_coord.c - shader/nodes/node_shader_tex_environment.c - shader/nodes/node_shader_tex_gradient.cc - shader/nodes/node_shader_tex_image.cc - shader/nodes/node_shader_tex_magic.cc - shader/nodes/node_shader_tex_musgrave.cc - shader/nodes/node_shader_tex_noise.cc - shader/nodes/node_shader_tex_pointdensity.c - shader/nodes/node_shader_tex_sky.c - shader/nodes/node_shader_tex_voronoi.cc - shader/nodes/node_shader_tex_wave.cc - shader/nodes/node_shader_tex_white_noise.cc - shader/nodes/node_shader_uvAlongStroke.c - shader/nodes/node_shader_uvmap.c - shader/nodes/node_shader_valToRgb.cc - shader/nodes/node_shader_value.cc - shader/nodes/node_shader_vectTransform.c - shader/nodes/node_shader_vector_displacement.c - shader/nodes/node_shader_vector_math.cc - shader/nodes/node_shader_vector_rotate.cc - shader/nodes/node_shader_vertex_color.c - shader/nodes/node_shader_volume_absorption.c - shader/nodes/node_shader_volume_info.c - shader/nodes/node_shader_volume_principled.c - shader/nodes/node_shader_volume_scatter.c - shader/nodes/node_shader_wavelength.c - shader/nodes/node_shader_wireframe.c - shader/node_shader_tree.c - shader/node_shader_util.c - texture/nodes/node_texture_at.c texture/nodes/node_texture_bricks.c texture/nodes/node_texture_checker.c @@ -277,7 +184,6 @@ set(SRC texture/node_texture_util.c intern/derived_node_tree.cc - intern/extern_implementations.cc intern/geometry_nodes_eval_log.cc intern/math_functions.cc intern/node_common.cc @@ -287,13 +193,12 @@ set(SRC intern/node_multi_function.cc intern/node_socket.cc intern/node_socket_declarations.cc + intern/socket_search_link.cc intern/node_tree_ref.cc intern/node_util.c - intern/type_conversions.cc composite/node_composite_util.hh function/node_function_util.hh - shader/node_shader_util.h texture/node_texture_util.h NOD_common.h @@ -310,10 +215,10 @@ set(SRC NOD_shader.h NOD_socket.h NOD_socket_declarations.hh + NOD_socket_search_link.hh NOD_socket_declarations_geometry.hh NOD_static_types.h NOD_texture.h - NOD_type_conversions.hh intern/node_common.h intern/node_exec.h intern/node_util.h @@ -322,8 +227,8 @@ set(SRC set(LIB bf_bmesh bf_functions - bf_intern_sky bf_nodes_geometry + bf_nodes_shader ) if(WITH_BULLET) diff --git a/source/blender/nodes/NOD_common.h b/source/blender/nodes/NOD_common.h index fa979bb4799..e488352170b 100644 --- a/source/blender/nodes/NOD_common.h +++ b/source/blender/nodes/NOD_common.h @@ -35,9 +35,11 @@ void register_node_type_reroute(void); void register_node_type_group_input(void); void register_node_type_group_output(void); -/* internal functions for editor */ +/* Internal functions for editor. */ + struct bNodeSocket *node_group_find_input_socket(struct bNode *groupnode, const char *identifier); struct bNodeSocket *node_group_find_output_socket(struct bNode *groupnode, const char *identifier); +/** Make sure all group node in ntree, which use ngroup, are sync'd. */ void node_group_update(struct bNodeTree *ntree, struct bNode *node); struct bNodeSocket *node_group_input_find_socket(struct bNode *node, const char *identifier); diff --git a/source/blender/nodes/NOD_derived_node_tree.hh b/source/blender/nodes/NOD_derived_node_tree.hh index 895f7ef6d5b..dc619deb5d2 100644 --- a/source/blender/nodes/NOD_derived_node_tree.hh +++ b/source/blender/nodes/NOD_derived_node_tree.hh @@ -72,8 +72,10 @@ class DTreeContext { bool is_root() const; }; -/* A (nullable) reference to a node and the context it is in. It is unique within an entire nested - * node group hierarchy. This type is small and can be passed around by value. */ +/** + * A (nullable) reference to a node and the context it is in. It is unique within an entire nested + * node group hierarchy. This type is small and can be passed around by value. + */ class DNode { private: const DTreeContext *context_ = nullptr; @@ -100,11 +102,13 @@ class DNode { DOutputSocket output_by_identifier(StringRef identifier) const; }; -/* A (nullable) reference to a socket and the context it is in. It is unique within an entire +/** + * A (nullable) reference to a socket and the context it is in. It is unique within an entire * nested node group hierarchy. This type is small and can be passed around by value. * * A #DSocket can represent an input or an output socket. If the type of a socket is known at - * compile time is preferable to use #DInputSocket or #DOutputSocket instead. */ + * compile time is preferable to use #DInputSocket or #DOutputSocket instead. + */ class DSocket { protected: const DTreeContext *context_ = nullptr; @@ -129,7 +133,7 @@ class DSocket { DNode node() const; }; -/* A (nullable) reference to an input socket and the context it is in. */ +/** A (nullable) reference to an input socket and the context it is in. */ class DInputSocket : public DSocket { public: DInputSocket() = default; @@ -142,10 +146,15 @@ class DInputSocket : public DSocket { DOutputSocket get_corresponding_group_node_output() const; Vector<DOutputSocket, 4> get_corresponding_group_input_sockets() const; + /** + * Call `origin_fn` for every "real" origin socket. "Real" means that reroutes, muted nodes + * and node groups are handled by this function. Origin sockets are ones where a node gets its + * inputs from. + */ void foreach_origin_socket(FunctionRef<void(DSocket)> origin_fn) const; }; -/* A (nullable) reference to an output socket and the context it is in. */ +/** A (nullable) reference to an output socket and the context it is in. */ class DOutputSocket : public DSocket { public: DOutputSocket() = default; @@ -166,6 +175,11 @@ class DOutputSocket : public DSocket { using ForeachTargetSocketFn = FunctionRef<void(DInputSocket, const TargetSocketPathInfo &path_info)>; + /** + * Calls `target_fn` for every "real" target socket. "Real" means that reroutes, muted nodes + * and node groups are handled by this function. Target sockets are on the nodes that use the + * value from this socket. + */ void foreach_target_socket(ForeachTargetSocketFn target_fn) const; private: @@ -180,16 +194,27 @@ class DerivedNodeTree { VectorSet<const NodeTreeRef *> used_node_tree_refs_; public: + /** + * Construct a new derived node tree for a given root node tree. The generated derived node tree + * does not own the used node tree refs (so that those can be used by others as well). The caller + * has to make sure that the node tree refs added to #node_tree_refs live at least as long as the + * derived node tree. + */ DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs); ~DerivedNodeTree(); const DTreeContext &root_context() const; Span<const NodeTreeRef *> used_node_tree_refs() const; + /** + * \return True when there is a link cycle. Unavailable sockets are ignored. + */ bool has_link_cycles() const; bool has_undefined_nodes_or_sockets() const; + /** Calls the given callback on all nodes in the (possibly nested) derived node tree. */ void foreach_node(FunctionRef<void(DNode)> callback) const; + /** Generates a graph in dot format. The generated graph has all node groups inlined. */ std::string to_dot() const; private: @@ -246,6 +271,7 @@ inline bool DTreeContext::is_root() const { return parent_context_ == nullptr; } + /** \} */ /* -------------------------------------------------------------------- */ @@ -312,6 +338,7 @@ inline DOutputSocket DNode::output_by_identifier(StringRef identifier) const { return {context_, &node_ref_->output_by_identifier(identifier)}; } + /** \} */ /* -------------------------------------------------------------------- */ @@ -374,6 +401,7 @@ inline DNode DSocket::node() const BLI_assert(socket_ref_ != nullptr); return {context_, &socket_ref_->node()}; } + /** \} */ /* -------------------------------------------------------------------- */ @@ -399,6 +427,7 @@ inline const InputSocketRef *DInputSocket::operator->() const { return (const InputSocketRef *)socket_ref_; } + /** \} */ /* -------------------------------------------------------------------- */ @@ -424,6 +453,7 @@ inline const OutputSocketRef *DOutputSocket::operator->() const { return (const OutputSocketRef *)socket_ref_; } + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/nodes/NOD_function.h b/source/blender/nodes/NOD_function.h index 81f0667fe1c..be3998a916c 100644 --- a/source/blender/nodes/NOD_function.h +++ b/source/blender/nodes/NOD_function.h @@ -24,7 +24,7 @@ void register_node_type_fn_legacy_random_float(void); void register_node_type_fn_align_euler_to_vector(void); void register_node_type_fn_boolean_math(void); -void register_node_type_fn_float_compare(void); +void register_node_type_fn_compare(void); void register_node_type_fn_float_to_int(void); void register_node_type_fn_input_bool(void); void register_node_type_fn_input_color(void); diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index ea3458af065..a0b8e237f19 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -16,12 +16,12 @@ #pragma once +#include "BKE_node.h" + #ifdef __cplusplus extern "C" { #endif -#include "BKE_node.h" - extern struct bNodeTreeType *ntreeType_Geometry; void register_node_tree_type_geo(void); @@ -57,6 +57,7 @@ void register_node_type_geo_attribute_combine_xyz(void); void register_node_type_geo_attribute_compare(void); void register_node_type_geo_attribute_convert(void); void register_node_type_geo_attribute_curve_map(void); +void register_node_type_geo_attribute_domain_size(void); void register_node_type_geo_attribute_fill(void); void register_node_type_geo_attribute_map_range(void); void register_node_type_geo_attribute_math(void); @@ -75,7 +76,6 @@ void register_node_type_geo_curve_fill(void); void register_node_type_geo_curve_fillet(void); void register_node_type_geo_curve_handle_type_selection(void); void register_node_type_geo_curve_length(void); -void register_node_type_geo_curve_parameter(void); void register_node_type_geo_curve_primitive_bezier_segment(void); void register_node_type_geo_curve_primitive_circle(void); void register_node_type_geo_curve_primitive_line(void); @@ -88,13 +88,16 @@ void register_node_type_geo_curve_reverse(void); void register_node_type_geo_curve_sample(void); void register_node_type_geo_curve_set_handles(void); void register_node_type_geo_curve_spline_type(void); +void register_node_type_geo_curve_spline_parameter(void); void register_node_type_geo_curve_subdivide(void); void register_node_type_geo_curve_to_mesh(void); void register_node_type_geo_curve_to_points(void); void register_node_type_geo_curve_trim(void); void register_node_type_geo_delete_geometry(void); void register_node_type_geo_distribute_points_on_faces(void); +void register_node_type_geo_dual_mesh(void); void register_node_type_geo_edge_split(void); +void register_node_type_geo_geometry_to_instance(void); void register_node_type_geo_image_texture(void); void register_node_type_geo_input_curve_handles(void); void register_node_type_geo_input_curve_tilt(void); @@ -102,9 +105,16 @@ void register_node_type_geo_input_id(void); void register_node_type_geo_input_index(void); void register_node_type_geo_input_material_index(void); void register_node_type_geo_input_material(void); +void register_node_type_geo_input_mesh_edge_neighbors(void); +void register_node_type_geo_input_mesh_edge_vertices(void); +void register_node_type_geo_input_mesh_face_area(void); +void register_node_type_geo_input_mesh_face_neighbors(void); +void register_node_type_geo_input_mesh_island(void); +void register_node_type_geo_input_mesh_vertex_neighbors(void); void register_node_type_geo_input_normal(void); void register_node_type_geo_input_position(void); void register_node_type_geo_input_radius(void); +void register_node_type_geo_input_scene_time(void); void register_node_type_geo_input_shade_smooth(void); void register_node_type_geo_input_spline_cyclic(void); void register_node_type_geo_input_spline_length(void); diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh index 700f32ee414..f225b3b94b2 100644 --- a/source/blender/nodes/NOD_geometry_exec.hh +++ b/source/blender/nodes/NOD_geometry_exec.hh @@ -28,6 +28,8 @@ #include "NOD_derived_node_tree.hh" #include "NOD_geometry_nodes_eval_log.hh" +#include "GEO_realize_instances.hh" + struct Depsgraph; struct ModifierData; @@ -36,8 +38,8 @@ namespace blender::nodes { using bke::AnonymousAttributeFieldInput; using bke::AttributeFieldInput; using bke::AttributeIDRef; -using bke::geometry_set_realize_instances; using bke::GeometryComponentFieldContext; +using bke::GeometryFieldInput; using bke::OutputAttribute; using bke::OutputAttribute_Typed; using bke::ReadAttributeLookup; @@ -59,6 +61,7 @@ using fn::GVArray; using fn::GVArray_GSpan; using fn::GVMutableArray; using fn::GVMutableArray_GSpan; +using fn::ValueOrField; using geometry_nodes_eval_log::NodeWarningType; /** @@ -117,6 +120,8 @@ class GeoNodeExecParamsProvider { virtual bool output_is_required(StringRef identifier) const = 0; virtual bool lazy_require_input(StringRef identifier) = 0; virtual bool lazy_output_is_required(StringRef identifier) const = 0; + + virtual void set_default_remaining_outputs() = 0; }; class GeoNodeExecParams { @@ -129,7 +134,7 @@ class GeoNodeExecParams { } template<typename T> - static inline constexpr bool is_stored_as_field_v = std::is_same_v<T, float> || + static inline constexpr bool is_field_base_type_v = std::is_same_v<T, float> || std::is_same_v<T, int> || std::is_same_v<T, bool> || std::is_same_v<T, ColorGeometry4f> || @@ -157,9 +162,15 @@ class GeoNodeExecParams { */ template<typename T> T extract_input(StringRef identifier) { - if constexpr (is_stored_as_field_v<T>) { - Field<T> field = this->extract_input<Field<T>>(identifier); - return fn::evaluate_constant_field(field); + if constexpr (is_field_base_type_v<T>) { + ValueOrField<T> value_or_field = this->extract_input<ValueOrField<T>>(identifier); + return value_or_field.as_value(); + } + else if constexpr (fn::is_field_v<T>) { + using BaseType = typename T::base_type; + ValueOrField<BaseType> value_or_field = this->extract_input<ValueOrField<BaseType>>( + identifier); + return value_or_field.as_field(); } else { #ifdef DEBUG @@ -186,9 +197,9 @@ class GeoNodeExecParams { Vector<GMutablePointer> gvalues = provider_->extract_multi_input(identifier); Vector<T> values; for (GMutablePointer gvalue : gvalues) { - if constexpr (is_stored_as_field_v<T>) { - const Field<T> field = gvalue.relocate_out<Field<T>>(); - values.append(fn::evaluate_constant_field(field)); + if constexpr (is_field_base_type_v<T>) { + const ValueOrField<T> value_or_field = gvalue.relocate_out<ValueOrField<T>>(); + values.append(value_or_field.as_value()); } else { values.append(gvalue.relocate_out<T>()); @@ -200,11 +211,16 @@ class GeoNodeExecParams { /** * Get the input value for the input socket with the given identifier. */ - template<typename T> const T get_input(StringRef identifier) const + template<typename T> T get_input(StringRef identifier) const { - if constexpr (is_stored_as_field_v<T>) { - const Field<T> &field = this->get_input<Field<T>>(identifier); - return fn::evaluate_constant_field(field); + if constexpr (is_field_base_type_v<T>) { + ValueOrField<T> value_or_field = this->get_input<ValueOrField<T>>(identifier); + return value_or_field.as_value(); + } + else if constexpr (fn::is_field_v<T>) { + using BaseType = typename T::base_type; + ValueOrField<BaseType> value_or_field = this->get_input<ValueOrField<BaseType>>(identifier); + return value_or_field.as_field(); } else { #ifdef DEBUG @@ -226,9 +242,12 @@ class GeoNodeExecParams { template<typename T> void set_output(StringRef identifier, T &&value) { using StoredT = std::decay_t<T>; - if constexpr (is_stored_as_field_v<StoredT>) { - this->set_output<Field<StoredT>>(identifier, - fn::make_constant_field<StoredT>(std::forward<T>(value))); + if constexpr (is_field_base_type_v<StoredT>) { + this->set_output(identifier, ValueOrField<StoredT>(std::forward<T>(value))); + } + else if constexpr (fn::is_field_v<StoredT>) { + using BaseType = typename StoredT::base_type; + this->set_output(identifier, ValueOrField<BaseType>(std::forward<T>(value))); } else { const CPPType &type = CPPType::get<StoredT>(); @@ -336,12 +355,19 @@ class GeoNodeExecParams { const GeometryComponent &component, const CustomDataType default_type) const; + /** + * If any of the corresponding input sockets are attributes instead of single values, + * use the highest priority attribute domain from among them. + * Otherwise return the default domain. + */ AttributeDomain get_highest_priority_input_domain(Span<std::string> names, const GeometryComponent &component, const AttributeDomain default_domain) const; std::string attribute_producer_name() const; + void set_default_remaining_outputs(); + private: /* Utilities for detecting common errors at when using this class. */ void check_input_access(StringRef identifier, const CPPType *requested_type = nullptr) const; diff --git a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh index 2a118057a03..ac2c29b4ec2 100644 --- a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh +++ b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh @@ -41,6 +41,8 @@ #include "NOD_derived_node_tree.hh" +#include <chrono> + struct SpaceNode; struct SpaceSpreadsheet; @@ -169,6 +171,16 @@ struct NodeWithWarning { NodeWarning warning; }; +struct NodeWithExecutionTime { + DNode node; + std::chrono::microseconds exec_time; +}; + +struct NodeWithDebugMessage { + DNode node; + std::string message; +}; + /** The same value can be referenced by multiple sockets when they are linked. */ struct ValueOfSockets { Span<DSocket> sockets; @@ -189,6 +201,8 @@ class LocalGeoLogger { std::unique_ptr<LinearAllocator<>> allocator_; Vector<ValueOfSockets> values_; Vector<NodeWithWarning> node_warnings_; + Vector<NodeWithExecutionTime> node_exec_times_; + Vector<NodeWithDebugMessage> node_debug_messages_; friend ModifierLog; @@ -201,6 +215,12 @@ class LocalGeoLogger { void log_value_for_sockets(Span<DSocket> sockets, GPointer value); void log_multi_value_socket(DSocket socket, Span<GPointer> values); void log_node_warning(DNode node, NodeWarningType type, std::string message); + void log_execution_time(DNode node, std::chrono::microseconds exec_time); + /** + * Log a message that will be displayed in the node editor next to the node. + * This should only be used for debugging purposes and not to display information to users. + */ + void log_debug_message(DNode node, std::string message); }; /** The root logger class. */ @@ -274,12 +294,15 @@ class NodeLog { Vector<SocketLog> input_logs_; Vector<SocketLog> output_logs_; Vector<NodeWarning, 0> warnings_; + Vector<std::string, 0> debug_messages_; + std::chrono::microseconds exec_time_; friend ModifierLog; public: const SocketLog *lookup_socket_log(eNodeSocketInOut in_out, int index) const; const SocketLog *lookup_socket_log(const bNode &node, const bNodeSocket &socket) const; + void execution_time(std::chrono::microseconds exec_time); Span<SocketLog> input_logs() const { @@ -296,6 +319,16 @@ class NodeLog { return warnings_; } + Span<std::string> debug_messages() const + { + return debug_messages_; + } + + std::chrono::microseconds execution_time() const + { + return exec_time_; + } + Vector<const GeometryAttributeInfo *> lookup_available_attributes() const; }; diff --git a/source/blender/nodes/NOD_math_functions.hh b/source/blender/nodes/NOD_math_functions.hh index 86ff8cab3e9..54abc754346 100644 --- a/source/blender/nodes/NOD_math_functions.hh +++ b/source/blender/nodes/NOD_math_functions.hh @@ -204,7 +204,7 @@ inline bool try_dispatch_float_math_fl_fl_fl_to_fl(const int operation, Callback * This is similar to try_dispatch_float_math_fl_to_fl, just with a different callback signature. */ template<typename Callback> -inline bool try_dispatch_float_math_fl_fl_to_bool(const FloatCompareOperation operation, +inline bool try_dispatch_float_math_fl_fl_to_bool(const NodeCompareOperation operation, Callback &&callback) { const FloatMathOperationInfo *info = get_float_compare_operation_info(operation); @@ -219,13 +219,13 @@ inline bool try_dispatch_float_math_fl_fl_to_bool(const FloatCompareOperation op }; switch (operation) { - case NODE_FLOAT_COMPARE_LESS_THAN: + case NODE_COMPARE_LESS_THAN: return dispatch([](float a, float b) { return a < b; }); - case NODE_FLOAT_COMPARE_LESS_EQUAL: + case NODE_COMPARE_LESS_EQUAL: return dispatch([](float a, float b) { return a <= b; }); - case NODE_FLOAT_COMPARE_GREATER_THAN: + case NODE_COMPARE_GREATER_THAN: return dispatch([](float a, float b) { return a > b; }); - case NODE_FLOAT_COMPARE_GREATER_EQUAL: + case NODE_COMPARE_GREATER_EQUAL: return dispatch([](float a, float b) { return a >= b; }); default: return false; diff --git a/source/blender/nodes/NOD_node_declaration.hh b/source/blender/nodes/NOD_node_declaration.hh index 9b99026d6a7..af2130ec452 100644 --- a/source/blender/nodes/NOD_node_declaration.hh +++ b/source/blender/nodes/NOD_node_declaration.hh @@ -16,6 +16,7 @@ #pragma once +#include <functional> #include <type_traits> #include "BLI_string_ref.hh" @@ -23,6 +24,8 @@ #include "DNA_node_types.h" +struct bNode; + namespace blender::nodes { class NodeDeclarationBuilder; @@ -84,8 +87,12 @@ class SocketDeclaration { std::string name_; std::string identifier_; std::string description_; + /** Defined by whether the socket is part of the node's input or + * output socket declaration list. Included here for convenience. */ + eNodeSocketInOut in_out_; bool hide_label_ = false; bool hide_value_ = false; + bool compact_ = false; bool is_multi_input_ = false; bool no_mute_links_ = false; bool is_attribute_name_ = false; @@ -94,19 +101,36 @@ class SocketDeclaration { InputSocketFieldType input_field_type_ = InputSocketFieldType::None; OutputFieldDependency output_field_dependency_; + /** Utility method to make the socket available if there is a straightforward way to do so. */ + std::function<void(bNode &)> make_available_fn_; + friend NodeDeclarationBuilder; template<typename SocketDecl> friend class SocketDeclarationBuilder; public: virtual ~SocketDeclaration() = default; - virtual bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const = 0; + virtual bNodeSocket &build(bNodeTree &ntree, bNode &node) const = 0; virtual bool matches(const bNodeSocket &socket) const = 0; virtual bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const; + /** + * Determine if a new socket described by this declaration could have a valid connection + * the other socket. + */ + virtual bool can_connect(const bNodeSocket &socket) const = 0; + + /** + * Change the node such that the socket will become visible. The node type's update method + * should be called afterwards. + * \note Note that this is not necessarily implemented for all node types. + */ + void make_available(bNode &node) const; + StringRefNull name() const; StringRefNull description() const; StringRefNull identifier() const; + eNodeSocketInOut in_out() const; bool is_attribute_name() const; bool is_default_link_socket() const; @@ -215,6 +239,18 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder { std::move(input_dependencies)); return *(Self *)this; } + + /** + * Pass a function that sets properties on the node required to make the corresponding socket + * available, if it is not available on the default state of the node. The function is allowed to + * make other sockets unavailable, since it is meant to be called when the node is first added. + * The node type's update function is called afterwards. + */ + Self &make_available(std::function<void(bNode &)> fn) + { + decl_->make_available_fn_ = std::move(fn); + return *(Self *)this; + } }; using SocketDeclarationPtr = std::unique_ptr<SocketDeclaration>; @@ -232,6 +268,7 @@ class NodeDeclaration { Span<SocketDeclarationPtr> inputs() const; Span<SocketDeclarationPtr> outputs() const; + Span<SocketDeclarationPtr> sockets(eNodeSocketInOut in_out) const; bool is_function_node() const { @@ -267,7 +304,7 @@ class NodeDeclarationBuilder { template<typename DeclType> typename DeclType::Builder &add_socket(StringRef name, StringRef identifier, - Vector<SocketDeclarationPtr> &r_decls); + eNodeSocketInOut in_out); }; /* -------------------------------------------------------------------- */ @@ -360,6 +397,11 @@ inline StringRefNull SocketDeclaration::identifier() const return identifier_; } +inline eNodeSocketInOut SocketDeclaration::in_out() const +{ + return in_out_; +} + inline StringRefNull SocketDeclaration::description() const { return description_; @@ -385,6 +427,13 @@ inline const OutputFieldDependency &SocketDeclaration::output_field_dependency() return output_field_dependency_; } +inline void SocketDeclaration::make_available(bNode &node) const +{ + if (make_available_fn_) { + make_available_fn_(node); + } +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -400,28 +449,34 @@ template<typename DeclType> inline typename DeclType::Builder &NodeDeclarationBuilder::add_input(StringRef name, StringRef identifier) { - return this->add_socket<DeclType>(name, identifier, declaration_.inputs_); + return this->add_socket<DeclType>(name, identifier, SOCK_IN); } template<typename DeclType> inline typename DeclType::Builder &NodeDeclarationBuilder::add_output(StringRef name, StringRef identifier) { - return this->add_socket<DeclType>(name, identifier, declaration_.outputs_); + return this->add_socket<DeclType>(name, identifier, SOCK_OUT); } template<typename DeclType> -inline typename DeclType::Builder &NodeDeclarationBuilder::add_socket( - StringRef name, StringRef identifier, Vector<SocketDeclarationPtr> &r_decls) +inline typename DeclType::Builder &NodeDeclarationBuilder::add_socket(StringRef name, + StringRef identifier, + eNodeSocketInOut in_out) { static_assert(std::is_base_of_v<SocketDeclaration, DeclType>); using Builder = typename DeclType::Builder; + + Vector<SocketDeclarationPtr> &declarations = in_out == SOCK_IN ? declaration_.inputs_ : + declaration_.outputs_; + std::unique_ptr<DeclType> socket_decl = std::make_unique<DeclType>(); std::unique_ptr<Builder> socket_decl_builder = std::make_unique<Builder>(); socket_decl_builder->decl_ = &*socket_decl; socket_decl->name_ = name; socket_decl->identifier_ = identifier.is_empty() ? name : identifier; - r_decls.append(std::move(socket_decl)); + socket_decl->in_out_ = in_out; + declarations.append(std::move(socket_decl)); Builder &socket_decl_builder_ref = *socket_decl_builder; builders_.append(std::move(socket_decl_builder)); return socket_decl_builder_ref; @@ -443,6 +498,14 @@ inline Span<SocketDeclarationPtr> NodeDeclaration::outputs() const return outputs_; } +inline Span<SocketDeclarationPtr> NodeDeclaration::sockets(eNodeSocketInOut in_out) const +{ + if (in_out == SOCK_IN) { + return inputs_; + } + return outputs_; +} + /** \} */ } // namespace blender::nodes diff --git a/source/blender/nodes/NOD_node_tree_ref.hh b/source/blender/nodes/NOD_node_tree_ref.hh index 26a5dc9d60f..65789069231 100644 --- a/source/blender/nodes/NOD_node_tree_ref.hh +++ b/source/blender/nodes/NOD_node_tree_ref.hh @@ -279,6 +279,9 @@ class NodeTreeRef : NonCopyable, NonMovable { const NodeRef *find_node(const bNode &bnode) const; + /** + * \return True when there is a link cycle. Unavailable sockets are ignored. + */ bool has_link_cycles() const; bool has_undefined_nodes_or_sockets() const; @@ -297,6 +300,10 @@ class NodeTreeRef : NonCopyable, NonMovable { bool has_cycle = false; }; + /** + * Sort nodes topologically from left to right or right to left. + * In the future the result if this could be cached on #NodeTreeRef. + */ ToposortResult toposort(ToposortDirection direction) const; bNodeTree *btree() const; diff --git a/source/blender/nodes/NOD_socket_declarations.hh b/source/blender/nodes/NOD_socket_declarations.hh index f7aea212f73..3fb21a4263d 100644 --- a/source/blender/nodes/NOD_socket_declarations.hh +++ b/source/blender/nodes/NOD_socket_declarations.hh @@ -39,9 +39,10 @@ class Float : public SocketDeclaration { public: using Builder = FloatBuilder; - bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override; + bNodeSocket &build(bNodeTree &ntree, bNode &node) const override; bool matches(const bNodeSocket &socket) const override; bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const override; + bool can_connect(const bNodeSocket &socket) const override; }; class FloatBuilder : public SocketDeclarationBuilder<Float> { @@ -66,9 +67,10 @@ class Int : public SocketDeclaration { public: using Builder = IntBuilder; - bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override; + bNodeSocket &build(bNodeTree &ntree, bNode &node) const override; bool matches(const bNodeSocket &socket) const override; bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const override; + bool can_connect(const bNodeSocket &socket) const override; }; class IntBuilder : public SocketDeclarationBuilder<Int> { @@ -93,9 +95,10 @@ class Vector : public SocketDeclaration { public: using Builder = VectorBuilder; - bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override; + bNodeSocket &build(bNodeTree &ntree, bNode &node) const override; bool matches(const bNodeSocket &socket) const override; bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const override; + bool can_connect(const bNodeSocket &socket) const override; }; class VectorBuilder : public SocketDeclarationBuilder<Vector> { @@ -104,6 +107,7 @@ class VectorBuilder : public SocketDeclarationBuilder<Vector> { VectorBuilder &subtype(PropertySubType subtype); VectorBuilder &min(const float min); VectorBuilder &max(const float max); + VectorBuilder &compact(); }; class BoolBuilder; @@ -116,8 +120,9 @@ class Bool : public SocketDeclaration { public: using Builder = BoolBuilder; - bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override; + bNodeSocket &build(bNodeTree &ntree, bNode &node) const override; bool matches(const bNodeSocket &socket) const override; + bool can_connect(const bNodeSocket &socket) const override; }; class BoolBuilder : public SocketDeclarationBuilder<Bool> { @@ -136,8 +141,9 @@ class Color : public SocketDeclaration { public: using Builder = ColorBuilder; - bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override; + bNodeSocket &build(bNodeTree &ntree, bNode &node) const override; bool matches(const bNodeSocket &socket) const override; + bool can_connect(const bNodeSocket &socket) const override; }; class ColorBuilder : public SocketDeclarationBuilder<Color> { @@ -156,8 +162,9 @@ class String : public SocketDeclaration { public: using Builder = StringBuilder; - bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override; + bNodeSocket &build(bNodeTree &ntree, bNode &node) const override; bool matches(const bNodeSocket &socket) const override; + bool can_connect(const bNodeSocket &socket) const override; }; class StringBuilder : public SocketDeclarationBuilder<String> { @@ -172,9 +179,10 @@ class IDSocketDeclaration : public SocketDeclaration { public: IDSocketDeclaration(const char *idname); - bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override; + bNodeSocket &build(bNodeTree &ntree, bNode &node) const override; bool matches(const bNodeSocket &socket) const override; bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const override; + bool can_connect(const bNodeSocket &socket) const override; }; class Object : public IDSocketDeclaration { @@ -212,6 +220,23 @@ class Image : public IDSocketDeclaration { Image(); }; +class ShaderBuilder; + +class Shader : public SocketDeclaration { + private: + friend ShaderBuilder; + + public: + using Builder = ShaderBuilder; + + bNodeSocket &build(bNodeTree &ntree, bNode &node) const override; + bool matches(const bNodeSocket &socket) const override; + bool can_connect(const bNodeSocket &socket) const; +}; + +class ShaderBuilder : public SocketDeclarationBuilder<Shader> { +}; + /* -------------------------------------------------------------------- */ /** \name #FloatBuilder Inline Methods * \{ */ @@ -300,6 +325,12 @@ inline VectorBuilder &VectorBuilder::max(const float max) return *this; } +inline VectorBuilder &VectorBuilder::compact() +{ + decl_->compact_ = true; + return *this; +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -369,26 +400,3 @@ inline Image::Image() : IDSocketDeclaration("NodeSocketImage") /** \} */ } // namespace blender::nodes::decl - -/* -------------------------------------------------------------------- */ -/** \name External Template Instantiations - * - * Defined in `intern/extern_implementations.cc`. - * \{ */ - -namespace blender::nodes { -#define MAKE_EXTERN_SOCKET_DECLARATION(TYPE) \ - extern template class SocketDeclarationBuilder<TYPE>; \ - extern template TYPE::Builder &NodeDeclarationBuilder::add_input<TYPE>(StringRef, StringRef); \ - extern template TYPE::Builder &NodeDeclarationBuilder::add_output<TYPE>(StringRef, StringRef); - -MAKE_EXTERN_SOCKET_DECLARATION(decl::Float) -MAKE_EXTERN_SOCKET_DECLARATION(decl::Int) -MAKE_EXTERN_SOCKET_DECLARATION(decl::Vector) -MAKE_EXTERN_SOCKET_DECLARATION(decl::Bool) -MAKE_EXTERN_SOCKET_DECLARATION(decl::Color) -MAKE_EXTERN_SOCKET_DECLARATION(decl::String) - -} // namespace blender::nodes - -/** \} */ diff --git a/source/blender/nodes/NOD_socket_declarations_geometry.hh b/source/blender/nodes/NOD_socket_declarations_geometry.hh index 1531f82d67d..0ce07da22ff 100644 --- a/source/blender/nodes/NOD_socket_declarations_geometry.hh +++ b/source/blender/nodes/NOD_socket_declarations_geometry.hh @@ -35,8 +35,9 @@ class Geometry : public SocketDeclaration { public: using Builder = GeometryBuilder; - bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override; + bNodeSocket &build(bNodeTree &ntree, bNode &node) const override; bool matches(const bNodeSocket &socket) const override; + bool can_connect(const bNodeSocket &socket) const override; Span<GeometryComponentType> supported_types() const; bool only_realized_data() const; @@ -52,7 +53,3 @@ class GeometryBuilder : public SocketDeclarationBuilder<Geometry> { }; } // namespace blender::nodes::decl - -namespace blender::nodes { -MAKE_EXTERN_SOCKET_DECLARATION(decl::Geometry) -} diff --git a/source/blender/nodes/NOD_socket_search_link.hh b/source/blender/nodes/NOD_socket_search_link.hh new file mode 100644 index 00000000000..b7594561dc4 --- /dev/null +++ b/source/blender/nodes/NOD_socket_search_link.hh @@ -0,0 +1,151 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include <functional> + +#include "BLI_string_ref.hh" +#include "BLI_vector.hh" + +#include "DNA_node_types.h" /* Necessary for eNodeSocketInOut. */ + +#include "NOD_node_declaration.hh" + +struct bContext; + +namespace blender::nodes { + +/** + * Parameters for the operation operation of adding a node after the link drag search menu closes. + */ +class LinkSearchOpParams { + private: + /** + * Keep track of the nodes added by the callback, so they can be selected or moved afterwards. + */ + Vector<bNode *> &added_nodes_; + + public: + const bContext &C; + bNodeTree &node_tree; + /** + * The node that contains the #socket. + */ + bNode &node; + /** + * The existing socket to connect any added nodes to. Might be an input or output socket. + */ + bNodeSocket &socket; + + LinkSearchOpParams(const bContext &C, + bNodeTree &node_tree, + bNode &node, + bNodeSocket &socket, + Vector<bNode *> &added_nodes) + : added_nodes_(added_nodes), C(C), node_tree(node_tree), node(node), socket(socket) + { + } + + bNode &add_node(StringRef idname); + bNode &add_node(const bNodeType &type); + /** + * Find a socket with the given name (correctly checks for inputs and outputs) + * and connect it to the socket the link drag started from (#socket). + */ + void connect_available_socket(bNode &new_node, StringRef socket_name); + /** + * Like #connect_available_socket, but also calls the node's update function. + */ + void update_and_connect_available_socket(bNode &new_node, StringRef socket_name); +}; + +struct SocketLinkOperation { + using LinkSocketFn = std::function<void(LinkSearchOpParams &link_params)>; + + std::string name; + LinkSocketFn fn; + int weight = 0; +}; + +class GatherLinkSearchOpParams { + /** The current node type. */ + const bNodeType &node_type_; + + const bNodeTree &node_tree_; + + const bNodeSocket &other_socket_; + + /* The operations currently being built. Owned by the caller. */ + Vector<SocketLinkOperation> &items_; + + public: + GatherLinkSearchOpParams(const bNodeType &node_type, + const bNodeTree &node_tree, + const bNodeSocket &other_socket, + Vector<SocketLinkOperation> &items) + : node_type_(node_type), node_tree_(node_tree), other_socket_(other_socket), items_(items) + { + } + + /** + * The node on the other side of the dragged link. + */ + const bNodeSocket &other_socket() const; + + /** + * The node tree the user is editing when the search menu is created. + */ + const bNodeTree &node_tree() const; + + /** + * The type of the node in the current callback. + */ + const bNodeType &node_type() const; + + /** + * Whether to list the input or output sockets of the node. + */ + eNodeSocketInOut in_out() const; + + /** + * \param weight: Used to customize the order when multiple search items match. + * + * \warning When creating lambdas for the #fn argument, be careful not to capture this class + * itself, since it is temporary. That is why we tend to use the same variable name for this + * class (`params`) that we do for the argument to `LinkSocketFn`. + */ + void add_item(std::string socket_name, SocketLinkOperation::LinkSocketFn fn, int weight = 0); +}; + +/** + * This callback can be used for a node type when a few things are true about its inputs. + * To avoid creating more boilerplate, it is the default callback for node types. + * - Either all declared sockets are visible in the default state of the node, *OR* the node's + * type's declaration has been extended with #make_available functions for those sockets. + * + * If a node type does not meet these criteria, the function will do nothing in a release build. + * In a debug build, an assert will most likely be hit. + * + * \note For nodes with the deprecated #bNodeSocketTemplate instead of a declaration, + * these criteria do not apply and the function just tries its best without asserting. + */ +void search_link_ops_for_basic_node(GatherLinkSearchOpParams ¶ms); + +void search_link_ops_for_declarations(GatherLinkSearchOpParams ¶ms, + Span<SocketDeclarationPtr> declarations); + +} // namespace blender::nodes diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 20ad4d359f1..84bc7bf0ceb 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -267,7 +267,7 @@ DefNode(FunctionNode, FN_NODE_LEGACY_RANDOM_FLOAT, 0, "LEGACY_RANDOM_FLOAT", Leg DefNode(FunctionNode, FN_NODE_ALIGN_EULER_TO_VECTOR, def_fn_align_euler_to_vector, "ALIGN_EULER_TO_VECTOR", AlignEulerToVector, "Align Euler To Vector", "") DefNode(FunctionNode, FN_NODE_BOOLEAN_MATH, def_boolean_math, "BOOLEAN_MATH", BooleanMath, "Boolean Math", "") -DefNode(FunctionNode, FN_NODE_COMPARE_FLOATS, def_float_compare, "COMPARE_FLOATS", CompareFloats, "Compare Floats", "") +DefNode(FunctionNode, FN_NODE_COMPARE, def_compare, "COMPARE", Compare, "Compare", "") DefNode(FunctionNode, FN_NODE_FLOAT_TO_INT, def_float_to_int, "FLOAT_TO_INT", FloatToInt, "Float to Integer", "") DefNode(FunctionNode, FN_NODE_INPUT_BOOL, def_fn_input_bool, "INPUT_BOOL", InputBool, "Boolean", "") DefNode(FunctionNode, FN_NODE_INPUT_COLOR, def_fn_input_color, "INPUT_COLOR", InputColor, "Color", "") @@ -325,6 +325,7 @@ DefNode(GeometryNode, GEO_NODE_LEGACY_VOLUME_TO_MESH, def_geo_volume_to_mesh, "L DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_REMOVE, 0, "ATTRIBUTE_REMOVE", AttributeRemove, "Attribute Remove", "") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_STATISTIC, def_geo_attribute_statistic, "ATTRIBUTE_STATISTIC", AttributeStatistic, "Attribute Statistic", "") +DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, def_geo_attribute_domain_size, "ATTRIBUTE_DOMAIN_SIZE", AttributeDomainSize, "Domain Size", "") DefNode(GeometryNode, GEO_NODE_BOUNDING_BOX, 0, "BOUNDING_BOX", BoundBox, "Bounding Box", "") DefNode(GeometryNode, GEO_NODE_CAPTURE_ATTRIBUTE, def_geo_attribute_capture, "CAPTURE_ATTRIBUTE", CaptureAttribute, "Capture Attribute", "") DefNode(GeometryNode, GEO_NODE_COLLECTION_INFO, def_geo_collection_info, "COLLECTION_INFO", CollectionInfo, "Collection Info", "") @@ -332,7 +333,7 @@ DefNode(GeometryNode, GEO_NODE_CONVEX_HULL, 0, "CONVEX_HULL", ConvexHull, "Conve DefNode(GeometryNode, GEO_NODE_CURVE_ENDPOINT_SELECTION, 0, "CURVE_ENDPOINT_SELECTION", CurveEndpointSelection, "Endpoint Selection", "") DefNode(GeometryNode, GEO_NODE_CURVE_HANDLE_TYPE_SELECTION, def_geo_curve_handle_type_selection, "CURVE_HANDLE_TYPE_SELECTION", CurveHandleTypeSelection, "Handle Type Selection", "") DefNode(GeometryNode, GEO_NODE_CURVE_LENGTH, 0, "CURVE_LENGTH", CurveLength, "Curve Length", "") -DefNode(GeometryNode, GEO_NODE_CURVE_PARAMETER, 0, "CURVE_PARAMETER", CurveParameter, "Curve Parameter", "") +DefNode(GeometryNode, GEO_NODE_CURVE_SPLINE_PARAMETER, 0, "SPLINE_PARAMETER", SplineParameter, "Spline Parameter", "") DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT, def_geo_curve_primitive_bezier_segment, "CURVE_PRIMITIVE_BEZIER_SEGMENT", CurvePrimitiveBezierSegment, "Bezier Segment", "") DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, def_geo_curve_primitive_circle, "CURVE_PRIMITIVE_CIRCLE", CurvePrimitiveCircle, "Curve Circle", "") DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_LINE, def_geo_curve_primitive_line, "CURVE_PRIMITIVE_LINE", CurvePrimitiveLine, "Curve Line", "") @@ -346,8 +347,10 @@ DefNode(GeometryNode, GEO_NODE_CURVE_TO_MESH, 0, "CURVE_TO_MESH", CurveToMesh, " DefNode(GeometryNode, GEO_NODE_CURVE_TO_POINTS, def_geo_curve_to_points, "CURVE_TO_POINTS", CurveToPoints, "Curve to Points", "") DefNode(GeometryNode, GEO_NODE_DELETE_GEOMETRY, def_geo_delete_geometry, "DELETE_GEOMETRY", DeleteGeometry, "Delete Geometry", "") DefNode(GeometryNode, GEO_NODE_DISTRIBUTE_POINTS_ON_FACES, def_geo_distribute_points_on_faces, "DISTRIBUTE_POINTS_ON_FACES", DistributePointsOnFaces, "Distribute Points on Faces", "") +DefNode(GeometryNode, GEO_NODE_DUAL_MESH, 0, "DUAL_MESH", DualMesh, "Dual Mesh", "") DefNode(GeometryNode, GEO_NODE_FILL_CURVE, def_geo_curve_fill, "FILL_CURVE", FillCurve, "Fill Curve", "") DefNode(GeometryNode, GEO_NODE_FILLET_CURVE, def_geo_curve_fillet, "FILLET_CURVE", FilletCurve, "Fillet Curve", "") +DefNode(GeometryNode, GEO_NODE_GEOMETRY_TO_INSTANCE, 0, "GEOMETRY_TO_INSTANCE", GeometryToInstance, "Geometry to Instance", "") DefNode(GeometryNode, GEO_NODE_IMAGE_TEXTURE, def_geo_image_texture, "IMAGE_TEXTURE", ImageTexture, "Image Texture", "") DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_HANDLES, 0, "INPUT_CURVE_HANDLES", InputCurveHandlePositions, "Curve Handle Positions", "") DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_TILT, 0, "INPUT_CURVE_TILT", InputCurveTilt, "Curve Tilt", "") @@ -355,9 +358,16 @@ DefNode(GeometryNode, GEO_NODE_INPUT_ID, 0, "INPUT_ID", InputID, "ID", "") DefNode(GeometryNode, GEO_NODE_INPUT_INDEX, 0, "INDEX", InputIndex, "Index", "") DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL_INDEX, 0, "INPUT_MATERIAL_INDEX", InputMaterialIndex, "Material Index", "") DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL, def_geo_input_material, "INPUT_MATERIAL", InputMaterial, "Material", "") +DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_NEIGHBORS, 0, "MESH_EDGE_NEIGHBORS", InputMeshEdgeNeighbors, "Edge Neighbors", "") +DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_VERTICES, 0, "MESH_EDGE_VERTICES", InputMeshEdgeVertices, "Edge Vertices", "") +DefNode(GeometryNode, GEO_NODE_INPUT_MESH_FACE_AREA, 0, "MESH_FACE_AREA", InputMeshFaceArea, "Face Area", "") +DefNode(GeometryNode, GEO_NODE_INPUT_MESH_FACE_NEIGHBORS, 0, "MESH_FACE_NEIGHBORS", InputMeshFaceNeighbors, "Face Neighbors", "") +DefNode(GeometryNode, GEO_NODE_INPUT_MESH_ISLAND, 0, "MESH_ISLAND", InputMeshIsland, "Mesh Island", "") +DefNode(GeometryNode, GEO_NODE_INPUT_MESH_VERTEX_NEIGHBORS, 0, "MESH_VERTEX_NEIGHBORS", InputMeshVertexNeighbors, "Vertex Neighbors", "") DefNode(GeometryNode, GEO_NODE_INPUT_NORMAL, 0, "INPUT_NORMAL", InputNormal, "Normal", "") DefNode(GeometryNode, GEO_NODE_INPUT_POSITION, 0, "POSITION", InputPosition, "Position", "") DefNode(GeometryNode, GEO_NODE_INPUT_RADIUS, 0, "INPUT_RADIUS", InputRadius, "Radius", "") +DefNode(GeometryNode, GEO_NODE_INPUT_SCENE_TIME, 0, "INPUT_SCENE_TIME", InputSceneTime, "Scene Time", "") DefNode(GeometryNode, GEO_NODE_INPUT_SHADE_SMOOTH, 0, "INPUT_SHADE_SMOOTH", InputShadeSmooth, "Is Shade Smooth", "") DefNode(GeometryNode, GEO_NODE_INPUT_SPLINE_CYCLIC, 0, "INPUT_SPLINE_CYCLIC", InputSplineCyclic, "Is Spline Cyclic", "") DefNode(GeometryNode, GEO_NODE_INPUT_SPLINE_LENGTH, 0, "SPLINE_LENGTH", SplineLength, "Spline Length", "") @@ -384,7 +394,7 @@ DefNode(GeometryNode, GEO_NODE_POINTS_TO_VERTICES, 0, "POINTS_TO_VERTICES", Poin DefNode(GeometryNode, GEO_NODE_POINTS_TO_VOLUME, def_geo_points_to_volume, "POINTS_TO_VOLUME", PointsToVolume, "Points to Volume", "") DefNode(GeometryNode, GEO_NODE_PROXIMITY, def_geo_proximity, "PROXIMITY", Proximity, "Geometry Proximity", "") DefNode(GeometryNode, GEO_NODE_RAYCAST, def_geo_raycast, "RAYCAST", Raycast, "Raycast", "") -DefNode(GeometryNode, GEO_NODE_REALIZE_INSTANCES, 0, "REALIZE_INSTANCES", RealizeInstances, "Realize Instances", "") +DefNode(GeometryNode, GEO_NODE_REALIZE_INSTANCES, def_geo_realize_instances, "REALIZE_INSTANCES", RealizeInstances, "Realize Instances", "") DefNode(GeometryNode, GEO_NODE_REPLACE_MATERIAL, 0, "REPLACE_MATERIAL", ReplaceMaterial, "Replace Material", "") DefNode(GeometryNode, GEO_NODE_RESAMPLE_CURVE, def_geo_curve_resample, "RESAMPLE_CURVE", ResampleCurve, "Resample Curve", "") DefNode(GeometryNode, GEO_NODE_REVERSE_CURVE, 0, "REVERSE_CURVE", ReverseCurve, "Reverse Curve", "") diff --git a/source/blender/nodes/NOD_type_conversions.hh b/source/blender/nodes/NOD_type_conversions.hh deleted file mode 100644 index c8b24fd1260..00000000000 --- a/source/blender/nodes/NOD_type_conversions.hh +++ /dev/null @@ -1,82 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#pragma once - -#include "FN_multi_function.hh" - -namespace blender::nodes { - -using fn::CPPType; - -struct ConversionFunctions { - const fn::MultiFunction *multi_function; - void (*convert_single_to_initialized)(const void *src, void *dst); - void (*convert_single_to_uninitialized)(const void *src, void *dst); -}; - -class DataTypeConversions { - private: - Map<std::pair<fn::MFDataType, fn::MFDataType>, ConversionFunctions> conversions_; - - public: - void add(fn::MFDataType from_type, - fn::MFDataType to_type, - const fn::MultiFunction &fn, - void (*convert_single_to_initialized)(const void *src, void *dst), - void (*convert_single_to_uninitialized)(const void *src, void *dst)) - { - conversions_.add_new({from_type, to_type}, - {&fn, convert_single_to_initialized, convert_single_to_uninitialized}); - } - - const ConversionFunctions *get_conversion_functions(fn::MFDataType from, fn::MFDataType to) const - { - return conversions_.lookup_ptr({from, to}); - } - - const ConversionFunctions *get_conversion_functions(const CPPType &from, const CPPType &to) const - { - return this->get_conversion_functions(fn::MFDataType::ForSingle(from), - fn::MFDataType::ForSingle(to)); - } - - const fn::MultiFunction *get_conversion_multi_function(fn::MFDataType from, - fn::MFDataType to) const - { - const ConversionFunctions *functions = this->get_conversion_functions(from, to); - return functions ? functions->multi_function : nullptr; - } - - bool is_convertible(const CPPType &from_type, const CPPType &to_type) const - { - return conversions_.contains( - {fn::MFDataType::ForSingle(from_type), fn::MFDataType::ForSingle(to_type)}); - } - - void convert_to_uninitialized(const CPPType &from_type, - const CPPType &to_type, - const void *from_value, - void *to_value) const; - - fn::GVArray try_convert(fn::GVArray varray, const CPPType &to_type) const; - - fn::GVMutableArray try_convert(fn::GVMutableArray varray, const CPPType &to_type) const; -}; - -const DataTypeConversions &get_implicit_type_conversions(); - -} // namespace blender::nodes diff --git a/source/blender/nodes/composite/node_composite_tree.cc b/source/blender/nodes/composite/node_composite_tree.cc index a596a85b748..1326c9edab1 100644 --- a/source/blender/nodes/composite/node_composite_tree.cc +++ b/source/blender/nodes/composite/node_composite_tree.cc @@ -212,7 +212,7 @@ static bool composite_node_tree_socket_type_valid(bNodeTreeType *UNUSED(ntreetyp bNodeTreeType *ntreeType_Composite; -void register_node_tree_type_cmp(void) +void register_node_tree_type_cmp() { bNodeTreeType *tt = ntreeType_Composite = (bNodeTreeType *)MEM_callocN( sizeof(bNodeTreeType), "compositor node tree type"); @@ -259,16 +259,6 @@ void ntreeCompositExecTree(Scene *scene, /* *********************************************** */ -/** - * Update the outputs of the render layer nodes. - * Since the outputs depend on the render engine, this part is a bit complex: - * - #ntreeCompositUpdateRLayers is called and loops over all render layer nodes. - * - Each render layer node calls the update function of the - * render engine that's used for its scene. - * - The render engine calls RE_engine_register_pass for each pass. - * - #RE_engine_register_pass calls #ntreeCompositRegisterPass, - * which calls #node_cmp_rlayers_register_pass for every render layer node. - */ void ntreeCompositUpdateRLayers(bNodeTree *ntree) { if (ntree == nullptr) { @@ -299,8 +289,6 @@ void ntreeCompositRegisterPass(bNodeTree *ntree, } } -/* called from render pipeline, to tag render input and output */ -/* need to do all scenes, to prevent errors when you re-render 1 scene */ void ntreeCompositTagRender(Scene *scene) { /* XXX Think using G_MAIN here is valid, since you want to update current file's scene nodes, diff --git a/source/blender/nodes/composite/node_composite_util.cc b/source/blender/nodes/composite/node_composite_util.cc index 21269b92e65..1262dfad11f 100644 --- a/source/blender/nodes/composite/node_composite_util.cc +++ b/source/blender/nodes/composite/node_composite_util.cc @@ -21,6 +21,8 @@ * \ingroup nodes */ +#include "NOD_socket_search_link.hh" + #include "node_composite_util.hh" bool cmp_node_poll_default(bNodeType *UNUSED(ntype), @@ -28,7 +30,7 @@ bool cmp_node_poll_default(bNodeType *UNUSED(ntype), const char **r_disabled_hint) { if (!STREQ(ntree->idname, "CompositorNodeTree")) { - *r_disabled_hint = "Not a compositor node tree"; + *r_disabled_hint = TIP_("Not a compositor node tree"); return false; } return true; @@ -52,4 +54,5 @@ void cmp_node_type_base(bNodeType *ntype, int type, const char *name, short ncla ntype->poll = cmp_node_poll_default; ntype->updatefunc = cmp_node_update_default; ntype->insert_link = node_insert_link_default; + ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node; } diff --git a/source/blender/nodes/composite/node_composite_util.hh b/source/blender/nodes/composite/node_composite_util.hh index 6fd82ffc93f..04708d0d854 100644 --- a/source/blender/nodes/composite/node_composite_util.hh +++ b/source/blender/nodes/composite/node_composite_util.hh @@ -27,9 +27,6 @@ #include "DNA_movieclip_types.h" #include "DNA_node_types.h" -#include "BLI_blenlib.h" -#include "BLI_math.h" - #include "BLT_translation.h" #include "BKE_colorband.h" @@ -45,8 +42,8 @@ #include "RE_pipeline.h" -/* only for forward declarations */ #include "NOD_composite.h" +#include "NOD_socket.h" #include "NOD_socket_declarations.hh" #define CMP_SCALE_MAX 12000 diff --git a/source/blender/nodes/composite/nodes/node_composite_alphaOver.cc b/source/blender/nodes/composite/nodes/node_composite_alphaOver.cc index b6f64ed00c7..5e6d59edfd5 100644 --- a/source/blender/nodes/composite/nodes/node_composite_alphaOver.cc +++ b/source/blender/nodes/composite/nodes/node_composite_alphaOver.cc @@ -21,32 +21,46 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* **************** ALPHAOVER ******************** */ -static bNodeSocketTemplate cmp_node_alphaover_in[] = { - {SOCK_FLOAT, N_("Fac"), 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_FACTOR}, - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {-1, ""}, -}; -static bNodeSocketTemplate cmp_node_alphaover_out[] = { - {SOCK_RGBA, N_("Image")}, - {-1, ""}, -}; +namespace blender::nodes { + +static void cmp_node_alphaover_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR); + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Color>(N_("Image"), "Image_001").default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_output<decl::Color>(N_("Image")); +} + +} // namespace blender::nodes static void node_alphaover_init(bNodeTree *UNUSED(ntree), bNode *node) { node->storage = MEM_callocN(sizeof(NodeTwoFloats), "NodeTwoFloats"); } -void register_node_type_cmp_alphaover(void) +static void node_composit_buts_alphaover(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *col; + + col = uiLayoutColumn(layout, true); + uiItemR(col, ptr, "use_premultiply", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(col, ptr, "premul", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} + +void register_node_type_cmp_alphaover() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_ALPHAOVER, "Alpha Over", NODE_CLASS_OP_COLOR, 0); - node_type_socket_templates(&ntype, cmp_node_alphaover_in, cmp_node_alphaover_out); + ntype.declare = blender::nodes::cmp_node_alphaover_declare; + ntype.draw_buttons = node_composit_buts_alphaover; node_type_init(&ntype, node_alphaover_init); node_type_storage( &ntype, "NodeTwoFloats", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc b/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc index 23e63b9a53b..02b2652ed6a 100644 --- a/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc +++ b/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc @@ -23,14 +23,22 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* **************** Anti-Aliasing (SMAA 1x) ******************** */ -static bNodeSocketTemplate cmp_node_antialiasing_in[] = { - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, {-1, ""}}; +namespace blender::nodes { -static bNodeSocketTemplate cmp_node_antialiasing_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}}; +static void cmp_node_antialiasing_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_output<decl::Color>(N_("Image")); +} + +} // namespace blender::nodes static void node_composit_init_antialiasing(bNodeTree *UNUSED(ntree), bNode *node) { @@ -44,13 +52,25 @@ static void node_composit_init_antialiasing(bNodeTree *UNUSED(ntree), bNode *nod node->storage = data; } -void register_node_type_cmp_antialiasing(void) +static void node_composit_buts_antialiasing(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *col; + + col = uiLayoutColumn(layout, false); + + uiItemR(col, ptr, "threshold", 0, nullptr, ICON_NONE); + uiItemR(col, ptr, "contrast_limit", 0, nullptr, ICON_NONE); + uiItemR(col, ptr, "corner_rounding", 0, nullptr, ICON_NONE); +} + +void register_node_type_cmp_antialiasing() { static bNodeType ntype; cmp_node_type_base( &ntype, CMP_NODE_ANTIALIASING, "Anti-Aliasing", NODE_CLASS_OP_FILTER, NODE_PREVIEW); - node_type_socket_templates(&ntype, cmp_node_antialiasing_in, cmp_node_antialiasing_out); + ntype.declare = blender::nodes::cmp_node_antialiasing_declare; + ntype.draw_buttons = node_composit_buts_antialiasing; node_type_size(&ntype, 170, 140, 200); node_type_init(&ntype, node_composit_init_antialiasing); node_type_storage( diff --git a/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc b/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc index 3e724d17a10..3f107a13a44 100644 --- a/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc +++ b/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc @@ -21,18 +21,23 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* **************** BILATERALBLUR ******************** */ -static bNodeSocketTemplate cmp_node_bilateralblur_in[] = { - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {SOCK_RGBA, N_("Determinator"), 1.0f, 1.0f, 1.0f, 1.0f}, - {-1, ""}}; -static bNodeSocketTemplate cmp_node_bilateralblur_out[] = { - {SOCK_RGBA, N_("Image")}, - {-1, ""}, -}; +namespace blender::nodes { + +static void cmp_node_bilateralblur_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Color>(N_("Determinator")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_output<decl::Color>(N_("Image")); +} + +} // namespace blender::nodes static void node_composit_init_bilateralblur(bNodeTree *UNUSED(ntree), bNode *node) { @@ -44,12 +49,25 @@ static void node_composit_init_bilateralblur(bNodeTree *UNUSED(ntree), bNode *no nbbd->sigma_space = 5.0; } -void register_node_type_cmp_bilateralblur(void) +static void node_composit_buts_bilateralblur(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiLayout *col; + + col = uiLayoutColumn(layout, true); + uiItemR(col, ptr, "iterations", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(col, ptr, "sigma_color", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(col, ptr, "sigma_space", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} + +void register_node_type_cmp_bilateralblur() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_BILATERALBLUR, "Bilateral Blur", NODE_CLASS_OP_FILTER, 0); - node_type_socket_templates(&ntype, cmp_node_bilateralblur_in, cmp_node_bilateralblur_out); + ntype.declare = blender::nodes::cmp_node_bilateralblur_declare; + ntype.draw_buttons = node_composit_buts_bilateralblur; node_type_init(&ntype, node_composit_init_bilateralblur); node_type_storage( &ntype, "NodeBilateralBlurData", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_blur.cc b/source/blender/nodes/composite/nodes/node_composite_blur.cc index c5c0c21929e..bcc8c786ae5 100644 --- a/source/blender/nodes/composite/nodes/node_composite_blur.cc +++ b/source/blender/nodes/composite/nodes/node_composite_blur.cc @@ -22,14 +22,25 @@ * \ingroup cmpnodes */ +#include "RNA_access.h" + +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* **************** BLUR ******************** */ -static bNodeSocketTemplate cmp_node_blur_in[] = { - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {SOCK_FLOAT, N_("Size"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE}, - {-1, ""}}; -static bNodeSocketTemplate cmp_node_blur_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}}; + +namespace blender::nodes { + +static void cmp_node_blur_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Float>(N_("Size")).default_value(1.0f).min(0.0f).max(1.0f); + b.add_output<decl::Color>(N_("Image")); +} + +} // namespace blender::nodes static void node_composit_init_blur(bNodeTree *UNUSED(ntree), bNode *node) { @@ -38,12 +49,54 @@ static void node_composit_init_blur(bNodeTree *UNUSED(ntree), bNode *node) node->storage = data; } -void register_node_type_cmp_blur(void) +static void node_composit_buts_blur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *col, *row; + + col = uiLayoutColumn(layout, false); + const int filter = RNA_enum_get(ptr, "filter_type"); + const int reference = RNA_boolean_get(ptr, "use_variable_size"); + + uiItemR(col, ptr, "filter_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); + if (filter != R_FILTER_FAST_GAUSS) { + uiItemR(col, ptr, "use_variable_size", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + if (!reference) { + uiItemR(col, ptr, "use_bokeh", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + } + uiItemR(col, ptr, "use_gamma_correction", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + } + + uiItemR(col, ptr, "use_relative", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + if (RNA_boolean_get(ptr, "use_relative")) { + uiItemL(col, IFACE_("Aspect Correction"), ICON_NONE); + row = uiLayoutRow(layout, true); + uiItemR(row, + ptr, + "aspect_correction", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, + nullptr, + ICON_NONE); + + col = uiLayoutColumn(layout, true); + uiItemR(col, ptr, "factor_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("X"), ICON_NONE); + uiItemR(col, ptr, "factor_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Y"), ICON_NONE); + } + else { + col = uiLayoutColumn(layout, true); + uiItemR(col, ptr, "size_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("X"), ICON_NONE); + uiItemR(col, ptr, "size_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Y"), ICON_NONE); + } + uiItemR(col, ptr, "use_extended_bounds", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} + +void register_node_type_cmp_blur() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_BLUR, "Blur", NODE_CLASS_OP_FILTER, NODE_PREVIEW); - node_type_socket_templates(&ntype, cmp_node_blur_in, cmp_node_blur_out); + ntype.declare = blender::nodes::cmp_node_blur_declare; + ntype.draw_buttons = node_composit_buts_blur; node_type_init(&ntype, node_composit_init_blur); node_type_storage( &ntype, "NodeBlurData", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc b/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc index f130a642e20..d0659f6a51e 100644 --- a/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc +++ b/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc @@ -22,18 +22,25 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "../node_composite_util.hh" /* **************** BLUR ******************** */ -static bNodeSocketTemplate cmp_node_bokehblur_in[] = { - {SOCK_RGBA, N_("Image"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, - {SOCK_RGBA, N_("Bokeh"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f}, - {SOCK_FLOAT, N_("Size"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 10.0f}, - {SOCK_FLOAT, N_("Bounding box"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f}, - {-1, ""}}; -static bNodeSocketTemplate cmp_node_bokehblur_out[] = { - {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, {-1, ""}}; +namespace blender::nodes { + +static void cmp_node_bokehblur_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({0.8f, 0.8f, 0.8f, 1.0f}); + b.add_input<decl::Color>(N_("Bokeh")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Float>(N_("Size")).default_value(1.0f).min(0.0f).max(10.0f); + b.add_input<decl::Float>(N_("Bounding box")).default_value(1.0f).min(0.0f).max(1.0f); + b.add_output<decl::Color>(N_("Image")); +} + +} // namespace blender::nodes static void node_composit_init_bokehblur(bNodeTree *UNUSED(ntree), bNode *node) { @@ -41,12 +48,21 @@ static void node_composit_init_bokehblur(bNodeTree *UNUSED(ntree), bNode *node) node->custom4 = 16.0f; } -void register_node_type_cmp_bokehblur(void) +static void node_composit_buts_bokehblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "use_variable_size", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + // uiItemR(layout, ptr, "f_stop", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); /* UNUSED */ + uiItemR(layout, ptr, "blur_max", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "use_extended_bounds", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} + +void register_node_type_cmp_bokehblur() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_BOKEHBLUR, "Bokeh Blur", NODE_CLASS_OP_FILTER, 0); - node_type_socket_templates(&ntype, cmp_node_bokehblur_in, cmp_node_bokehblur_out); + ntype.declare = blender::nodes::cmp_node_bokehblur_declare; + ntype.draw_buttons = node_composit_buts_bokehblur; node_type_init(&ntype, node_composit_init_bokehblur); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc b/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc index 3f8a7606d94..8817a07a422 100644 --- a/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc +++ b/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc @@ -21,6 +21,9 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "../node_composite_util.hh" /* **************** Bokeh image Tools ******************** */ @@ -45,12 +48,28 @@ static void node_composit_init_bokehimage(bNodeTree *UNUSED(ntree), bNode *node) node->storage = data; } -void register_node_type_cmp_bokehimage(void) +static void node_composit_buts_bokehimage(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "flaps", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "angle", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR( + layout, ptr, "rounding", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); + uiItemR(layout, + ptr, + "catadioptric", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, + nullptr, + ICON_NONE); + uiItemR(layout, ptr, "shift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); +} + +void register_node_type_cmp_bokehimage() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_BOKEHIMAGE, "Bokeh Image", NODE_CLASS_INPUT, NODE_PREVIEW); ntype.declare = blender::nodes::cmp_node_bokehimage_declare; + ntype.draw_buttons = node_composit_buts_bokehimage; node_type_init(&ntype, node_composit_init_bokehimage); node_type_storage( &ntype, "NodeBokehImage", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_boxmask.cc b/source/blender/nodes/composite/nodes/node_composite_boxmask.cc index cdf96065f97..40859922154 100644 --- a/source/blender/nodes/composite/nodes/node_composite_boxmask.cc +++ b/source/blender/nodes/composite/nodes/node_composite_boxmask.cc @@ -21,16 +21,23 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "../node_composite_util.hh" /* **************** SCALAR MATH ******************** */ -static bNodeSocketTemplate cmp_node_boxmask_in[] = { - {SOCK_FLOAT, N_("Mask"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, - {SOCK_FLOAT, N_("Value"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, - {-1, ""}}; -static bNodeSocketTemplate cmp_node_boxmask_out[] = { - {SOCK_FLOAT, N_("Mask"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, {-1, ""}}; +namespace blender::nodes { + +static void cmp_node_boxmask_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Float>(N_("Mask")).default_value(0.0f).min(0.0f).max(1.0f); + b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(1.0f); + b.add_output<decl::Float>(N_("Mask")); +} + +} // namespace blender::nodes static void node_composit_init_boxmask(bNodeTree *UNUSED(ntree), bNode *node) { @@ -43,12 +50,29 @@ static void node_composit_init_boxmask(bNodeTree *UNUSED(ntree), bNode *node) node->storage = data; } -void register_node_type_cmp_boxmask(void) +static void node_composit_buts_boxmask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *row; + + row = uiLayoutRow(layout, true); + uiItemR(row, ptr, "x", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(row, ptr, "y", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + row = uiLayoutRow(layout, true); + uiItemR(row, ptr, "width", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); + uiItemR(row, ptr, "height", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); + + uiItemR(layout, ptr, "rotation", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "mask_type", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} + +void register_node_type_cmp_boxmask() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_MASK_BOX, "Box Mask", NODE_CLASS_MATTE, 0); - node_type_socket_templates(&ntype, cmp_node_boxmask_in, cmp_node_boxmask_out); + ntype.declare = blender::nodes::cmp_node_boxmask_declare; + ntype.draw_buttons = node_composit_buts_boxmask; node_type_init(&ntype, node_composit_init_boxmask); node_type_storage(&ntype, "NodeBoxMask", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_brightness.cc b/source/blender/nodes/composite/nodes/node_composite_brightness.cc index 028afad3cf8..ca03a9b4fbf 100644 --- a/source/blender/nodes/composite/nodes/node_composite_brightness.cc +++ b/source/blender/nodes/composite/nodes/node_composite_brightness.cc @@ -21,6 +21,9 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* **************** Bright and Contrast ******************** */ @@ -42,12 +45,20 @@ static void node_composit_init_brightcontrast(bNodeTree *UNUSED(ntree), bNode *n node->custom1 = 1; } -void register_node_type_cmp_brightcontrast(void) +static void node_composit_buts_brightcontrast(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiItemR(layout, ptr, "use_premultiply", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} + +void register_node_type_cmp_brightcontrast() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR, 0); ntype.declare = blender::nodes::cmp_node_brightcontrast_declare; + ntype.draw_buttons = node_composit_buts_brightcontrast; node_type_init(&ntype, node_composit_init_brightcontrast); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_channelMatte.cc b/source/blender/nodes/composite/nodes/node_composite_channelMatte.cc index e211bc45b17..1b4be78c71b 100644 --- a/source/blender/nodes/composite/nodes/node_composite_channelMatte.cc +++ b/source/blender/nodes/composite/nodes/node_composite_channelMatte.cc @@ -21,19 +21,25 @@ * \ingroup cmpnodes */ +#include "RNA_access.h" + +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* ******************* Channel Matte Node ********************************* */ -static bNodeSocketTemplate cmp_node_channel_matte_in[] = { - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {-1, ""}, -}; -static bNodeSocketTemplate cmp_node_channel_matte_out[] = { - {SOCK_RGBA, N_("Image")}, - {SOCK_FLOAT, N_("Matte")}, - {-1, ""}, -}; +namespace blender::nodes { + +static void cmp_node_channel_matte_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_output<decl::Color>(N_("Image")); + b.add_output<decl::Float>(N_("Matte")); +} + +} // namespace blender::nodes static void node_composit_init_channel_matte(bNodeTree *UNUSED(ntree), bNode *node) { @@ -50,13 +56,55 @@ static void node_composit_init_channel_matte(bNodeTree *UNUSED(ntree), bNode *no node->custom2 = 2; /* Green Channel. */ } -void register_node_type_cmp_channel_matte(void) +static void node_composit_buts_channel_matte(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiLayout *col, *row; + + uiItemL(layout, IFACE_("Color Space:"), ICON_NONE); + row = uiLayoutRow(layout, false); + uiItemR( + row, ptr, "color_space", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, nullptr, ICON_NONE); + + col = uiLayoutColumn(layout, false); + uiItemL(col, IFACE_("Key Channel:"), ICON_NONE); + row = uiLayoutRow(col, false); + uiItemR(row, + ptr, + "matte_channel", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, + nullptr, + ICON_NONE); + + col = uiLayoutColumn(layout, false); + + uiItemR(col, ptr, "limit_method", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + if (RNA_enum_get(ptr, "limit_method") == 0) { + uiItemL(col, IFACE_("Limiting Channel:"), ICON_NONE); + row = uiLayoutRow(col, false); + uiItemR(row, + ptr, + "limit_channel", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, + nullptr, + ICON_NONE); + } + + uiItemR( + col, ptr, "limit_max", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); + uiItemR( + col, ptr, "limit_min", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); +} + +void register_node_type_cmp_channel_matte() { static bNodeType ntype; cmp_node_type_base( &ntype, CMP_NODE_CHANNEL_MATTE, "Channel Key", NODE_CLASS_MATTE, NODE_PREVIEW); - node_type_socket_templates(&ntype, cmp_node_channel_matte_in, cmp_node_channel_matte_out); + ntype.declare = blender::nodes::cmp_node_channel_matte_declare; + ntype.draw_buttons = node_composit_buts_channel_matte; node_type_init(&ntype, node_composit_init_channel_matte); node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc b/source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc index 990778160df..a7e3a1c148f 100644 --- a/source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc +++ b/source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc @@ -21,20 +21,24 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* ******************* Chroma Key ********************************************************** */ -static bNodeSocketTemplate cmp_node_chroma_in[] = { - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {SOCK_RGBA, N_("Key Color"), 1.0f, 1.0f, 1.0f, 1.0f}, - {-1, ""}, -}; - -static bNodeSocketTemplate cmp_node_chroma_out[] = { - {SOCK_RGBA, N_("Image")}, - {SOCK_FLOAT, N_("Matte")}, - {-1, ""}, -}; + +namespace blender::nodes { + +static void cmp_node_chroma_matte_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Color>(N_("Key Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_output<decl::Color>(N_("Image")); + b.add_output<decl::Float>(N_("Matte")); +} + +} // namespace blender::nodes static void node_composit_init_chroma_matte(bNodeTree *UNUSED(ntree), bNode *node) { @@ -47,12 +51,29 @@ static void node_composit_init_chroma_matte(bNodeTree *UNUSED(ntree), bNode *nod c->fstrength = 1.0f; } -void register_node_type_cmp_chroma_matte(void) +static void node_composit_buts_chroma_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *col; + + col = uiLayoutColumn(layout, false); + uiItemR(col, ptr, "tolerance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(col, ptr, "threshold", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + col = uiLayoutColumn(layout, true); + /* Removed for now. */ + // uiItemR(col, ptr, "lift", UI_ITEM_R_SLIDER, nullptr, ICON_NONE); + uiItemR(col, ptr, "gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); + /* Removed for now. */ + // uiItemR(col, ptr, "shadow_adjust", UI_ITEM_R_SLIDER, nullptr, ICON_NONE); +} + +void register_node_type_cmp_chroma_matte() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_CHROMA_MATTE, "Chroma Key", NODE_CLASS_MATTE, NODE_PREVIEW); - node_type_socket_templates(&ntype, cmp_node_chroma_in, cmp_node_chroma_out); + ntype.declare = blender::nodes::cmp_node_chroma_matte_declare; + ntype.draw_buttons = node_composit_buts_chroma_matte; node_type_init(&ntype, node_composit_init_chroma_matte); node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_colorMatte.cc b/source/blender/nodes/composite/nodes/node_composite_colorMatte.cc index fc9a0075b14..367b046f3f6 100644 --- a/source/blender/nodes/composite/nodes/node_composite_colorMatte.cc +++ b/source/blender/nodes/composite/nodes/node_composite_colorMatte.cc @@ -21,20 +21,24 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" -/* ******************* Color Key ********************************************************** */ -static bNodeSocketTemplate cmp_node_color_in[] = { - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {SOCK_RGBA, N_("Key Color"), 1.0f, 1.0f, 1.0f, 1.0f}, - {-1, ""}, -}; +/* ******************* Color Matte ********************************************************** */ + +namespace blender::nodes { + +static void cmp_node_color_matte_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Color>(N_("Key Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_output<decl::Color>(N_("Image")); + b.add_output<decl::Float>(N_("Matte")); +} -static bNodeSocketTemplate cmp_node_color_out[] = { - {SOCK_RGBA, N_("Image")}, - {SOCK_FLOAT, N_("Matte")}, - {-1, ""}, -}; +} // namespace blender::nodes static void node_composit_init_color_matte(bNodeTree *UNUSED(ntree), bNode *node) { @@ -47,12 +51,30 @@ static void node_composit_init_color_matte(bNodeTree *UNUSED(ntree), bNode *node c->fstrength = 1.0f; } -void register_node_type_cmp_color_matte(void) +static void node_composit_buts_color_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *col; + + col = uiLayoutColumn(layout, true); + uiItemR( + col, ptr, "color_hue", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); + uiItemR(col, + ptr, + "color_saturation", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, + nullptr, + ICON_NONE); + uiItemR( + col, ptr, "color_value", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); +} + +void register_node_type_cmp_color_matte() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_COLOR_MATTE, "Color Key", NODE_CLASS_MATTE, NODE_PREVIEW); - node_type_socket_templates(&ntype, cmp_node_color_in, cmp_node_color_out); + ntype.declare = blender::nodes::cmp_node_color_matte_declare; + ntype.draw_buttons = node_composit_buts_color_matte; node_type_init(&ntype, node_composit_init_color_matte); node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc b/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc index 7bdc2e8289e..e136041cf6e 100644 --- a/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc +++ b/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc @@ -21,19 +21,25 @@ * \ingroup cmpnodes */ +#include "RNA_access.h" + +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* ******************* Color Spill Suppression ********************************* */ -static bNodeSocketTemplate cmp_node_color_spill_in[] = { - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {SOCK_FLOAT, N_("Fac"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_FACTOR}, - {-1, ""}, -}; -static bNodeSocketTemplate cmp_node_color_spill_out[] = { - {SOCK_RGBA, N_("Image")}, - {-1, ""}, -}; +namespace blender::nodes { + +static void cmp_node_color_spill_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR); + b.add_output<decl::Color>(N_("Image")); +} + +} // namespace blender::nodes static void node_composit_init_color_spill(bNodeTree *UNUSED(ntree), bNode *node) { @@ -46,12 +52,59 @@ static void node_composit_init_color_spill(bNodeTree *UNUSED(ntree), bNode *node ncs->unspill = 0; /* do not use unspill */ } -void register_node_type_cmp_color_spill(void) +static void node_composit_buts_color_spill(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *row, *col; + + uiItemL(layout, IFACE_("Despill Channel:"), ICON_NONE); + row = uiLayoutRow(layout, false); + uiItemR(row, ptr, "channel", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, nullptr, ICON_NONE); + + col = uiLayoutColumn(layout, false); + uiItemR(col, ptr, "limit_method", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + if (RNA_enum_get(ptr, "limit_method") == 0) { + uiItemL(col, IFACE_("Limiting Channel:"), ICON_NONE); + row = uiLayoutRow(col, false); + uiItemR(row, + ptr, + "limit_channel", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, + nullptr, + ICON_NONE); + } + + uiItemR(col, ptr, "ratio", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); + uiItemR(col, ptr, "use_unspill", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + if (RNA_boolean_get(ptr, "use_unspill") == true) { + uiItemR(col, + ptr, + "unspill_red", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, + nullptr, + ICON_NONE); + uiItemR(col, + ptr, + "unspill_green", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, + nullptr, + ICON_NONE); + uiItemR(col, + ptr, + "unspill_blue", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, + nullptr, + ICON_NONE); + } +} + +void register_node_type_cmp_color_spill() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_COLOR_SPILL, "Color Spill", NODE_CLASS_MATTE, 0); - node_type_socket_templates(&ntype, cmp_node_color_spill_in, cmp_node_color_spill_out); + ntype.declare = blender::nodes::cmp_node_color_spill_declare; + ntype.draw_buttons = node_composit_buts_color_spill; node_type_init(&ntype, node_composit_init_color_spill); node_type_storage( &ntype, "NodeColorspill", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc b/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc index ef8af5f81a6..a35b3d813e6 100644 --- a/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc +++ b/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc @@ -21,6 +21,11 @@ * \ingroup cmpnodes */ +#include "RNA_access.h" + +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* ******************* Color Balance ********************************* */ @@ -39,8 +44,7 @@ static void cmp_node_colorbalance_declare(NodeDeclarationBuilder &b) /* Sync functions update formula parameters for other modes, such that the result is comparable. * Note that the results are not exactly the same due to differences in color handling * (sRGB conversion happens for LGG), - * but this keeps settings comparable. - */ + * but this keeps settings comparable. */ void ntreeCompositColorBalanceSyncFromLGG(bNodeTree *UNUSED(ntree), bNode *node) { @@ -80,12 +84,88 @@ static void node_composit_init_colorbalance(bNodeTree *UNUSED(ntree), bNode *nod node->storage = n; } -void register_node_type_cmp_colorbalance(void) +static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *split, *col, *row; + + uiItemR(layout, ptr, "correction_method", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + if (RNA_enum_get(ptr, "correction_method") == 0) { + + split = uiLayoutSplit(layout, 0.0f, false); + col = uiLayoutColumn(split, false); + uiTemplateColorPicker(col, ptr, "lift", true, true, false, true); + row = uiLayoutRow(col, false); + uiItemR(row, ptr, "lift", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + col = uiLayoutColumn(split, false); + uiTemplateColorPicker(col, ptr, "gamma", true, true, true, true); + row = uiLayoutRow(col, false); + uiItemR(row, ptr, "gamma", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + col = uiLayoutColumn(split, false); + uiTemplateColorPicker(col, ptr, "gain", true, true, true, true); + row = uiLayoutRow(col, false); + uiItemR(row, ptr, "gain", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + } + else { + + split = uiLayoutSplit(layout, 0.0f, false); + col = uiLayoutColumn(split, false); + uiTemplateColorPicker(col, ptr, "offset", true, true, false, true); + row = uiLayoutRow(col, false); + uiItemR(row, ptr, "offset", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(col, ptr, "offset_basis", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + col = uiLayoutColumn(split, false); + uiTemplateColorPicker(col, ptr, "power", true, true, false, true); + row = uiLayoutRow(col, false); + uiItemR(row, ptr, "power", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + col = uiLayoutColumn(split, false); + uiTemplateColorPicker(col, ptr, "slope", true, true, false, true); + row = uiLayoutRow(col, false); + uiItemR(row, ptr, "slope", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + } +} + +static void node_composit_buts_colorbalance_ex(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiItemR(layout, ptr, "correction_method", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + if (RNA_enum_get(ptr, "correction_method") == 0) { + + uiTemplateColorPicker(layout, ptr, "lift", true, true, false, true); + uiItemR(layout, ptr, "lift", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + uiTemplateColorPicker(layout, ptr, "gamma", true, true, true, true); + uiItemR(layout, ptr, "gamma", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + uiTemplateColorPicker(layout, ptr, "gain", true, true, true, true); + uiItemR(layout, ptr, "gain", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + } + else { + uiTemplateColorPicker(layout, ptr, "offset", true, true, false, true); + uiItemR(layout, ptr, "offset", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + uiTemplateColorPicker(layout, ptr, "power", true, true, false, true); + uiItemR(layout, ptr, "power", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + uiTemplateColorPicker(layout, ptr, "slope", true, true, false, true); + uiItemR(layout, ptr, "slope", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + } +} + +void register_node_type_cmp_colorbalance() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_COLORBALANCE, "Color Balance", NODE_CLASS_OP_COLOR, 0); ntype.declare = blender::nodes::cmp_node_colorbalance_declare; + ntype.draw_buttons = node_composit_buts_colorbalance; + ntype.draw_buttons_ex = node_composit_buts_colorbalance_ex; node_type_size(&ntype, 400, 200, 400); node_type_init(&ntype, node_composit_init_colorbalance); node_type_storage( diff --git a/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc b/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc index 095fbef826a..e3bba3b6c4f 100644 --- a/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc +++ b/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc @@ -21,6 +21,9 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* ******************* Color Correction ********************************* */ @@ -66,12 +69,230 @@ static void node_composit_init_colorcorrection(bNodeTree *UNUSED(ntree), bNode * node->storage = n; } -void register_node_type_cmp_colorcorrection(void) +static void node_composit_buts_colorcorrection(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiLayout *row; + + row = uiLayoutRow(layout, false); + uiItemR(row, ptr, "red", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(row, ptr, "green", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(row, ptr, "blue", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + row = uiLayoutRow(layout, false); + uiItemL(row, "", ICON_NONE); + uiItemL(row, IFACE_("Saturation"), ICON_NONE); + uiItemL(row, IFACE_("Contrast"), ICON_NONE); + uiItemL(row, IFACE_("Gamma"), ICON_NONE); + uiItemL(row, IFACE_("Gain"), ICON_NONE); + uiItemL(row, IFACE_("Lift"), ICON_NONE); + + row = uiLayoutRow(layout, false); + uiItemL(row, IFACE_("Master"), ICON_NONE); + uiItemR( + row, ptr, "master_saturation", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR( + row, ptr, "master_contrast", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "master_gamma", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "master_gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "master_lift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE); + + row = uiLayoutRow(layout, false); + uiItemL(row, IFACE_("Highlights"), ICON_NONE); + uiItemR(row, + ptr, + "highlights_saturation", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, + "", + ICON_NONE); + uiItemR(row, + ptr, + "highlights_contrast", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, + "", + ICON_NONE); + uiItemR( + row, ptr, "highlights_gamma", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR( + row, ptr, "highlights_gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR( + row, ptr, "highlights_lift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE); + + row = uiLayoutRow(layout, false); + uiItemL(row, IFACE_("Midtones"), ICON_NONE); + uiItemR(row, + ptr, + "midtones_saturation", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, + "", + ICON_NONE); + uiItemR( + row, ptr, "midtones_contrast", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR( + row, ptr, "midtones_gamma", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "midtones_gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "midtones_lift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE); + + row = uiLayoutRow(layout, false); + uiItemL(row, IFACE_("Shadows"), ICON_NONE); + uiItemR(row, + ptr, + "shadows_saturation", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, + "", + ICON_NONE); + uiItemR( + row, ptr, "shadows_contrast", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "shadows_gamma", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "shadows_gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "shadows_lift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE); + + row = uiLayoutRow(layout, false); + uiItemR(row, + ptr, + "midtones_start", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, + nullptr, + ICON_NONE); + uiItemR( + row, ptr, "midtones_end", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); +} + +static void node_composit_buts_colorcorrection_ex(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiLayout *row; + + row = uiLayoutRow(layout, false); + uiItemR(row, ptr, "red", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(row, ptr, "green", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(row, ptr, "blue", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + row = layout; + uiItemL(row, IFACE_("Saturation"), ICON_NONE); + uiItemR(row, + ptr, + "master_saturation", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, + nullptr, + ICON_NONE); + uiItemR(row, + ptr, + "highlights_saturation", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, + nullptr, + ICON_NONE); + uiItemR(row, + ptr, + "midtones_saturation", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, + nullptr, + ICON_NONE); + uiItemR(row, + ptr, + "shadows_saturation", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, + nullptr, + ICON_NONE); + + uiItemL(row, IFACE_("Contrast"), ICON_NONE); + uiItemR(row, + ptr, + "master_contrast", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, + nullptr, + ICON_NONE); + uiItemR(row, + ptr, + "highlights_contrast", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, + nullptr, + ICON_NONE); + uiItemR(row, + ptr, + "midtones_contrast", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, + nullptr, + ICON_NONE); + uiItemR(row, + ptr, + "shadows_contrast", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, + nullptr, + ICON_NONE); + + uiItemL(row, IFACE_("Gamma"), ICON_NONE); + uiItemR( + row, ptr, "master_gamma", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); + uiItemR(row, + ptr, + "highlights_gamma", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, + nullptr, + ICON_NONE); + uiItemR(row, + ptr, + "midtones_gamma", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, + nullptr, + ICON_NONE); + uiItemR(row, + ptr, + "shadows_gamma", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, + nullptr, + ICON_NONE); + + uiItemL(row, IFACE_("Gain"), ICON_NONE); + uiItemR( + row, ptr, "master_gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); + uiItemR(row, + ptr, + "highlights_gain", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, + nullptr, + ICON_NONE); + uiItemR(row, + ptr, + "midtones_gain", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, + nullptr, + ICON_NONE); + uiItemR( + row, ptr, "shadows_gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); + + uiItemL(row, IFACE_("Lift"), ICON_NONE); + uiItemR( + row, ptr, "master_lift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); + uiItemR(row, + ptr, + "highlights_lift", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, + nullptr, + ICON_NONE); + uiItemR(row, + ptr, + "midtones_lift", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, + nullptr, + ICON_NONE); + uiItemR( + row, ptr, "shadows_lift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); + + row = uiLayoutRow(layout, false); + uiItemR(row, ptr, "midtones_start", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(row, ptr, "midtones_end", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} + +void register_node_type_cmp_colorcorrection() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_COLORCORRECTION, "Color Correction", NODE_CLASS_OP_COLOR, 0); ntype.declare = blender::nodes::cmp_node_colorcorrection_declare; + ntype.draw_buttons = node_composit_buts_colorcorrection; + ntype.draw_buttons_ex = node_composit_buts_colorcorrection_ex; node_type_size(&ntype, 400, 200, 600); node_type_init(&ntype, node_composit_init_colorcorrection); node_type_storage( diff --git a/source/blender/nodes/composite/nodes/node_composite_common.cc b/source/blender/nodes/composite/nodes/node_composite_common.cc index 6432a89ffa0..aa81cecc3e2 100644 --- a/source/blender/nodes/composite/nodes/node_composite_common.cc +++ b/source/blender/nodes/composite/nodes/node_composite_common.cc @@ -32,14 +32,13 @@ #include "RNA_access.h" -void register_node_type_cmp_group(void) +void register_node_type_cmp_group() { static bNodeType ntype; /* NOTE: Cannot use sh_node_type_base for node group, because it would map the node type * to the shared NODE_GROUP integer type id. */ - node_type_base_custom( - &ntype, "CompositorNodeGroup", "Group", NODE_CLASS_GROUP, NODE_CONST_OUTPUT); + node_type_base_custom(&ntype, "CompositorNodeGroup", "Group", NODE_CLASS_GROUP, 0); ntype.type = NODE_GROUP; ntype.poll = cmp_node_poll_default; ntype.poll_instance = node_group_poll_instance; @@ -50,7 +49,7 @@ void register_node_type_cmp_group(void) node_type_socket_templates(&ntype, nullptr, nullptr); node_type_size(&ntype, 140, 60, 400); - node_type_label(&ntype, node_group_label); + ntype.labelfunc = node_group_label; node_type_group_update(&ntype, node_group_update); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_composite.cc b/source/blender/nodes/composite/nodes/node_composite_composite.cc index a1a49133a3a..547e5123579 100644 --- a/source/blender/nodes/composite/nodes/node_composite_composite.cc +++ b/source/blender/nodes/composite/nodes/node_composite_composite.cc @@ -21,6 +21,9 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* **************** COMPOSITE ******************** */ @@ -36,13 +39,18 @@ static void cmp_node_composite_declare(NodeDeclarationBuilder &b) } // namespace blender::nodes -void register_node_type_cmp_composite(void) +static void node_composit_buts_composite(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "use_alpha", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} + +void register_node_type_cmp_composite() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_COMPOSITE, "Composite", NODE_CLASS_OUTPUT, NODE_PREVIEW); ntype.declare = blender::nodes::cmp_node_composite_declare; - + ntype.draw_buttons = node_composit_buts_composite; ntype.no_muting = true; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc b/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc index b5ca1fb015e..2e7a87a576d 100644 --- a/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc +++ b/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc @@ -23,27 +23,39 @@ #include "node_composite_util.hh" -static bNodeSocketTemplate inputs[] = { - {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, - {SOCK_VECTOR, N_("Upper Left"), 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, - {SOCK_VECTOR, N_("Upper Right"), 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, - {SOCK_VECTOR, N_("Lower Left"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, - {SOCK_VECTOR, N_("Lower Right"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, - {-1, ""}, -}; - -static bNodeSocketTemplate outputs[] = { - {SOCK_RGBA, N_("Image")}, - {SOCK_FLOAT, N_("Plane")}, - {-1, ""}, -}; - -void register_node_type_cmp_cornerpin(void) +namespace blender::nodes { + +static void cmp_node_cornerpin_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Vector>(N_("Upper Left")) + .default_value({0.0f, 1.0f, 0.0f}) + .min(0.0f) + .max(1.0f); + b.add_input<decl::Vector>(N_("Upper Right")) + .default_value({1.0f, 1.0f, 0.0f}) + .min(0.0f) + .max(1.0f); + b.add_input<decl::Vector>(N_("Lower Left")) + .default_value({0.0f, 0.0f, 0.0f}) + .min(0.0f) + .max(1.0f); + b.add_input<decl::Vector>(N_("Lower Right")) + .default_value({1.0f, 0.0f, 0.0f}) + .min(0.0f) + .max(1.0f); + b.add_output<decl::Color>(N_("Image")); + b.add_output<decl::Float>(N_("Plane")); +} + +} // namespace blender::nodes + +void register_node_type_cmp_cornerpin() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_CORNERPIN, "Corner Pin", NODE_CLASS_DISTORT, 0); - node_type_socket_templates(&ntype, inputs, outputs); + ntype.declare = blender::nodes::cmp_node_cornerpin_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_crop.cc b/source/blender/nodes/composite/nodes/node_composite_crop.cc index f07dba8a74b..fa33caa4c0e 100644 --- a/source/blender/nodes/composite/nodes/node_composite_crop.cc +++ b/source/blender/nodes/composite/nodes/node_composite_crop.cc @@ -21,18 +21,24 @@ * \ingroup cmpnodes */ +#include "RNA_access.h" + +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* **************** Crop ******************** */ -static bNodeSocketTemplate cmp_node_crop_in[] = { - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {-1, ""}, -}; -static bNodeSocketTemplate cmp_node_crop_out[] = { - {SOCK_RGBA, N_("Image")}, - {-1, ""}, -}; +namespace blender::nodes { + +static void cmp_node_crop_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_output<decl::Color>(N_("Image")); +} + +} // namespace blender::nodes static void node_composit_init_crop(bNodeTree *UNUSED(ntree), bNode *node) { @@ -44,12 +50,35 @@ static void node_composit_init_crop(bNodeTree *UNUSED(ntree), bNode *node) nxy->y2 = 0; } -void register_node_type_cmp_crop(void) +static void node_composit_buts_crop(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *col; + + uiItemR(layout, ptr, "use_crop_size", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "relative", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + col = uiLayoutColumn(layout, true); + if (RNA_boolean_get(ptr, "relative")) { + uiItemR(col, ptr, "rel_min_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Left"), ICON_NONE); + uiItemR(col, ptr, "rel_max_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Right"), ICON_NONE); + uiItemR(col, ptr, "rel_min_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Up"), ICON_NONE); + uiItemR(col, ptr, "rel_max_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Down"), ICON_NONE); + } + else { + uiItemR(col, ptr, "min_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Left"), ICON_NONE); + uiItemR(col, ptr, "max_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Right"), ICON_NONE); + uiItemR(col, ptr, "min_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Up"), ICON_NONE); + uiItemR(col, ptr, "max_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Down"), ICON_NONE); + } +} + +void register_node_type_cmp_crop() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_CROP, "Crop", NODE_CLASS_DISTORT, 0); - node_type_socket_templates(&ntype, cmp_node_crop_in, cmp_node_crop_out); + ntype.declare = blender::nodes::cmp_node_crop_declare; + ntype.draw_buttons = node_composit_buts_crop; node_type_init(&ntype, node_composit_init_crop); node_type_storage(&ntype, "NodeTwoXYs", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc index 6657267b016..65b1f6799d7 100644 --- a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc +++ b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc @@ -38,8 +38,10 @@ #include <optional> +/* -------------------------------------------------------------------- */ /** \name Cryptomatte * \{ */ + static blender::bke::cryptomatte::CryptomatteSessionPtr cryptomatte_init_from_node_render( const bNode &node, const bool use_meta_data) { @@ -297,16 +299,16 @@ static bool node_poll_cryptomatte(bNodeType *UNUSED(ntype), } if (scene == nullptr) { - *r_disabled_hint = - "The node tree must be the compositing node tree of any scene in the file"; + *r_disabled_hint = TIP_( + "The node tree must be the compositing node tree of any scene in the file"); } return scene != nullptr; } - *r_disabled_hint = "Not a compositor node tree"; + *r_disabled_hint = TIP_("Not a compositor node tree"); return false; } -void register_node_type_cmp_cryptomatte(void) +void register_node_type_cmp_cryptomatte() { static bNodeType ntype; @@ -322,8 +324,10 @@ void register_node_type_cmp_cryptomatte(void) /** \} */ +/* -------------------------------------------------------------------- */ /** \name Cryptomatte Legacy * \{ */ + static void node_init_cryptomatte_legacy(bNodeTree *ntree, bNode *node) { node_init_cryptomatte(ntree, node); @@ -361,7 +365,7 @@ int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node) return 1; } -void register_node_type_cmp_cryptomatte_legacy(void) +void register_node_type_cmp_cryptomatte_legacy() { static bNodeType ntype; diff --git a/source/blender/nodes/composite/nodes/node_composite_curves.cc b/source/blender/nodes/composite/nodes/node_composite_curves.cc index 5f99bb57768..518b57dc405 100644 --- a/source/blender/nodes/composite/nodes/node_composite_curves.cc +++ b/source/blender/nodes/composite/nodes/node_composite_curves.cc @@ -21,6 +21,9 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* **************** CURVE Time ******************** */ @@ -42,7 +45,7 @@ static void node_composit_init_curves_time(bNodeTree *UNUSED(ntree), bNode *node node->storage = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); } -void register_node_type_cmp_curve_time(void) +void register_node_type_cmp_curve_time() { static bNodeType ntype; @@ -56,27 +59,34 @@ void register_node_type_cmp_curve_time(void) } /* **************** CURVE VEC ******************** */ -static bNodeSocketTemplate cmp_node_curve_vec_in[] = { - {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE}, - {-1, ""}, -}; -static bNodeSocketTemplate cmp_node_curve_vec_out[] = { - {SOCK_VECTOR, N_("Vector")}, - {-1, ""}, -}; +namespace blender::nodes { + +static void cmp_node_curve_vec_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Vector>(N_("Vector")).default_value({0.0f, 0.0f, 0.0f}).min(-1.0f).max(1.0f); + b.add_output<decl::Vector>(N_("Vector")); +} + +} // namespace blender::nodes static void node_composit_init_curve_vec(bNodeTree *UNUSED(ntree), bNode *node) { node->storage = BKE_curvemapping_add(3, -1.0f, -1.0f, 1.0f, 1.0f); } -void register_node_type_cmp_curve_vec(void) +static void node_buts_curvevec(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiTemplateCurveMapping(layout, ptr, "mapping", 'v', false, false, false, false); +} + +void register_node_type_cmp_curve_vec() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_CURVE_VEC, "Vector Curves", NODE_CLASS_OP_VECTOR, 0); - node_type_socket_templates(&ntype, cmp_node_curve_vec_in, cmp_node_curve_vec_out); + ntype.declare = blender::nodes::cmp_node_curve_vec_declare; + ntype.draw_buttons = node_buts_curvevec; node_type_size(&ntype, 200, 140, 320); node_type_init(&ntype, node_composit_init_curve_vec); node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves); @@ -105,7 +115,7 @@ static void node_composit_init_curve_rgb(bNodeTree *UNUSED(ntree), bNode *node) node->storage = BKE_curvemapping_add(4, 0.0f, 0.0f, 1.0f, 1.0f); } -void register_node_type_cmp_curve_rgb(void) +void register_node_type_cmp_curve_rgb() { static bNodeType ntype; diff --git a/source/blender/nodes/composite/nodes/node_composite_defocus.cc b/source/blender/nodes/composite/nodes/node_composite_defocus.cc index 1103aff4366..0ee8a8da1e8 100644 --- a/source/blender/nodes/composite/nodes/node_composite_defocus.cc +++ b/source/blender/nodes/composite/nodes/node_composite_defocus.cc @@ -21,20 +21,27 @@ * \ingroup cmpnodes */ -#include "node_composite_util.hh" - #include <climits> +#include "RNA_access.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "node_composite_util.hh" + /* ************ Defocus Node ****************** */ -static bNodeSocketTemplate cmp_node_defocus_in[] = { - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {SOCK_FLOAT, N_("Z"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, - {-1, ""}, -}; -static bNodeSocketTemplate cmp_node_defocus_out[] = { - {SOCK_RGBA, N_("Image")}, - {-1, ""}, -}; + +namespace blender::nodes { + +static void cmp_node_defocus_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Float>(N_("Z")).default_value(1.0f).min(0.0f).max(1.0f); + b.add_output<decl::Color>(N_("Image")); +} + +} // namespace blender::nodes static void node_composit_init_defocus(bNodeTree *UNUSED(ntree), bNode *node) { @@ -53,12 +60,52 @@ static void node_composit_init_defocus(bNodeTree *UNUSED(ntree), bNode *node) node->storage = nbd; } -void register_node_type_cmp_defocus(void) +static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA *ptr) +{ + uiLayout *sub, *col; + + col = uiLayoutColumn(layout, false); + uiItemL(col, IFACE_("Bokeh Type:"), ICON_NONE); + uiItemR(col, ptr, "bokeh", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); + uiItemR(col, ptr, "angle", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + uiItemR(layout, ptr, "use_gamma_correction", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + col = uiLayoutColumn(layout, false); + uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_zbuffer") == true); + uiItemR(col, ptr, "f_stop", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + uiItemR(layout, ptr, "blur_max", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "threshold", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + col = uiLayoutColumn(layout, false); + uiItemR(col, ptr, "use_preview", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + uiTemplateID(layout, + C, + ptr, + "scene", + nullptr, + nullptr, + nullptr, + UI_TEMPLATE_ID_FILTER_ALL, + false, + nullptr); + + col = uiLayoutColumn(layout, false); + uiItemR(col, ptr, "use_zbuffer", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + sub = uiLayoutColumn(col, false); + uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_zbuffer") == false); + uiItemR(sub, ptr, "z_scale", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} + +void register_node_type_cmp_defocus() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_DEFOCUS, "Defocus", NODE_CLASS_OP_FILTER, 0); - node_type_socket_templates(&ntype, cmp_node_defocus_in, cmp_node_defocus_out); + ntype.declare = blender::nodes::cmp_node_defocus_declare; + ntype.draw_buttons = node_composit_buts_defocus; node_type_init(&ntype, node_composit_init_defocus); node_type_storage(&ntype, "NodeDefocus", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_denoise.cc b/source/blender/nodes/composite/nodes/node_composite_denoise.cc index ec085794462..f1e5388a7a3 100644 --- a/source/blender/nodes/composite/nodes/node_composite_denoise.cc +++ b/source/blender/nodes/composite/nodes/node_composite_denoise.cc @@ -23,14 +23,26 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" -static bNodeSocketTemplate cmp_node_denoise_in[] = { - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f}, - {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, - {SOCK_RGBA, N_("Albedo"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, - {-1, ""}}; -static bNodeSocketTemplate cmp_node_denoise_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}}; +namespace blender::nodes { + +static void cmp_node_denoise_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Vector>(N_("Normal")) + .default_value({0.0f, 0.0f, 0.0f}) + .min(-1.0f) + .max(1.0f) + .hide_value(); + b.add_input<decl::Color>(N_("Albedo")).default_value({1.0f, 1.0f, 1.0f, 1.0f}).hide_value(); + b.add_output<decl::Color>(N_("Image")); +} + +} // namespace blender::nodes static void node_composit_init_denonise(bNodeTree *UNUSED(ntree), bNode *node) { @@ -40,12 +52,31 @@ static void node_composit_init_denonise(bNodeTree *UNUSED(ntree), bNode *node) node->storage = ndg; } -void register_node_type_cmp_denoise(void) +static void node_composit_buts_denoise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ +#ifndef WITH_OPENIMAGEDENOISE + uiItemL(layout, IFACE_("Disabled, built without OpenImageDenoise"), ICON_ERROR); +#else + /* Always supported through Accelerate framework BNNS on macOS. */ +# ifndef __APPLE__ + if (!BLI_cpu_support_sse41()) { + uiItemL(layout, IFACE_("Disabled, CPU with SSE4.1 is required"), ICON_ERROR); + } +# endif +#endif + + uiItemL(layout, IFACE_("Prefilter:"), ICON_NONE); + uiItemR(layout, ptr, "prefilter", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "use_hdr", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} + +void register_node_type_cmp_denoise() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_DENOISE, "Denoise", NODE_CLASS_OP_FILTER, 0); - node_type_socket_templates(&ntype, cmp_node_denoise_in, cmp_node_denoise_out); + ntype.declare = blender::nodes::cmp_node_denoise_declare; + ntype.draw_buttons = node_composit_buts_denoise; node_type_init(&ntype, node_composit_init_denonise); node_type_storage(&ntype, "NodeDenoise", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_despeckle.cc b/source/blender/nodes/composite/nodes/node_composite_despeckle.cc index 52d91dabeb1..411bad14f25 100644 --- a/source/blender/nodes/composite/nodes/node_composite_despeckle.cc +++ b/source/blender/nodes/composite/nodes/node_composite_despeckle.cc @@ -21,18 +21,23 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* **************** FILTER ******************** */ -static bNodeSocketTemplate cmp_node_despeckle_in[] = { - {SOCK_FLOAT, N_("Fac"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_FACTOR}, - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {-1, ""}, -}; -static bNodeSocketTemplate cmp_node_despeckle_out[] = { - {SOCK_RGBA, N_("Image")}, - {-1, ""}, -}; + +namespace blender::nodes { + +static void cmp_node_despeckle_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR); + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_output<decl::Color>(N_("Image")); +} + +} // namespace blender::nodes static void node_composit_init_despeckle(bNodeTree *UNUSED(ntree), bNode *node) { @@ -40,12 +45,22 @@ static void node_composit_init_despeckle(bNodeTree *UNUSED(ntree), bNode *node) node->custom4 = 0.5f; } -void register_node_type_cmp_despeckle(void) +static void node_composit_buts_despeckle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *col; + + col = uiLayoutColumn(layout, false); + uiItemR(col, ptr, "threshold", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(col, ptr, "threshold_neighbor", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} + +void register_node_type_cmp_despeckle() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_DESPECKLE, "Despeckle", NODE_CLASS_OP_FILTER, NODE_PREVIEW); - node_type_socket_templates(&ntype, cmp_node_despeckle_in, cmp_node_despeckle_out); + ntype.declare = blender::nodes::cmp_node_despeckle_declare; + ntype.draw_buttons = node_composit_buts_despeckle; node_type_init(&ntype, node_composit_init_despeckle); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_diffMatte.cc b/source/blender/nodes/composite/nodes/node_composite_diffMatte.cc index 1e1a48381b7..a9e3258c8fb 100644 --- a/source/blender/nodes/composite/nodes/node_composite_diffMatte.cc +++ b/source/blender/nodes/composite/nodes/node_composite_diffMatte.cc @@ -21,20 +21,24 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* ******************* channel Difference Matte ********************************* */ -static bNodeSocketTemplate cmp_node_diff_matte_in[] = { - {SOCK_RGBA, N_("Image 1"), 1.0f, 1.0f, 1.0f, 1.0f}, - {SOCK_RGBA, N_("Image 2"), 1.0f, 1.0f, 1.0f, 1.0f}, - {-1, ""}, -}; - -static bNodeSocketTemplate cmp_node_diff_matte_out[] = { - {SOCK_RGBA, N_("Image")}, - {SOCK_FLOAT, N_("Matte")}, - {-1, ""}, -}; + +namespace blender::nodes { + +static void cmp_node_diff_matte_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image 1")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Color>(N_("Image 2")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_output<decl::Color>(N_("Image")); + b.add_output<decl::Color>(N_("Matte")); +} + +} // namespace blender::nodes static void node_composit_init_diff_matte(bNodeTree *UNUSED(ntree), bNode *node) { @@ -44,13 +48,24 @@ static void node_composit_init_diff_matte(bNodeTree *UNUSED(ntree), bNode *node) c->t2 = 0.1f; } -void register_node_type_cmp_diff_matte(void) +static void node_composit_buts_diff_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *col; + + col = uiLayoutColumn(layout, true); + uiItemR( + col, ptr, "tolerance", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); + uiItemR(col, ptr, "falloff", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); +} + +void register_node_type_cmp_diff_matte() { static bNodeType ntype; cmp_node_type_base( &ntype, CMP_NODE_DIFF_MATTE, "Difference Key", NODE_CLASS_MATTE, NODE_PREVIEW); - node_type_socket_templates(&ntype, cmp_node_diff_matte_in, cmp_node_diff_matte_out); + ntype.declare = blender::nodes::cmp_node_diff_matte_declare; + ntype.draw_buttons = node_composit_buts_diff_matte; node_type_init(&ntype, node_composit_init_diff_matte); node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_dilate.cc b/source/blender/nodes/composite/nodes/node_composite_dilate.cc index 57884a299da..1af2bb0433b 100644 --- a/source/blender/nodes/composite/nodes/node_composite_dilate.cc +++ b/source/blender/nodes/composite/nodes/node_composite_dilate.cc @@ -21,13 +21,24 @@ * \ingroup cmpnodes */ +#include "RNA_access.h" + +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* **************** Dilate/Erode ******************** */ -static bNodeSocketTemplate cmp_node_dilateerode_in[] = { - {SOCK_FLOAT, N_("Mask"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, {-1, ""}}; -static bNodeSocketTemplate cmp_node_dilateerode_out[] = {{SOCK_FLOAT, N_("Mask")}, {-1, ""}}; +namespace blender::nodes { + +static void cmp_node_dilate_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Float>(N_("Mask")).default_value(0.0f).min(0.0f).max(1.0f); + b.add_output<decl::Float>(N_("Mask")); +} + +} // namespace blender::nodes static void node_composit_init_dilateerode(bNodeTree *UNUSED(ntree), bNode *node) { @@ -37,12 +48,27 @@ static void node_composit_init_dilateerode(bNodeTree *UNUSED(ntree), bNode *node node->storage = data; } -void register_node_type_cmp_dilateerode(void) +static void node_composit_buts_dilateerode(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "mode", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "distance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + switch (RNA_enum_get(ptr, "mode")) { + case CMP_NODE_DILATEERODE_DISTANCE_THRESH: + uiItemR(layout, ptr, "edge", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + break; + case CMP_NODE_DILATEERODE_DISTANCE_FEATHER: + uiItemR(layout, ptr, "falloff", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + break; + } +} + +void register_node_type_cmp_dilateerode() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_DILATEERODE, "Dilate/Erode", NODE_CLASS_OP_FILTER, 0); - node_type_socket_templates(&ntype, cmp_node_dilateerode_in, cmp_node_dilateerode_out); + ntype.draw_buttons = node_composit_buts_dilateerode; + ntype.declare = blender::nodes::cmp_node_dilate_declare; node_type_init(&ntype, node_composit_init_dilateerode); node_type_storage( &ntype, "NodeDilateErode", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc b/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc index d9f82ba5009..36b130d55a4 100644 --- a/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc +++ b/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc @@ -21,12 +21,20 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" -static bNodeSocketTemplate cmp_node_dblur_in[] = {{SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {-1, ""}}; +namespace blender::nodes { + +static void cmp_node_directional_blur_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_output<decl::Color>(N_("Image")); +} -static bNodeSocketTemplate cmp_node_dblur_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}}; +} // namespace blender::nodes static void node_composit_init_dblur(bNodeTree *UNUSED(ntree), bNode *node) { @@ -37,12 +45,37 @@ static void node_composit_init_dblur(bNodeTree *UNUSED(ntree), bNode *node) ndbd->center_y = 0.5; } -void register_node_type_cmp_dblur(void) +static void node_composit_buts_dblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *col; + + uiItemR(layout, ptr, "iterations", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "use_wrap", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + col = uiLayoutColumn(layout, true); + uiItemL(col, IFACE_("Center:"), ICON_NONE); + uiItemR(col, ptr, "center_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("X"), ICON_NONE); + uiItemR(col, ptr, "center_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Y"), ICON_NONE); + + uiItemS(layout); + + col = uiLayoutColumn(layout, true); + uiItemR(col, ptr, "distance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(col, ptr, "angle", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + uiItemS(layout); + + uiItemR(layout, ptr, "spin", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "zoom", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} + +void register_node_type_cmp_dblur() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_DBLUR, "Directional Blur", NODE_CLASS_OP_FILTER, 0); - node_type_socket_templates(&ntype, cmp_node_dblur_in, cmp_node_dblur_out); + ntype.declare = blender::nodes::cmp_node_directional_blur_declare; + ntype.draw_buttons = node_composit_buts_dblur; node_type_init(&ntype, node_composit_init_dblur); node_type_storage( &ntype, "NodeDBlurData", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_displace.cc b/source/blender/nodes/composite/nodes/node_composite_displace.cc index b1ed7f05794..0137c1f7da8 100644 --- a/source/blender/nodes/composite/nodes/node_composite_displace.cc +++ b/source/blender/nodes/composite/nodes/node_composite_displace.cc @@ -25,24 +25,29 @@ /* **************** Displace ******************** */ -static bNodeSocketTemplate cmp_node_displace_in[] = { - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {SOCK_VECTOR, N_("Vector"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_TRANSLATION}, - {SOCK_FLOAT, N_("X Scale"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f, PROP_NONE}, - {SOCK_FLOAT, N_("Y Scale"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f, PROP_NONE}, - {-1, ""}, -}; -static bNodeSocketTemplate cmp_node_displace_out[] = { - {SOCK_RGBA, N_("Image")}, - {-1, ""}, -}; - -void register_node_type_cmp_displace(void) +namespace blender::nodes { + +static void cmp_node_displace_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Vector>(N_("Vector")) + .default_value({1.0f, 1.0f, 1.0f}) + .min(0.0f) + .max(1.0f) + .subtype(PROP_TRANSLATION); + b.add_input<decl::Float>(N_("X Scale")).default_value(0.0f).min(-1000.0f).max(1000.0f); + b.add_input<decl::Float>(N_("Y Scale")).default_value(0.0f).min(-1000.0f).max(1000.0f); + b.add_output<decl::Color>(N_("Image")); +} + +} // namespace blender::nodes + +void register_node_type_cmp_displace() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_DISPLACE, "Displace", NODE_CLASS_DISTORT, 0); - node_type_socket_templates(&ntype, cmp_node_displace_in, cmp_node_displace_out); + ntype.declare = blender::nodes::cmp_node_displace_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc b/source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc index 3f8767ecd08..47a48ed141e 100644 --- a/source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc +++ b/source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc @@ -21,20 +21,24 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* ******************* channel Distance Matte ********************************* */ -static bNodeSocketTemplate cmp_node_distance_matte_in[] = { - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {SOCK_RGBA, N_("Key Color"), 1.0f, 1.0f, 1.0f, 1.0f}, - {-1, ""}, -}; - -static bNodeSocketTemplate cmp_node_distance_matte_out[] = { - {SOCK_RGBA, N_("Image")}, - {SOCK_FLOAT, N_("Matte")}, - {-1, ""}, -}; + +namespace blender::nodes { + +static void cmp_node_distance_matte_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Color>(N_("Key Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_output<decl::Color>(N_("Image")); + b.add_output<decl::Float>(N_("Matte")); +} + +} // namespace blender::nodes static void node_composit_init_distance_matte(bNodeTree *UNUSED(ntree), bNode *node) { @@ -45,12 +49,30 @@ static void node_composit_init_distance_matte(bNodeTree *UNUSED(ntree), bNode *n c->t2 = 0.1f; } -void register_node_type_cmp_distance_matte(void) +static void node_composit_buts_distance_matte(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiLayout *col, *row; + + col = uiLayoutColumn(layout, true); + + uiItemL(layout, IFACE_("Color Space:"), ICON_NONE); + row = uiLayoutRow(layout, false); + uiItemR(row, ptr, "channel", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, nullptr, ICON_NONE); + + uiItemR( + col, ptr, "tolerance", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); + uiItemR(col, ptr, "falloff", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); +} + +void register_node_type_cmp_distance_matte() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_DIST_MATTE, "Distance Key", NODE_CLASS_MATTE, NODE_PREVIEW); - node_type_socket_templates(&ntype, cmp_node_distance_matte_in, cmp_node_distance_matte_out); + ntype.declare = blender::nodes::cmp_node_distance_matte_declare; + ntype.draw_buttons = node_composit_buts_distance_matte; node_type_init(&ntype, node_composit_init_distance_matte); node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc b/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc index 7c9a48efc2d..4fde539e6fb 100644 --- a/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc +++ b/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc @@ -20,31 +20,46 @@ /** \file * \ingroup cmpnodes */ + +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" + /* **************** Double Edge Mask ******************** */ -static bNodeSocketTemplate cmp_node_doubleedgemask_in[] = { - /* Inner mask socket definition. */ - {SOCK_FLOAT, "Inner Mask", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f, PROP_NONE}, - /* Outer mask socket definition. */ - {SOCK_FLOAT, "Outer Mask", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f, PROP_NONE}, - /* Input socket array terminator. */ - {-1, ""}, -}; -static bNodeSocketTemplate cmp_node_doubleedgemask_out[] = { - /* Output socket definition. */ - {SOCK_FLOAT, "Mask"}, - /* Output socket array terminator. */ - {-1, ""}, -}; - -void register_node_type_cmp_doubleedgemask(void) +namespace blender::nodes { + +static void cmp_node_double_edge_mask_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Float>(N_("Inner Mask")).default_value(0.8f).min(0.0f).max(1.0f); + b.add_input<decl::Float>(N_("Outer Mask")).default_value(0.8f).min(0.0f).max(1.0f); + b.add_output<decl::Float>(N_("Mask")); +} + +} // namespace blender::nodes + +static void node_composit_buts_double_edge_mask(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiLayout *col; + + col = uiLayoutColumn(layout, false); + + uiItemL(col, IFACE_("Inner Edge:"), ICON_NONE); + uiItemR(col, ptr, "inner_mode", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); + uiItemL(col, IFACE_("Buffer Edge:"), ICON_NONE); + uiItemR(col, ptr, "edge_mode", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); +} + +void register_node_type_cmp_doubleedgemask() { static bNodeType ntype; /* Allocate a node type data structure. */ cmp_node_type_base(&ntype, CMP_NODE_DOUBLEEDGEMASK, "Double Edge Mask", NODE_CLASS_MATTE, 0); - node_type_socket_templates(&ntype, cmp_node_doubleedgemask_in, cmp_node_doubleedgemask_out); - node_type_socket_templates(&ntype, cmp_node_doubleedgemask_in, cmp_node_doubleedgemask_out); + ntype.declare = blender::nodes::cmp_node_double_edge_mask_declare; + ntype.draw_buttons = node_composit_buts_double_edge_mask; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc b/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc index 67196fb0d35..8eb89e53790 100644 --- a/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc +++ b/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc @@ -21,16 +21,23 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "../node_composite_util.hh" /* **************** SCALAR MATH ******************** */ -static bNodeSocketTemplate cmp_node_ellipsemask_in[] = { - {SOCK_FLOAT, N_("Mask"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, - {SOCK_FLOAT, N_("Value"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, - {-1, ""}}; -static bNodeSocketTemplate cmp_node_ellipsemask_out[] = { - {SOCK_FLOAT, N_("Mask"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, {-1, ""}}; +namespace blender::nodes { + +static void cmp_node_ellipsemask_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Float>(N_("Mask")).default_value(0.0f).min(0.0f).max(1.0f); + b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(1.0f); + b.add_output<decl::Float>(N_("Mask")); +} + +} // namespace blender::nodes static void node_composit_init_ellipsemask(bNodeTree *UNUSED(ntree), bNode *node) { @@ -44,12 +51,27 @@ static void node_composit_init_ellipsemask(bNodeTree *UNUSED(ntree), bNode *node node->storage = data; } -void register_node_type_cmp_ellipsemask(void) +static void node_composit_buts_ellipsemask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *row; + row = uiLayoutRow(layout, true); + uiItemR(row, ptr, "x", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(row, ptr, "y", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + row = uiLayoutRow(layout, true); + uiItemR(row, ptr, "width", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); + uiItemR(row, ptr, "height", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); + + uiItemR(layout, ptr, "rotation", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "mask_type", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} + +void register_node_type_cmp_ellipsemask() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_MASK_ELLIPSE, "Ellipse Mask", NODE_CLASS_MATTE, 0); - node_type_socket_templates(&ntype, cmp_node_ellipsemask_in, cmp_node_ellipsemask_out); + ntype.declare = blender::nodes::cmp_node_ellipsemask_declare; + ntype.draw_buttons = node_composit_buts_ellipsemask; node_type_size(&ntype, 260, 110, 320); node_type_init(&ntype, node_composit_init_ellipsemask); node_type_storage( diff --git a/source/blender/nodes/composite/nodes/node_composite_exposure.cc b/source/blender/nodes/composite/nodes/node_composite_exposure.cc index c1e64065f7e..b696db41a3c 100644 --- a/source/blender/nodes/composite/nodes/node_composite_exposure.cc +++ b/source/blender/nodes/composite/nodes/node_composite_exposure.cc @@ -36,7 +36,7 @@ static void cmp_node_exposure_declare(NodeDeclarationBuilder &b) } // namespace blender::nodes -void register_node_type_cmp_exposure(void) +void register_node_type_cmp_exposure() { static bNodeType ntype; diff --git a/source/blender/nodes/composite/nodes/node_composite_filter.cc b/source/blender/nodes/composite/nodes/node_composite_filter.cc index f07619877f4..3671d502539 100644 --- a/source/blender/nodes/composite/nodes/node_composite_filter.cc +++ b/source/blender/nodes/composite/nodes/node_composite_filter.cc @@ -21,26 +21,37 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* **************** FILTER ******************** */ -static bNodeSocketTemplate cmp_node_filter_in[] = { - {SOCK_FLOAT, N_("Fac"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_FACTOR}, - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {-1, ""}, -}; -static bNodeSocketTemplate cmp_node_filter_out[] = { - {SOCK_RGBA, N_("Image")}, - {-1, ""}, -}; - -void register_node_type_cmp_filter(void) + +namespace blender::nodes { + +static void cmp_node_filter_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR); + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_output<decl::Color>(N_("Image")); +} + +} // namespace blender::nodes + +static void node_composit_buts_filter(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "filter_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); +} + +void register_node_type_cmp_filter() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_FILTER, "Filter", NODE_CLASS_OP_FILTER, NODE_PREVIEW); - node_type_socket_templates(&ntype, cmp_node_filter_in, cmp_node_filter_out); - node_type_label(&ntype, node_filter_label); + ntype.declare = blender::nodes::cmp_node_filter_declare; + ntype.draw_buttons = node_composit_buts_filter; + ntype.labelfunc = node_filter_label; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_flip.cc b/source/blender/nodes/composite/nodes/node_composite_flip.cc index 42aa3141f5c..38bc0f8b855 100644 --- a/source/blender/nodes/composite/nodes/node_composite_flip.cc +++ b/source/blender/nodes/composite/nodes/node_composite_flip.cc @@ -21,25 +21,35 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* **************** Flip ******************** */ -static bNodeSocketTemplate cmp_node_flip_in[] = { - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {-1, ""}, -}; -static bNodeSocketTemplate cmp_node_flip_out[] = { - {SOCK_RGBA, N_("Image")}, - {-1, ""}, -}; +namespace blender::nodes { + +static void cmp_node_flip_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_output<decl::Color>(N_("Image")); +} + +} // namespace blender::nodes + +static void node_composit_buts_flip(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "axis", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); +} -void register_node_type_cmp_flip(void) +void register_node_type_cmp_flip() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_FLIP, "Flip", NODE_CLASS_DISTORT, 0); - node_type_socket_templates(&ntype, cmp_node_flip_in, cmp_node_flip_out); + ntype.declare = blender::nodes::cmp_node_flip_declare; + ntype.draw_buttons = node_composit_buts_flip; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_gamma.cc b/source/blender/nodes/composite/nodes/node_composite_gamma.cc index 74152a27485..438770865ae 100644 --- a/source/blender/nodes/composite/nodes/node_composite_gamma.cc +++ b/source/blender/nodes/composite/nodes/node_composite_gamma.cc @@ -40,7 +40,7 @@ static void cmp_node_gamma_declare(NodeDeclarationBuilder &b) } // namespace blender::nodes -void register_node_type_cmp_gamma(void) +void register_node_type_cmp_gamma() { static bNodeType ntype; diff --git a/source/blender/nodes/composite/nodes/node_composite_glare.cc b/source/blender/nodes/composite/nodes/node_composite_glare.cc index 8a2fd1e1584..adaf22395c3 100644 --- a/source/blender/nodes/composite/nodes/node_composite_glare.cc +++ b/source/blender/nodes/composite/nodes/node_composite_glare.cc @@ -21,16 +21,22 @@ * \ingroup cmpnodes */ +#include "RNA_access.h" + +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" -static bNodeSocketTemplate cmp_node_glare_in[] = { - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {-1, ""}, -}; -static bNodeSocketTemplate cmp_node_glare_out[] = { - {SOCK_RGBA, N_("Image")}, - {-1, ""}, -}; +namespace blender::nodes { + +static void cmp_node_glare_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_output<decl::Color>(N_("Image")); +} + +} // namespace blender::nodes static void node_composit_init_glare(bNodeTree *UNUSED(ntree), bNode *node) { @@ -49,12 +55,51 @@ static void node_composit_init_glare(bNodeTree *UNUSED(ntree), bNode *node) node->storage = ndg; } -void register_node_type_cmp_glare(void) +static void node_composit_buts_glare(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "glare_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); + uiItemR(layout, ptr, "quality", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); + + if (RNA_enum_get(ptr, "glare_type") != 1) { + uiItemR(layout, ptr, "iterations", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + if (RNA_enum_get(ptr, "glare_type") != 0) { + uiItemR(layout, + ptr, + "color_modulation", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, + nullptr, + ICON_NONE); + } + } + + uiItemR(layout, ptr, "mix", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "threshold", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + if (RNA_enum_get(ptr, "glare_type") == 2) { + uiItemR(layout, ptr, "streaks", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "angle_offset", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + } + if (RNA_enum_get(ptr, "glare_type") == 0 || RNA_enum_get(ptr, "glare_type") == 2) { + uiItemR( + layout, ptr, "fade", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); + + if (RNA_enum_get(ptr, "glare_type") == 0) { + uiItemR(layout, ptr, "use_rotate_45", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + } + } + if (RNA_enum_get(ptr, "glare_type") == 1) { + uiItemR(layout, ptr, "size", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + } +} + +void register_node_type_cmp_glare() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_GLARE, "Glare", NODE_CLASS_OP_FILTER, 0); - node_type_socket_templates(&ntype, cmp_node_glare_in, cmp_node_glare_out); + ntype.declare = blender::nodes::cmp_node_glare_declare; + ntype.draw_buttons = node_composit_buts_glare; node_type_init(&ntype, node_composit_init_glare); node_type_storage(&ntype, "NodeGlare", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc b/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc index 21430035465..47fbaa4d384 100644 --- a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc +++ b/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc @@ -47,7 +47,7 @@ static void cmp_node_huesatval_declare(NodeDeclarationBuilder &b) } // namespace blender::nodes -void register_node_type_cmp_hue_sat(void) +void register_node_type_cmp_hue_sat() { static bNodeType ntype; diff --git a/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc b/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc index 83743bbed18..e78ba0c7f9c 100644 --- a/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc +++ b/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc @@ -51,7 +51,7 @@ static void node_composit_init_huecorrect(bNodeTree *UNUSED(ntree), bNode *node) cumapping->cur = 1; } -void register_node_type_cmp_huecorrect(void) +void register_node_type_cmp_huecorrect() { static bNodeType ntype; diff --git a/source/blender/nodes/composite/nodes/node_composite_idMask.cc b/source/blender/nodes/composite/nodes/node_composite_idMask.cc index 5121370567c..f5b8cb6c567 100644 --- a/source/blender/nodes/composite/nodes/node_composite_idMask.cc +++ b/source/blender/nodes/composite/nodes/node_composite_idMask.cc @@ -21,6 +21,9 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* **************** ID Mask ******************** */ @@ -35,12 +38,19 @@ static void cmp_node_idmask_declare(NodeDeclarationBuilder &b) } // namespace blender::nodes -void register_node_type_cmp_idmask(void) +static void node_composit_buts_id_mask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "index", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "use_antialiasing", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} + +void register_node_type_cmp_idmask() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_ID_MASK, "ID Mask", NODE_CLASS_CONVERTER, 0); ntype.declare = blender::nodes::cmp_node_idmask_declare; + ntype.draw_buttons = node_composit_buts_id_mask; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_image.cc b/source/blender/nodes/composite/nodes/node_composite_image.cc index 40d4d4563c9..8e3cc9bcd95 100644 --- a/source/blender/nodes/composite/nodes/node_composite_image.cc +++ b/source/blender/nodes/composite/nodes/node_composite_image.cc @@ -26,16 +26,21 @@ #include "BLI_linklist.h" #include "BLI_utildefines.h" -#include "DNA_scene_types.h" - -#include "RE_engine.h" - #include "BKE_context.h" #include "BKE_global.h" #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_scene.h" +#include "DNA_scene_types.h" + +#include "RE_engine.h" + +#include "RNA_access.h" + +#include "UI_interface.h" +#include "UI_resources.h" + /* **************** IMAGE (and RenderResult, multilayer image) ******************** */ static bNodeSocketTemplate cmp_node_rlayers_out[] = { @@ -443,7 +448,7 @@ static void node_composit_copy_image(bNodeTree *UNUSED(dest_ntree), } } -void register_node_type_cmp_image(void) +void register_node_type_cmp_image() { static bNodeType ntype; @@ -451,7 +456,7 @@ void register_node_type_cmp_image(void) node_type_init(&ntype, node_composit_init_image); node_type_storage(&ntype, "ImageUser", node_composit_free_image, node_composit_copy_image); node_type_update(&ntype, cmp_node_image_update); - node_type_label(&ntype, node_image_label); + ntype.labelfunc = node_image_label; nodeRegisterType(&ntype); } @@ -499,7 +504,7 @@ static bool node_composit_poll_rlayers(bNodeType *UNUSED(ntype), const char **r_disabled_hint) { if (!STREQ(ntree->idname, "CompositorNodeTree")) { - *r_disabled_hint = "Not a compositor node tree"; + *r_disabled_hint = TIP_("Not a compositor node tree"); return false; } @@ -516,7 +521,8 @@ static bool node_composit_poll_rlayers(bNodeType *UNUSED(ntype), } if (scene == nullptr) { - *r_disabled_hint = "The node tree must be the compositing node tree of any scene in the file"; + *r_disabled_hint = TIP_( + "The node tree must be the compositing node tree of any scene in the file"); return false; } return true; @@ -554,12 +560,56 @@ static void cmp_node_rlayers_update(bNodeTree *ntree, bNode *node) cmp_node_update_default(ntree, node); } -void register_node_type_cmp_rlayers(void) +static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, PointerRNA *ptr) +{ + bNode *node = (bNode *)ptr->data; + uiLayout *col, *row; + + uiTemplateID(layout, + C, + ptr, + "scene", + nullptr, + nullptr, + nullptr, + UI_TEMPLATE_ID_FILTER_ALL, + false, + nullptr); + + if (!node->id) { + return; + } + + col = uiLayoutColumn(layout, false); + row = uiLayoutRow(col, true); + uiItemR(row, ptr, "layer", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); + + PropertyRNA *prop = RNA_struct_find_property(ptr, "layer"); + const char *layer_name; + if (!(RNA_property_enum_identifier( + C, ptr, prop, RNA_property_enum_get(ptr, prop), &layer_name))) { + return; + } + + PointerRNA scn_ptr; + char scene_name[MAX_ID_NAME - 2]; + scn_ptr = RNA_pointer_get(ptr, "scene"); + RNA_string_get(&scn_ptr, "name", scene_name); + + PointerRNA op_ptr; + uiItemFullO( + row, "RENDER_OT_render", "", ICON_RENDER_STILL, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr); + RNA_string_set(&op_ptr, "layer", layer_name); + RNA_string_set(&op_ptr, "scene", scene_name); +} + +void register_node_type_cmp_rlayers() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_R_LAYERS, "Render Layers", NODE_CLASS_INPUT, NODE_PREVIEW); node_type_socket_templates(&ntype, nullptr, cmp_node_rlayers_out); + ntype.draw_buttons = node_composit_buts_viewlayers; ntype.initfunc_api = node_composit_init_rlayers; ntype.poll = node_composit_poll_rlayers; node_type_storage(&ntype, nullptr, node_composit_free_rlayers, node_composit_copy_rlayers); diff --git a/source/blender/nodes/composite/nodes/node_composite_inpaint.cc b/source/blender/nodes/composite/nodes/node_composite_inpaint.cc index d0ff97a2ca0..976b1cd5a15 100644 --- a/source/blender/nodes/composite/nodes/node_composite_inpaint.cc +++ b/source/blender/nodes/composite/nodes/node_composite_inpaint.cc @@ -21,20 +21,35 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* **************** Inpaint/ ******************** */ -static bNodeSocketTemplate cmp_node_inpaint_in[] = { - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, {-1, ""}}; -static bNodeSocketTemplate cmp_node_inpaint_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}}; +namespace blender::nodes { + +static void cmp_node_inpaint_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_output<decl::Color>(N_("Image")); +} + +} // namespace blender::nodes + +static void node_composit_buts_inpaint(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "distance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} -void register_node_type_cmp_inpaint(void) +void register_node_type_cmp_inpaint() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_INPAINT, "Inpaint", NODE_CLASS_OP_FILTER, 0); - node_type_socket_templates(&ntype, cmp_node_inpaint_in, cmp_node_inpaint_out); + ntype.declare = blender::nodes::cmp_node_inpaint_declare; + ntype.draw_buttons = node_composit_buts_inpaint; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_invert.cc b/source/blender/nodes/composite/nodes/node_composite_invert.cc index dabf0452628..2243608d5c3 100644 --- a/source/blender/nodes/composite/nodes/node_composite_invert.cc +++ b/source/blender/nodes/composite/nodes/node_composite_invert.cc @@ -21,6 +21,9 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* **************** INVERT ******************** */ @@ -41,13 +44,23 @@ static void node_composit_init_invert(bNodeTree *UNUSED(ntree), bNode *node) node->custom1 |= CMP_CHAN_RGB; } +static void node_composit_buts_invert(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *col; + + col = uiLayoutColumn(layout, false); + uiItemR(col, ptr, "invert_rgb", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(col, ptr, "invert_alpha", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} + /* custom1 = mix type */ -void register_node_type_cmp_invert(void) +void register_node_type_cmp_invert() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR, 0); ntype.declare = blender::nodes::cmp_node_invert_declare; + ntype.draw_buttons = node_composit_buts_invert; node_type_init(&ntype, node_composit_init_invert); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_keying.cc b/source/blender/nodes/composite/nodes/node_composite_keying.cc index d5547161069..de1da3289f9 100644 --- a/source/blender/nodes/composite/nodes/node_composite_keying.cc +++ b/source/blender/nodes/composite/nodes/node_composite_keying.cc @@ -21,30 +21,33 @@ * \ingroup cmpnodes */ +#include "BLI_math_base.h" + #include "BLT_translation.h" #include "DNA_movieclip_types.h" -#include "BLI_math_base.h" +#include "UI_interface.h" +#include "UI_resources.h" #include "node_composite_util.hh" -/* **************** Translate ******************** */ +/* **************** Keying ******************** */ -static bNodeSocketTemplate cmp_node_keying_in[] = { - {SOCK_RGBA, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, - {SOCK_RGBA, "Key Color", 1.0f, 1.0f, 1.0f, 1.0f}, - {SOCK_FLOAT, "Garbage Matte", 0.0f, 1.0f, 1.0f, 1.0f}, - {SOCK_FLOAT, "Core Matte", 0.0f, 1.0f, 1.0f, 1.0f}, - {-1, ""}, -}; +namespace blender::nodes { + +static void cmp_node_keying_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({0.8f, 0.8f, 0.8f, 1.0f}); + b.add_input<decl::Color>(N_("Key Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Float>(N_("Garbage Matte")).hide_value(); + b.add_input<decl::Float>(N_("Core Matte")).hide_value(); + b.add_output<decl::Color>(N_("Image")); + b.add_output<decl::Float>(N_("Matte")); + b.add_output<decl::Float>(N_("Edges")); +} -static bNodeSocketTemplate cmp_node_keying_out[] = { - {SOCK_RGBA, "Image"}, - {SOCK_FLOAT, "Matte"}, - {SOCK_FLOAT, "Edges"}, - {-1, ""}, -}; +} // namespace blender::nodes static void node_composit_init_keying(bNodeTree *UNUSED(ntree), bNode *node) { @@ -60,12 +63,31 @@ static void node_composit_init_keying(bNodeTree *UNUSED(ntree), bNode *node) node->storage = data; } -void register_node_type_cmp_keying(void) +static void node_composit_buts_keying(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + /* bNode *node = (bNode*)ptr->data; */ /* UNUSED */ + + uiItemR(layout, ptr, "blur_pre", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "screen_balance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "despill_factor", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "despill_balance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "edge_kernel_radius", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "edge_kernel_tolerance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "clip_black", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "clip_white", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "dilate_distance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "feather_falloff", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "feather_distance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "blur_post", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} + +void register_node_type_cmp_keying() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_KEYING, "Keying", NODE_CLASS_MATTE, 0); - node_type_socket_templates(&ntype, cmp_node_keying_in, cmp_node_keying_out); + ntype.declare = blender::nodes::cmp_node_keying_declare; + ntype.draw_buttons = node_composit_buts_keying; node_type_init(&ntype, node_composit_init_keying); node_type_storage( &ntype, "NodeKeyingData", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc b/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc index c976a92b92d..d90fbe05211 100644 --- a/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc +++ b/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc @@ -26,14 +26,23 @@ #include "BLI_math_base.h" #include "BLI_math_color.h" +#include "RNA_access.h" + +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" -/* **************** Translate ******************** */ +/* **************** Keying Screen ******************** */ -static bNodeSocketTemplate cmp_node_keyingscreen_out[] = { - {SOCK_RGBA, "Screen"}, - {-1, ""}, -}; +namespace blender::nodes { + +static void cmp_node_keyingscreen_declare(NodeDeclarationBuilder &b) +{ + b.add_output<decl::Color>(N_("Screen")); +} + +} // namespace blender::nodes static void node_composit_init_keyingscreen(bNodeTree *UNUSED(ntree), bNode *node) { @@ -42,12 +51,40 @@ static void node_composit_init_keyingscreen(bNodeTree *UNUSED(ntree), bNode *nod node->storage = data; } -void register_node_type_cmp_keyingscreen(void) +static void node_composit_buts_keyingscreen(uiLayout *layout, bContext *C, PointerRNA *ptr) +{ + bNode *node = (bNode *)ptr->data; + + uiTemplateID(layout, + C, + ptr, + "clip", + nullptr, + nullptr, + nullptr, + UI_TEMPLATE_ID_FILTER_ALL, + false, + nullptr); + + if (node->id) { + MovieClip *clip = (MovieClip *)node->id; + uiLayout *col; + PointerRNA tracking_ptr; + + RNA_pointer_create(&clip->id, &RNA_MovieTracking, &clip->tracking, &tracking_ptr); + + col = uiLayoutColumn(layout, true); + uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA); + } +} + +void register_node_type_cmp_keyingscreen() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_KEYINGSCREEN, "Keying Screen", NODE_CLASS_MATTE, 0); - node_type_socket_templates(&ntype, nullptr, cmp_node_keyingscreen_out); + ntype.declare = blender::nodes::cmp_node_keyingscreen_declare; + ntype.draw_buttons = node_composit_buts_keyingscreen; node_type_init(&ntype, node_composit_init_keyingscreen); node_type_storage( &ntype, "NodeKeyingScreenData", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_lensdist.cc b/source/blender/nodes/composite/nodes/node_composite_lensdist.cc index 2a8dc035792..11ee0cf0aa3 100644 --- a/source/blender/nodes/composite/nodes/node_composite_lensdist.cc +++ b/source/blender/nodes/composite/nodes/node_composite_lensdist.cc @@ -21,18 +21,24 @@ * \ingroup cmpnodes */ +#include "RNA_access.h" + +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" -static bNodeSocketTemplate cmp_node_lensdist_in[] = { - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {SOCK_FLOAT, N_("Distort"), 0.0f, 0.0f, 0.0f, 0.0f, -0.999f, 1.0f, PROP_NONE}, - {SOCK_FLOAT, N_("Dispersion"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE}, - {-1, ""}, -}; -static bNodeSocketTemplate cmp_node_lensdist_out[] = { - {SOCK_RGBA, N_("Image")}, - {-1, ""}, -}; +namespace blender::nodes { + +static void cmp_node_lensdist_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Float>(N_("Distort")).default_value(0.0f).min(-0.999f).max(1.0f); + b.add_input<decl::Float>(N_("Dispersion")).default_value(0.0f).min(0.0f).max(1.0f); + b.add_output<decl::Color>(N_("Image")); +} + +} // namespace blender::nodes static void node_composit_init_lensdist(bNodeTree *UNUSED(ntree), bNode *node) { @@ -41,12 +47,26 @@ static void node_composit_init_lensdist(bNodeTree *UNUSED(ntree), bNode *node) node->storage = nld; } -void register_node_type_cmp_lensdist(void) +static void node_composit_buts_lensdist(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *col; + + col = uiLayoutColumn(layout, false); + uiItemR(col, ptr, "use_projector", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + col = uiLayoutColumn(col, false); + uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_projector") == false); + uiItemR(col, ptr, "use_jitter", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(col, ptr, "use_fit", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} + +void register_node_type_cmp_lensdist() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_LENSDIST, "Lens Distortion", NODE_CLASS_DISTORT, 0); - node_type_socket_templates(&ntype, cmp_node_lensdist_in, cmp_node_lensdist_out); + ntype.declare = blender::nodes::cmp_node_lensdist_declare; + ntype.draw_buttons = node_composit_buts_lensdist; node_type_init(&ntype, node_composit_init_lensdist); node_type_storage( &ntype, "NodeLensDist", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_levels.cc b/source/blender/nodes/composite/nodes/node_composite_levels.cc index 54064f24e0d..891f79f9bf9 100644 --- a/source/blender/nodes/composite/nodes/node_composite_levels.cc +++ b/source/blender/nodes/composite/nodes/node_composite_levels.cc @@ -21,6 +21,9 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* **************** LEVELS ******************** */ @@ -41,12 +44,18 @@ static void node_composit_init_view_levels(bNodeTree *UNUSED(ntree), bNode *node node->custom1 = 1; /* All channels. */ } -void register_node_type_cmp_view_levels(void) +static void node_composit_buts_view_levels(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "channel", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); +} + +void register_node_type_cmp_view_levels() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_VIEW_LEVELS, "Levels", NODE_CLASS_OUTPUT, NODE_PREVIEW); ntype.declare = blender::nodes::cmp_node_levels_declare; + ntype.draw_buttons = node_composit_buts_view_levels; node_type_init(&ntype, node_composit_init_view_levels); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc b/source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc index 600406d22b9..f5193bd5df2 100644 --- a/source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc +++ b/source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc @@ -21,19 +21,23 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* ******************* Luma Matte Node ********************************* */ -static bNodeSocketTemplate cmp_node_luma_matte_in[] = { - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {-1, ""}, -}; -static bNodeSocketTemplate cmp_node_luma_matte_out[] = { - {SOCK_RGBA, N_("Image")}, - {SOCK_FLOAT, N_("Matte")}, - {-1, ""}, -}; +namespace blender::nodes { + +static void cmp_node_luma_matte_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_output<decl::Color>(N_("Image")); + b.add_output<decl::Float>(N_("Matte")); +} + +} // namespace blender::nodes static void node_composit_init_luma_matte(bNodeTree *UNUSED(ntree), bNode *node) { @@ -43,12 +47,24 @@ static void node_composit_init_luma_matte(bNodeTree *UNUSED(ntree), bNode *node) c->t2 = 0.0f; } -void register_node_type_cmp_luma_matte(void) +static void node_composit_buts_luma_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *col; + + col = uiLayoutColumn(layout, true); + uiItemR( + col, ptr, "limit_max", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); + uiItemR( + col, ptr, "limit_min", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); +} + +void register_node_type_cmp_luma_matte() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_LUMA_MATTE, "Luminance Key", NODE_CLASS_MATTE, NODE_PREVIEW); - node_type_socket_templates(&ntype, cmp_node_luma_matte_in, cmp_node_luma_matte_out); + ntype.declare = blender::nodes::cmp_node_luma_matte_declare; + ntype.draw_buttons = node_composit_buts_luma_matte; node_type_init(&ntype, node_composit_init_luma_matte); node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_mapRange.cc b/source/blender/nodes/composite/nodes/node_composite_mapRange.cc index 808ad538e55..1ae80f68dfd 100644 --- a/source/blender/nodes/composite/nodes/node_composite_mapRange.cc +++ b/source/blender/nodes/composite/nodes/node_composite_mapRange.cc @@ -21,28 +21,42 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" -/* **************** MAP VALUE ******************** */ -static bNodeSocketTemplate cmp_node_map_range_in[] = { - {SOCK_FLOAT, N_("Value"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, - {SOCK_FLOAT, N_("From Min"), 0.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, - {SOCK_FLOAT, N_("From Max"), 1.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, - {SOCK_FLOAT, N_("To Min"), 0.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, - {SOCK_FLOAT, N_("To Max"), 1.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, - {-1, ""}, -}; -static bNodeSocketTemplate cmp_node_map_range_out[] = { - {SOCK_FLOAT, N_("Value")}, - {-1, ""}, -}; - -void register_node_type_cmp_map_range(void) +/* **************** Map Range ******************** */ + +namespace blender::nodes { + +static void cmp_node_map_range_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(1.0f); + b.add_input<decl::Float>(N_("From Min")).default_value(0.0f).min(-10000.0f).max(10000.0f); + b.add_input<decl::Float>(N_("From Max")).default_value(0.0f).min(-10000.0f).max(10000.0f); + b.add_input<decl::Float>(N_("To Min")).default_value(0.0f).min(-10000.0f).max(10000.0f); + b.add_input<decl::Float>(N_("To Max")).default_value(0.0f).min(-10000.0f).max(10000.0f); + b.add_output<decl::Float>(N_("Value")); +} + +} // namespace blender::nodes + +static void node_composit_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *col; + + col = uiLayoutColumn(layout, true); + uiItemR(col, ptr, "use_clamp", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} + +void register_node_type_cmp_map_range() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_MAP_RANGE, "Map Range", NODE_CLASS_OP_VECTOR, 0); - node_type_socket_templates(&ntype, cmp_node_map_range_in, cmp_node_map_range_out); + ntype.declare = blender::nodes::cmp_node_map_range_declare; + ntype.draw_buttons = node_composit_buts_map_range; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_mapUV.cc b/source/blender/nodes/composite/nodes/node_composite_mapUV.cc index 99032bd042e..71446e3a3c4 100644 --- a/source/blender/nodes/composite/nodes/node_composite_mapUV.cc +++ b/source/blender/nodes/composite/nodes/node_composite_mapUV.cc @@ -21,26 +21,36 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* **************** Map UV ******************** */ -static bNodeSocketTemplate cmp_node_mapuv_in[] = { - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {SOCK_VECTOR, N_("UV"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE}, - {-1, ""}, -}; -static bNodeSocketTemplate cmp_node_mapuv_out[] = { - {SOCK_RGBA, N_("Image")}, - {-1, ""}, -}; - -void register_node_type_cmp_mapuv(void) +namespace blender::nodes { + +static void cmp_node_map_uv_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Vector>(N_("UV")).default_value({1.0f, 0.0f, 0.0f}).min(0.0f).max(1.0f); + b.add_output<decl::Color>(N_("Image")); +} + +} // namespace blender::nodes + +static void node_composit_buts_map_uv(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "alpha", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} + +void register_node_type_cmp_mapuv() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_MAP_UV, "Map UV", NODE_CLASS_DISTORT, 0); - node_type_socket_templates(&ntype, cmp_node_mapuv_in, cmp_node_mapuv_out); + ntype.declare = blender::nodes::cmp_node_map_uv_declare; + ntype.draw_buttons = node_composit_buts_map_uv; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_mapValue.cc b/source/blender/nodes/composite/nodes/node_composite_mapValue.cc index 25c00c2ba13..4bd9124fa68 100644 --- a/source/blender/nodes/composite/nodes/node_composite_mapValue.cc +++ b/source/blender/nodes/composite/nodes/node_composite_mapValue.cc @@ -21,29 +21,58 @@ * \ingroup cmpnodes */ +#include "RNA_access.h" + +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* **************** MAP VALUE ******************** */ -static bNodeSocketTemplate cmp_node_map_value_in[] = { - {SOCK_FLOAT, N_("Value"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, - {-1, ""}, -}; -static bNodeSocketTemplate cmp_node_map_value_out[] = { - {SOCK_FLOAT, N_("Value")}, - {-1, ""}, -}; + +namespace blender::nodes { + +static void cmp_node_map_value_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(1.0f); + b.add_output<decl::Float>(N_("Value")); +} + +} // namespace blender::nodes static void node_composit_init_map_value(bNodeTree *UNUSED(ntree), bNode *node) { node->storage = BKE_texture_mapping_add(TEXMAP_TYPE_POINT); } -void register_node_type_cmp_map_value(void) +static void node_composit_buts_map_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *sub, *col; + + col = uiLayoutColumn(layout, true); + uiItemR(col, ptr, "offset", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(col, ptr, "size", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + col = uiLayoutColumn(layout, true); + uiItemR(col, ptr, "use_min", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + sub = uiLayoutColumn(col, false); + uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min")); + uiItemR(sub, ptr, "min", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); + + col = uiLayoutColumn(layout, true); + uiItemR(col, ptr, "use_max", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + sub = uiLayoutColumn(col, false); + uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max")); + uiItemR(sub, ptr, "max", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); +} + +void register_node_type_cmp_map_value() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_MAP_VALUE, "Map Value", NODE_CLASS_OP_VECTOR, 0); - node_type_socket_templates(&ntype, cmp_node_map_value_in, cmp_node_map_value_out); + ntype.declare = blender::nodes::cmp_node_map_value_declare; + ntype.draw_buttons = node_composit_buts_map_value; node_type_init(&ntype, node_composit_init_map_value); node_type_storage(&ntype, "TexMapping", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_mask.cc b/source/blender/nodes/composite/nodes/node_composite_mask.cc index 6428fadaa5f..8cbf526a289 100644 --- a/source/blender/nodes/composite/nodes/node_composite_mask.cc +++ b/source/blender/nodes/composite/nodes/node_composite_mask.cc @@ -23,6 +23,9 @@ #include "DNA_mask_types.h" +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* **************** Mask ******************** */ @@ -46,7 +49,10 @@ static void node_composit_init_mask(bNodeTree *UNUSED(ntree), bNode *node) node->custom3 = 0.5f; /* shutter */ } -static void node_mask_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen) +static void node_mask_label(const bNodeTree *UNUSED(ntree), + const bNode *node, + char *label, + int maxlen) { if (node->id != nullptr) { BLI_strncpy(label, node->id->name + 2, maxlen); @@ -56,14 +62,45 @@ static void node_mask_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, } } -void register_node_type_cmp_mask(void) +static void node_composit_buts_mask(uiLayout *layout, bContext *C, PointerRNA *ptr) +{ + bNode *node = (bNode *)ptr->data; + + uiTemplateID(layout, + C, + ptr, + "mask", + nullptr, + nullptr, + nullptr, + UI_TEMPLATE_ID_FILTER_ALL, + false, + nullptr); + uiItemR(layout, ptr, "use_feather", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + uiItemR(layout, ptr, "size_source", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); + + if (node->custom1 & (CMP_NODEFLAG_MASK_FIXED | CMP_NODEFLAG_MASK_FIXED_SCENE)) { + uiItemR(layout, ptr, "size_x", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "size_y", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + } + + uiItemR(layout, ptr, "use_motion_blur", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + if (node->custom1 & CMP_NODEFLAG_MASK_MOTION_BLUR) { + uiItemR(layout, ptr, "motion_blur_samples", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "motion_blur_shutter", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + } +} + +void register_node_type_cmp_mask() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_MASK, "Mask", NODE_CLASS_INPUT, 0); ntype.declare = blender::nodes::cmp_node_mask_declare; + ntype.draw_buttons = node_composit_buts_mask; node_type_init(&ntype, node_composit_init_mask); - node_type_label(&ntype, node_mask_label); + ntype.labelfunc = node_mask_label; node_type_storage(&ntype, "NodeMask", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_math.cc b/source/blender/nodes/composite/nodes/node_composite_math.cc index ecddcc2ad32..b34cfab5eb5 100644 --- a/source/blender/nodes/composite/nodes/node_composite_math.cc +++ b/source/blender/nodes/composite/nodes/node_composite_math.cc @@ -24,21 +24,32 @@ #include "node_composite_util.hh" /* **************** SCALAR MATH ******************** */ -static bNodeSocketTemplate cmp_node_math_in[] = { - {SOCK_FLOAT, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, - {SOCK_FLOAT, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, - {SOCK_FLOAT, N_("Value"), 0.0f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, - {-1, ""}}; -static bNodeSocketTemplate cmp_node_math_out[] = {{SOCK_FLOAT, N_("Value")}, {-1, ""}}; +namespace blender::nodes { -void register_node_type_cmp_math(void) +static void cmp_node_math_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Float>(N_("Value")).default_value(0.5f).min(-10000.0f).max(10000.0f); + b.add_input<decl::Float>(N_("Value"), "Value_001") + .default_value(0.5f) + .min(-10000.0f) + .max(10000.0f); + b.add_input<decl::Float>(N_("Value"), "Value_002") + .default_value(0.5f) + .min(-10000.0f) + .max(10000.0f); + b.add_output<decl::Float>(N_("Value")); +} + +} // namespace blender::nodes + +void register_node_type_cmp_math() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_MATH, "Math", NODE_CLASS_CONVERTER, 0); - node_type_socket_templates(&ntype, cmp_node_math_in, cmp_node_math_out); - node_type_label(&ntype, node_math_label); + ntype.declare = blender::nodes::cmp_node_math_declare; + ntype.labelfunc = node_math_label; node_type_update(&ntype, node_math_update); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc b/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc index 557116f5b7a..4432b031ee7 100644 --- a/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc +++ b/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc @@ -25,25 +25,26 @@ /* **************** MIX RGB ******************** */ -static bNodeSocketTemplate cmp_node_mix_rgb_in[] = { - {SOCK_FLOAT, N_("Fac"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {-1, ""}, -}; -static bNodeSocketTemplate cmp_node_mix_rgb_out[] = { - {SOCK_RGBA, N_("Image")}, - {-1, ""}, -}; +namespace blender::nodes { + +static void cmp_node_mixrgb_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR); + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Color>(N_("Image"), "Image_001").default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_output<decl::Color>(N_("Image")); +} + +} // namespace blender::nodes /* custom1 = mix type */ -void register_node_type_cmp_mix_rgb(void) +void register_node_type_cmp_mix_rgb() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, NODE_PREVIEW); - node_type_socket_templates(&ntype, cmp_node_mix_rgb_in, cmp_node_mix_rgb_out); - node_type_label(&ntype, node_blend_label); + ntype.declare = blender::nodes::cmp_node_mixrgb_declare; + ntype.labelfunc = node_blend_label; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_movieclip.cc b/source/blender/nodes/composite/nodes/node_composite_movieclip.cc index 5d63a1b8002..47a2c89a2f9 100644 --- a/source/blender/nodes/composite/nodes/node_composite_movieclip.cc +++ b/source/blender/nodes/composite/nodes/node_composite_movieclip.cc @@ -21,11 +21,16 @@ * \ingroup cmpnodes */ -#include "node_composite_util.hh" - #include "BKE_context.h" #include "BKE_lib_id.h" +#include "RNA_access.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "node_composite_util.hh" + namespace blender::nodes { static void cmp_node_movieclip_declare(NodeDeclarationBuilder &b) @@ -53,12 +58,53 @@ static void init(const bContext *C, PointerRNA *ptr) user->framenr = 1; } -void register_node_type_cmp_movieclip(void) +static void node_composit_buts_movieclip(uiLayout *layout, bContext *C, PointerRNA *ptr) +{ + uiTemplateID(layout, + C, + ptr, + "clip", + nullptr, + "CLIP_OT_open", + nullptr, + UI_TEMPLATE_ID_FILTER_ALL, + false, + nullptr); +} + +static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, PointerRNA *ptr) +{ + bNode *node = (bNode *)ptr->data; + PointerRNA clipptr; + + uiTemplateID(layout, + C, + ptr, + "clip", + nullptr, + "CLIP_OT_open", + nullptr, + UI_TEMPLATE_ID_FILTER_ALL, + false, + nullptr); + + if (!node->id) { + return; + } + + clipptr = RNA_pointer_get(ptr, "clip"); + + uiTemplateColorspaceSettings(layout, &clipptr, "colorspace_settings"); +} + +void register_node_type_cmp_movieclip() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_MOVIECLIP, "Movie Clip", NODE_CLASS_INPUT, NODE_PREVIEW); ntype.declare = blender::nodes::cmp_node_movieclip_declare; + ntype.draw_buttons = node_composit_buts_movieclip; + ntype.draw_buttons_ex = node_composit_buts_movieclip_ex; ntype.initfunc_api = init; node_type_storage( &ntype, "MovieClipUser", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc b/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc index 2bac30cc152..e7d9cac7c1a 100644 --- a/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc +++ b/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc @@ -21,24 +21,27 @@ * \ingroup cmpnodes */ -#include "node_composite_util.hh" - #include "BKE_context.h" #include "BKE_lib_id.h" +#include "UI_interface.h" +#include "UI_resources.h" + +#include "node_composite_util.hh" + /* **************** Translate ******************** */ -static bNodeSocketTemplate cmp_node_moviedistortion_in[] = { - {SOCK_RGBA, N_("Image"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, - {-1, ""}, -}; +namespace blender::nodes { + +static void cmp_node_moviedistortion_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({0.8f, 0.8f, 0.8f, 1.0f}); + b.add_output<decl::Color>(N_("Image")); +} -static bNodeSocketTemplate cmp_node_moviedistortion_out[] = { - {SOCK_RGBA, N_("Image")}, - {-1, ""}, -}; +} // namespace blender::nodes -static void label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen) +static void label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen) { if (node->custom1 == 0) { BLI_strncpy(label, IFACE_("Undistortion"), maxlen); @@ -73,14 +76,36 @@ static void storage_copy(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const } } -void register_node_type_cmp_moviedistortion(void) +static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, PointerRNA *ptr) +{ + bNode *node = (bNode *)ptr->data; + + uiTemplateID(layout, + C, + ptr, + "clip", + nullptr, + "CLIP_OT_open", + nullptr, + UI_TEMPLATE_ID_FILTER_ALL, + false, + nullptr); + + if (!node->id) { + return; + } + + uiItemR(layout, ptr, "distortion_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); +} + +void register_node_type_cmp_moviedistortion() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_MOVIEDISTORTION, "Movie Distortion", NODE_CLASS_DISTORT, 0); - node_type_socket_templates(&ntype, cmp_node_moviedistortion_in, cmp_node_moviedistortion_out); - node_type_label(&ntype, label); - + ntype.declare = blender::nodes::cmp_node_moviedistortion_declare; + ntype.draw_buttons = node_composit_buts_moviedistortion; + ntype.labelfunc = label; ntype.initfunc_api = init; node_type_storage(&ntype, nullptr, storage_free, storage_copy); diff --git a/source/blender/nodes/composite/nodes/node_composite_normal.cc b/source/blender/nodes/composite/nodes/node_composite_normal.cc index 7531025daa5..b541761a8cc 100644 --- a/source/blender/nodes/composite/nodes/node_composite_normal.cc +++ b/source/blender/nodes/composite/nodes/node_composite_normal.cc @@ -24,23 +24,28 @@ #include "node_composite_util.hh" /* **************** NORMAL ******************** */ -static bNodeSocketTemplate cmp_node_normal_in[] = { - {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, PROP_DIRECTION}, - {-1, ""}, -}; - -static bNodeSocketTemplate cmp_node_normal_out[] = { - {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, PROP_DIRECTION}, - {SOCK_FLOAT, N_("Dot")}, - {-1, ""}, -}; - -void register_node_type_cmp_normal(void) + +namespace blender::nodes { + +static void cmp_node_normal_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Vector>(N_("Normal")) + .default_value({1.0f, 1.0f, 1.0f}) + .min(-1.0f) + .max(1.0f) + .subtype(PROP_DIRECTION); + b.add_output<decl::Vector>(N_("Normal")); + b.add_output<decl::Float>(N_("Dot")); +} + +} // namespace blender::nodes + +void register_node_type_cmp_normal() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_NORMAL, "Normal", NODE_CLASS_OP_VECTOR, 0); - node_type_socket_templates(&ntype, cmp_node_normal_in, cmp_node_normal_out); + ntype.declare = blender::nodes::cmp_node_normal_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_normalize.cc b/source/blender/nodes/composite/nodes/node_composite_normalize.cc index 7cc54e4eed6..dd3939fa6e2 100644 --- a/source/blender/nodes/composite/nodes/node_composite_normalize.cc +++ b/source/blender/nodes/composite/nodes/node_composite_normalize.cc @@ -24,16 +24,23 @@ #include "node_composite_util.hh" /* **************** NORMALIZE single channel, useful for Z buffer ******************** */ -static bNodeSocketTemplate cmp_node_normalize_in[] = { - {SOCK_FLOAT, N_("Value"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, {-1, ""}}; -static bNodeSocketTemplate cmp_node_normalize_out[] = {{SOCK_FLOAT, N_("Value")}, {-1, ""}}; -void register_node_type_cmp_normalize(void) +namespace blender::nodes { + +static void cmp_node_normalize_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(1.0f); + b.add_output<decl::Float>(N_("Value")); +} + +} // namespace blender::nodes + +void register_node_type_cmp_normalize() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_NORMALIZE, "Normalize", NODE_CLASS_OP_VECTOR, 0); - node_type_socket_templates(&ntype, cmp_node_normalize_in, cmp_node_normalize_out); + ntype.declare = blender::nodes::cmp_node_normalize_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_outputFile.cc b/source/blender/nodes/composite/nodes/node_composite_outputFile.cc index a372d2f7419..79074375a23 100644 --- a/source/blender/nodes/composite/nodes/node_composite_outputFile.cc +++ b/source/blender/nodes/composite/nodes/node_composite_outputFile.cc @@ -21,14 +21,21 @@ * \ingroup cmpnodes */ +#include <cstring> + +#include "BLI_string_utf8.h" #include "BLI_string_utils.h" #include "BLI_utildefines.h" -#include <cstring> #include "BKE_context.h" #include "RNA_access.h" +#include "UI_interface.h" +#include "UI_resources.h" + +#include "WM_api.h" + #include "node_composite_util.hh" #include "intern/openexr/openexr_multi.h" @@ -275,12 +282,169 @@ static void update_output_file(bNodeTree *ntree, bNode *node) } } -void register_node_type_cmp_output_file(void) +static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + PointerRNA imfptr = RNA_pointer_get(ptr, "format"); + const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER; + + if (multilayer) { + uiItemL(layout, IFACE_("Path:"), ICON_NONE); + } + else { + uiItemL(layout, IFACE_("Base Path:"), ICON_NONE); + } + uiItemR(layout, ptr, "base_path", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); +} + +static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, PointerRNA *ptr) +{ + Scene *scene = CTX_data_scene(C); + PointerRNA imfptr = RNA_pointer_get(ptr, "format"); + PointerRNA active_input_ptr, op_ptr; + uiLayout *row, *col; + const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER; + const bool is_exr = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_OPENEXR; + const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0; + + node_composit_buts_file_output(layout, C, ptr); + uiTemplateImageSettings(layout, &imfptr, false); + + /* disable stereo output for multilayer, too much work for something that no one will use */ + /* if someone asks for that we can implement it */ + if (is_multiview) { + uiTemplateImageFormatViews(layout, &imfptr, nullptr); + } + + uiItemS(layout); + + uiItemO(layout, IFACE_("Add Input"), ICON_ADD, "NODE_OT_output_file_add_socket"); + + row = uiLayoutRow(layout, false); + col = uiLayoutColumn(row, true); + + const int active_index = RNA_int_get(ptr, "active_input_index"); + /* using different collection properties if multilayer format is enabled */ + if (multilayer) { + uiTemplateList(col, + C, + "UI_UL_list", + "file_output_node", + ptr, + "layer_slots", + ptr, + "active_input_index", + nullptr, + 0, + 0, + 0, + 0, + UI_TEMPLATE_LIST_FLAG_NONE); + RNA_property_collection_lookup_int( + ptr, RNA_struct_find_property(ptr, "layer_slots"), active_index, &active_input_ptr); + } + else { + uiTemplateList(col, + C, + "UI_UL_list", + "file_output_node", + ptr, + "file_slots", + ptr, + "active_input_index", + nullptr, + 0, + 0, + 0, + 0, + UI_TEMPLATE_LIST_FLAG_NONE); + RNA_property_collection_lookup_int( + ptr, RNA_struct_find_property(ptr, "file_slots"), active_index, &active_input_ptr); + } + /* XXX collection lookup does not return the ID part of the pointer, + * setting this manually here */ + active_input_ptr.owner_id = ptr->owner_id; + + col = uiLayoutColumn(row, true); + wmOperatorType *ot = WM_operatortype_find("NODE_OT_output_file_move_active_socket", false); + uiItemFullO_ptr(col, ot, "", ICON_TRIA_UP, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr); + RNA_enum_set(&op_ptr, "direction", 1); + uiItemFullO_ptr(col, ot, "", ICON_TRIA_DOWN, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr); + RNA_enum_set(&op_ptr, "direction", 2); + + if (active_input_ptr.data) { + if (multilayer) { + col = uiLayoutColumn(layout, true); + + uiItemL(col, IFACE_("Layer:"), ICON_NONE); + row = uiLayoutRow(col, false); + uiItemR(row, &active_input_ptr, "name", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); + uiItemFullO(row, + "NODE_OT_output_file_remove_active_socket", + "", + ICON_X, + nullptr, + WM_OP_EXEC_DEFAULT, + UI_ITEM_R_ICON_ONLY, + nullptr); + } + else { + col = uiLayoutColumn(layout, true); + + uiItemL(col, IFACE_("File Subpath:"), ICON_NONE); + row = uiLayoutRow(col, false); + uiItemR(row, &active_input_ptr, "path", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); + uiItemFullO(row, + "NODE_OT_output_file_remove_active_socket", + "", + ICON_X, + nullptr, + WM_OP_EXEC_DEFAULT, + UI_ITEM_R_ICON_ONLY, + nullptr); + + /* format details for individual files */ + imfptr = RNA_pointer_get(&active_input_ptr, "format"); + + col = uiLayoutColumn(layout, true); + uiItemL(col, IFACE_("Format:"), ICON_NONE); + uiItemR(col, + &active_input_ptr, + "use_node_format", + UI_ITEM_R_SPLIT_EMPTY_NAME, + nullptr, + ICON_NONE); + + const bool is_socket_exr = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_OPENEXR; + const bool use_node_format = RNA_boolean_get(&active_input_ptr, "use_node_format"); + + if ((!is_exr && use_node_format) || (!is_socket_exr && !use_node_format)) { + uiItemR(col, + &active_input_ptr, + "save_as_render", + UI_ITEM_R_SPLIT_EMPTY_NAME, + nullptr, + ICON_NONE); + } + + col = uiLayoutColumn(layout, false); + uiLayoutSetActive(col, use_node_format == false); + uiTemplateImageSettings(col, &imfptr, false); + + if (is_multiview) { + uiTemplateImageFormatViews(layout, &imfptr, nullptr); + } + } + } +} + +void register_node_type_cmp_output_file() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_OUTPUT_FILE, "File Output", NODE_CLASS_OUTPUT, NODE_PREVIEW); node_type_socket_templates(&ntype, nullptr, nullptr); + ntype.draw_buttons = node_composit_buts_file_output; + ntype.draw_buttons_ex = node_composit_buts_file_output_ex; ntype.initfunc_api = init_output_file; node_type_storage(&ntype, "NodeImageMultiFile", free_output_file, copy_output_file); node_type_update(&ntype, update_output_file); diff --git a/source/blender/nodes/composite/nodes/node_composite_pixelate.cc b/source/blender/nodes/composite/nodes/node_composite_pixelate.cc index 19975c21a0b..3679aada759 100644 --- a/source/blender/nodes/composite/nodes/node_composite_pixelate.cc +++ b/source/blender/nodes/composite/nodes/node_composite_pixelate.cc @@ -25,16 +25,22 @@ /* **************** Pixelate ******************** */ -static bNodeSocketTemplate cmp_node_pixelate_in[] = { - {SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, {-1, ""}}; -static bNodeSocketTemplate cmp_node_pixelate_out[] = {{SOCK_RGBA, N_("Color")}, {-1, ""}}; +namespace blender::nodes { -void register_node_type_cmp_pixelate(void) +static void cmp_node_pixelate_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Color")); + b.add_output<decl::Color>(N_("Color")); +} + +} // namespace blender::nodes + +void register_node_type_cmp_pixelate() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_PIXELATE, "Pixelate", NODE_CLASS_OP_FILTER, 0); - node_type_socket_templates(&ntype, cmp_node_pixelate_in, cmp_node_pixelate_out); + ntype.declare = blender::nodes::cmp_node_pixelate_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc b/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc index e122b710b7b..d9d362f5175 100644 --- a/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc +++ b/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc @@ -21,16 +21,23 @@ * \ingroup cmpnodes */ +#include "RNA_access.h" + +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" -static bNodeSocketTemplate cmp_node_planetrackdeform_in[] = { - {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, {-1, ""}}; +namespace blender::nodes { + +static void cmp_node_planetrackdeform_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")); + b.add_output<decl::Color>(N_("Image")); + b.add_output<decl::Float>(N_("Plane")); +} -static bNodeSocketTemplate cmp_node_planetrackdeform_out[] = { - {SOCK_RGBA, N_("Image")}, - {SOCK_FLOAT, N_("Plane")}, - {-1, ""}, -}; +} // namespace blender::nodes static void init(bNodeTree *UNUSED(ntree), bNode *node) { @@ -41,13 +48,63 @@ static void init(bNodeTree *UNUSED(ntree), bNode *node) node->storage = data; } -void register_node_type_cmp_planetrackdeform(void) +static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, PointerRNA *ptr) +{ + bNode *node = (bNode *)ptr->data; + NodePlaneTrackDeformData *data = (NodePlaneTrackDeformData *)node->storage; + + uiTemplateID(layout, + C, + ptr, + "clip", + nullptr, + "CLIP_OT_open", + nullptr, + UI_TEMPLATE_ID_FILTER_ALL, + false, + nullptr); + + if (node->id) { + MovieClip *clip = (MovieClip *)node->id; + MovieTracking *tracking = &clip->tracking; + MovieTrackingObject *object; + uiLayout *col; + PointerRNA tracking_ptr; + + RNA_pointer_create(&clip->id, &RNA_MovieTracking, tracking, &tracking_ptr); + + col = uiLayoutColumn(layout, false); + uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA); + + object = BKE_tracking_object_get_named(tracking, data->tracking_object); + if (object) { + PointerRNA object_ptr; + + RNA_pointer_create(&clip->id, &RNA_MovieTrackingObject, object, &object_ptr); + + uiItemPointerR( + col, ptr, "plane_track_name", &object_ptr, "plane_tracks", "", ICON_ANIM_DATA); + } + else { + uiItemR(layout, ptr, "plane_track_name", 0, "", ICON_ANIM_DATA); + } + } + + uiItemR(layout, ptr, "use_motion_blur", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) { + uiItemR(layout, ptr, "motion_blur_samples", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "motion_blur_shutter", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + } +} + +void register_node_type_cmp_planetrackdeform() { static bNodeType ntype; cmp_node_type_base( &ntype, CMP_NODE_PLANETRACKDEFORM, "Plane Track Deform", NODE_CLASS_DISTORT, 0); - node_type_socket_templates(&ntype, cmp_node_planetrackdeform_in, cmp_node_planetrackdeform_out); + ntype.declare = blender::nodes::cmp_node_planetrackdeform_declare; + ntype.draw_buttons = node_composit_buts_planetrackdeform; node_type_init(&ntype, init); node_type_storage( &ntype, "NodePlaneTrackDeformData", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_posterize.cc b/source/blender/nodes/composite/nodes/node_composite_posterize.cc index 45a98e68b4b..8437c72e76c 100644 --- a/source/blender/nodes/composite/nodes/node_composite_posterize.cc +++ b/source/blender/nodes/composite/nodes/node_composite_posterize.cc @@ -25,22 +25,23 @@ /* **************** Posterize ******************** */ -static bNodeSocketTemplate cmp_node_posterize_in[] = { - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {SOCK_FLOAT, N_("Steps"), 8.0f, 8.0f, 8.0f, 8.0f, 2.0f, 1024.0f, PROP_NONE}, - {-1, ""}, -}; -static bNodeSocketTemplate cmp_node_posterize_out[] = { - {SOCK_RGBA, N_("Image")}, - {-1, ""}, -}; - -void register_node_type_cmp_posterize(void) +namespace blender::nodes { + +static void cmp_node_posterize_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Float>(N_("Steps")).default_value(8.0f).min(2.0f).max(1024.0f); + b.add_output<decl::Color>(N_("Image")); +} + +} // namespace blender::nodes + +void register_node_type_cmp_posterize() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_POSTERIZE, "Posterize", NODE_CLASS_OP_COLOR, 0); - node_type_socket_templates(&ntype, cmp_node_posterize_in, cmp_node_posterize_out); + ntype.declare = blender::nodes::cmp_node_posterize_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_premulkey.cc b/source/blender/nodes/composite/nodes/node_composite_premulkey.cc index 49068429a8d..a70adf68692 100644 --- a/source/blender/nodes/composite/nodes/node_composite_premulkey.cc +++ b/source/blender/nodes/composite/nodes/node_composite_premulkey.cc @@ -21,6 +21,9 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* **************** Premul and Key Alpha Convert ******************** */ @@ -35,12 +38,18 @@ static void cmp_node_premulkey_declare(NodeDeclarationBuilder &b) } // namespace blender::nodes -void register_node_type_cmp_premulkey(void) +static void node_composit_buts_premulkey(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "mapping", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); +} + +void register_node_type_cmp_premulkey() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_PREMULKEY, "Alpha Convert", NODE_CLASS_CONVERTER, 0); ntype.declare = blender::nodes::cmp_node_premulkey_declare; + ntype.draw_buttons = node_composit_buts_premulkey; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_rgb.cc b/source/blender/nodes/composite/nodes/node_composite_rgb.cc index abe69d6a756..54f152d1cd0 100644 --- a/source/blender/nodes/composite/nodes/node_composite_rgb.cc +++ b/source/blender/nodes/composite/nodes/node_composite_rgb.cc @@ -34,7 +34,7 @@ static void cmp_node_rgb_declare(NodeDeclarationBuilder &b) } // namespace blender::nodes -void register_node_type_cmp_rgb(void) +void register_node_type_cmp_rgb() { static bNodeType ntype; diff --git a/source/blender/nodes/composite/nodes/node_composite_rotate.cc b/source/blender/nodes/composite/nodes/node_composite_rotate.cc index d28b35ec9fb..cc1589a47ca 100644 --- a/source/blender/nodes/composite/nodes/node_composite_rotate.cc +++ b/source/blender/nodes/composite/nodes/node_composite_rotate.cc @@ -21,31 +21,45 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* **************** Rotate ******************** */ -static bNodeSocketTemplate cmp_node_rotate_in[] = { - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {SOCK_FLOAT, N_("Degr"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f, PROP_ANGLE}, - {-1, ""}, -}; -static bNodeSocketTemplate cmp_node_rotate_out[] = { - {SOCK_RGBA, N_("Image")}, - {-1, ""}, -}; +namespace blender::nodes { + +static void cmp_node_rotate_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Float>(N_("Degr")) + .default_value(0.0f) + .min(-10000.0f) + .max(10000.0f) + .subtype(PROP_ANGLE); + b.add_output<decl::Color>(N_("Image")); +} + +} // namespace blender::nodes static void node_composit_init_rotate(bNodeTree *UNUSED(ntree), bNode *node) { node->custom1 = 1; /* Bilinear Filter. */ } -void register_node_type_cmp_rotate(void) +static void node_composit_buts_rotate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "filter_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); +} + +void register_node_type_cmp_rotate() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_ROTATE, "Rotate", NODE_CLASS_DISTORT, 0); - node_type_socket_templates(&ntype, cmp_node_rotate_in, cmp_node_rotate_out); + ntype.declare = blender::nodes::cmp_node_rotate_declare; + ntype.draw_buttons = node_composit_buts_rotate; node_type_init(&ntype, node_composit_init_rotate); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_scale.cc b/source/blender/nodes/composite/nodes/node_composite_scale.cc index 284d16b9b0d..98c9f6619f4 100644 --- a/source/blender/nodes/composite/nodes/node_composite_scale.cc +++ b/source/blender/nodes/composite/nodes/node_composite_scale.cc @@ -21,16 +21,26 @@ * \ingroup cmpnodes */ +#include "RNA_access.h" + +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* **************** Scale ******************** */ -static bNodeSocketTemplate cmp_node_scale_in[] = { - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {SOCK_FLOAT, N_("X"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0001f, CMP_SCALE_MAX, PROP_NONE}, - {SOCK_FLOAT, N_("Y"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0001f, CMP_SCALE_MAX, PROP_NONE}, - {-1, ""}}; -static bNodeSocketTemplate cmp_node_scale_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}}; +namespace blender::nodes { + +static void cmp_node_scale_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Float>(N_("X")).default_value(1.0f).min(0.0001f).max(CMP_SCALE_MAX); + b.add_input<decl::Float>(N_("Y")).default_value(1.0f).min(0.0001f).max(CMP_SCALE_MAX); + b.add_output<decl::Color>(N_("Image")); +} + +} // namespace blender::nodes static void node_composite_update_scale(bNodeTree *ntree, bNode *node) { @@ -45,12 +55,31 @@ static void node_composite_update_scale(bNodeTree *ntree, bNode *node) } } -void register_node_type_cmp_scale(void) +static void node_composit_buts_scale(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "space", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); + + if (RNA_enum_get(ptr, "space") == CMP_SCALE_RENDERPERCENT) { + uiLayout *row; + uiItemR(layout, + ptr, + "frame_method", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, + nullptr, + ICON_NONE); + row = uiLayoutRow(layout, true); + uiItemR(row, ptr, "offset_x", UI_ITEM_R_SPLIT_EMPTY_NAME, "X", ICON_NONE); + uiItemR(row, ptr, "offset_y", UI_ITEM_R_SPLIT_EMPTY_NAME, "Y", ICON_NONE); + } +} + +void register_node_type_cmp_scale() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_SCALE, "Scale", NODE_CLASS_DISTORT, 0); - node_type_socket_templates(&ntype, cmp_node_scale_in, cmp_node_scale_out); + ntype.declare = blender::nodes::cmp_node_scale_declare; + ntype.draw_buttons = node_composit_buts_scale; node_type_update(&ntype, node_composite_update_scale); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc index 83c54069658..9eafc0e3594 100644 --- a/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc +++ b/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc @@ -38,7 +38,7 @@ static void cmp_node_sephsva_declare(NodeDeclarationBuilder &b) } // namespace blender::nodes -void register_node_type_cmp_sephsva(void) +void register_node_type_cmp_sephsva() { static bNodeType ntype; @@ -62,7 +62,7 @@ static void cmp_node_combhsva_declare(NodeDeclarationBuilder &b) } // namespace blender::nodes -void register_node_type_cmp_combhsva(void) +void register_node_type_cmp_combhsva() { static bNodeType ntype; diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc index 049e798af0a..e81ea6f31be 100644 --- a/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc +++ b/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc @@ -37,7 +37,7 @@ static void cmp_node_seprgba_declare(NodeDeclarationBuilder &b) } // namespace blender::nodes -void register_node_type_cmp_seprgba(void) +void register_node_type_cmp_seprgba() { static bNodeType ntype; @@ -62,7 +62,7 @@ static void cmp_node_combrgba_declare(NodeDeclarationBuilder &b) } // namespace blender::nodes -void register_node_type_cmp_combrgba(void) +void register_node_type_cmp_combrgba() { static bNodeType ntype; diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc index eaf6ba5e9b2..15c8efc2ef8 100644 --- a/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc +++ b/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc @@ -43,7 +43,7 @@ static void node_composit_init_mode_sepycca(bNodeTree *UNUSED(ntree), bNode *nod node->custom1 = 1; /* BLI_YCC_ITU_BT709 */ } -void register_node_type_cmp_sepycca(void) +void register_node_type_cmp_sepycca() { static bNodeType ntype; @@ -74,7 +74,7 @@ static void node_composit_init_mode_combycca(bNodeTree *UNUSED(ntree), bNode *no node->custom1 = 1; /* BLI_YCC_ITU_BT709 */ } -void register_node_type_cmp_combycca(void) +void register_node_type_cmp_combycca() { static bNodeType ntype; diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc index bc7710122d1..4d4b01c2fb3 100644 --- a/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc +++ b/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc @@ -38,7 +38,7 @@ static void cmp_node_sepyuva_declare(NodeDeclarationBuilder &b) } // namespace blender::nodes -void register_node_type_cmp_sepyuva(void) +void register_node_type_cmp_sepyuva() { static bNodeType ntype; @@ -63,7 +63,7 @@ static void cmp_node_combyuva_declare(NodeDeclarationBuilder &b) } // namespace blender::nodes -void register_node_type_cmp_combyuva(void) +void register_node_type_cmp_combyuva() { static bNodeType ntype; diff --git a/source/blender/nodes/composite/nodes/node_composite_setalpha.cc b/source/blender/nodes/composite/nodes/node_composite_setalpha.cc index f59ba76f0c5..3e66f884efd 100644 --- a/source/blender/nodes/composite/nodes/node_composite_setalpha.cc +++ b/source/blender/nodes/composite/nodes/node_composite_setalpha.cc @@ -21,6 +21,9 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* **************** SET ALPHA ******************** */ @@ -43,12 +46,18 @@ static void node_composit_init_setalpha(bNodeTree *UNUSED(ntree), bNode *node) settings->mode = CMP_NODE_SETALPHA_MODE_APPLY; } -void register_node_type_cmp_setalpha(void) +static void node_composit_buts_set_alpha(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "mode", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} + +void register_node_type_cmp_setalpha() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_SETALPHA, "Set Alpha", NODE_CLASS_CONVERTER, 0); ntype.declare = blender::nodes::cmp_node_setalpha_declare; + ntype.draw_buttons = node_composit_buts_set_alpha; node_type_init(&ntype, node_composit_init_setalpha); node_type_storage( &ntype, "NodeSetAlpha", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc b/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc index c0403a041db..63772a52840 100644 --- a/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc +++ b/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc @@ -21,17 +21,25 @@ * \ingroup cmpnodes */ -#include "node_composite_util.hh" - #include "BKE_global.h" #include "BKE_image.h" +#include "UI_interface.h" +#include "UI_resources.h" + +#include "node_composite_util.hh" + /* **************** SPLIT VIEWER ******************** */ -static bNodeSocketTemplate cmp_node_splitviewer_in[] = { - {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f}, - {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f}, - {-1, ""}, -}; + +namespace blender::nodes { + +static void cmp_node_split_viewer_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")); + b.add_input<decl::Color>(N_("Image"), "Image_001"); +} + +} // namespace blender::nodes static void node_composit_init_splitviewer(bNodeTree *UNUSED(ntree), bNode *node) { @@ -43,13 +51,24 @@ static void node_composit_init_splitviewer(bNodeTree *UNUSED(ntree), bNode *node node->id = (ID *)BKE_image_ensure_viewer(G.main, IMA_TYPE_COMPOSITE, "Viewer Node"); } -void register_node_type_cmp_splitviewer(void) +static void node_composit_buts_splitviewer(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *row, *col; + + col = uiLayoutColumn(layout, false); + row = uiLayoutRow(col, false); + uiItemR(row, ptr, "axis", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, nullptr, ICON_NONE); + uiItemR(col, ptr, "factor", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} + +void register_node_type_cmp_splitviewer() { static bNodeType ntype; cmp_node_type_base( &ntype, CMP_NODE_SPLITVIEWER, "Split Viewer", NODE_CLASS_OUTPUT, NODE_PREVIEW); - node_type_socket_templates(&ntype, cmp_node_splitviewer_in, nullptr); + ntype.declare = blender::nodes::cmp_node_split_viewer_declare; + ntype.draw_buttons = node_composit_buts_splitviewer; node_type_init(&ntype, node_composit_init_splitviewer); node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc b/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc index e5ce2e8ceb9..de6cc21ccd5 100644 --- a/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc +++ b/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc @@ -21,22 +21,25 @@ * \ingroup cmpnodes */ -#include "node_composite_util.hh" +#include "UI_interface.h" +#include "UI_resources.h" #include "BKE_context.h" #include "BKE_lib_id.h" -/* **************** Translate ******************** */ +#include "node_composite_util.hh" -static bNodeSocketTemplate cmp_node_stabilize2d_in[] = { - {SOCK_RGBA, N_("Image"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, - {-1, ""}, -}; +/* **************** Stabilize 2D ******************** */ -static bNodeSocketTemplate cmp_node_stabilize2d_out[] = { - {SOCK_RGBA, N_("Image")}, - {-1, ""}, -}; +namespace blender::nodes { + +static void cmp_node_stabilize2d_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({0.8f, 0.8f, 0.8f, 1.0f}); + b.add_output<decl::Color>(N_("Image")); +} + +} // namespace blender::nodes static void init(const bContext *C, PointerRNA *ptr) { @@ -50,12 +53,36 @@ static void init(const bContext *C, PointerRNA *ptr) node->custom1 = 1; } -void register_node_type_cmp_stabilize2d(void) +static void node_composit_buts_stabilize2d(uiLayout *layout, bContext *C, PointerRNA *ptr) +{ + bNode *node = (bNode *)ptr->data; + + uiTemplateID(layout, + C, + ptr, + "clip", + nullptr, + "CLIP_OT_open", + nullptr, + UI_TEMPLATE_ID_FILTER_ALL, + false, + nullptr); + + if (!node->id) { + return; + } + + uiItemR(layout, ptr, "filter_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); + uiItemR(layout, ptr, "invert", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} + +void register_node_type_cmp_stabilize2d() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_STABILIZE2D, "Stabilize 2D", NODE_CLASS_DISTORT, 0); - node_type_socket_templates(&ntype, cmp_node_stabilize2d_in, cmp_node_stabilize2d_out); + ntype.declare = blender::nodes::cmp_node_stabilize2d_declare; + ntype.draw_buttons = node_composit_buts_stabilize2d; ntype.initfunc_api = init; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc b/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc index 73907d2e27f..f5d69c7d17b 100644 --- a/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc +++ b/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc @@ -21,16 +21,20 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" -static bNodeSocketTemplate inputs[] = { - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {-1, ""}, -}; -static bNodeSocketTemplate outputs[] = { - {SOCK_RGBA, N_("Image")}, - {-1, ""}, -}; +namespace blender::nodes { + +static void cmp_node_sunbeams_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_output<decl::Color>(N_("Image")); +} + +} // namespace blender::nodes static void init(bNodeTree *UNUSED(ntree), bNode *node) { @@ -41,12 +45,24 @@ static void init(bNodeTree *UNUSED(ntree), bNode *node) node->storage = data; } -void register_node_type_cmp_sunbeams(void) +static void node_composit_buts_sunbeams(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "source", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, "", ICON_NONE); + uiItemR(layout, + ptr, + "ray_length", + UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, + nullptr, + ICON_NONE); +} + +void register_node_type_cmp_sunbeams() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_SUNBEAMS, "Sun Beams", NODE_CLASS_OP_FILTER, 0); - node_type_socket_templates(&ntype, inputs, outputs); + ntype.declare = blender::nodes::cmp_node_sunbeams_declare; + ntype.draw_buttons = node_composit_buts_sunbeams; node_type_init(&ntype, init); node_type_storage( &ntype, "NodeSunBeams", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_switch.cc b/source/blender/nodes/composite/nodes/node_composite_switch.cc index 71226a6da0b..d13bcc28d10 100644 --- a/source/blender/nodes/composite/nodes/node_composite_switch.cc +++ b/source/blender/nodes/composite/nodes/node_composite_switch.cc @@ -21,27 +21,37 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "../node_composite_util.hh" -/* **************** MIX RGB ******************** */ -static bNodeSocketTemplate cmp_node_switch_in[] = { - {SOCK_RGBA, N_("Off"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, - {SOCK_RGBA, N_("On"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, - {-1, ""}, -}; +/* **************** Switch ******************** */ + +namespace blender::nodes { + +static void cmp_node_switch_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Off")).default_value({0.8f, 0.8f, 0.8f, 1.0f}); + b.add_input<decl::Color>(N_("On")).default_value({0.8f, 0.8f, 0.8f, 1.0f}); + b.add_output<decl::Color>(N_("Image")); +} + +} // namespace blender::nodes -static bNodeSocketTemplate cmp_node_switch_out[] = { - {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, - {-1, ""}, -}; +static void node_composit_buts_switch(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "check", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} /* custom1 = mix type */ -void register_node_type_cmp_switch(void) +void register_node_type_cmp_switch() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_SWITCH, "Switch", NODE_CLASS_LAYOUT, 0); - node_type_socket_templates(&ntype, cmp_node_switch_in, cmp_node_switch_out); + ntype.declare = blender::nodes::cmp_node_switch_declare; + ntype.draw_buttons = node_composit_buts_switch; node_type_size_preset(&ntype, NODE_SIZE_SMALL); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_switchview.cc b/source/blender/nodes/composite/nodes/node_composite_switchview.cc index a61712f7f8d..159d66fc6cc 100644 --- a/source/blender/nodes/composite/nodes/node_composite_switchview.cc +++ b/source/blender/nodes/composite/nodes/node_composite_switchview.cc @@ -25,9 +25,13 @@ #include "BKE_context.h" #include "BKE_lib_id.h" +#include "UI_interface.h" +#include "UI_resources.h" + #include "../node_composite_util.hh" /* **************** SWITCH VIEW ******************** */ + static bNodeSocketTemplate cmp_node_switch_view_out[] = { {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, {-1, ""}, @@ -137,13 +141,27 @@ static void init_switch_view(const bContext *C, PointerRNA *ptr) cmp_node_switch_view_sanitycheck(ntree, node); } -void register_node_type_cmp_switch_view(void) +static void node_composit_buts_switch_view_ex(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *UNUSED(ptr)) +{ + uiItemFullO(layout, + "NODE_OT_switch_view_update", + "Update Views", + ICON_FILE_REFRESH, + nullptr, + WM_OP_INVOKE_DEFAULT, + 0, + nullptr); +} + +void register_node_type_cmp_switch_view() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_SWITCH_VIEW, "Switch View", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, nullptr, cmp_node_switch_view_out); - + ntype.draw_buttons_ex = node_composit_buts_switch_view_ex; ntype.initfunc_api = init_switch_view; node_type_update(&ntype, cmp_node_switch_view_update); diff --git a/source/blender/nodes/composite/nodes/node_composite_texture.cc b/source/blender/nodes/composite/nodes/node_composite_texture.cc index 55ae6a4185e..5e5fca755b2 100644 --- a/source/blender/nodes/composite/nodes/node_composite_texture.cc +++ b/source/blender/nodes/composite/nodes/node_composite_texture.cc @@ -41,7 +41,7 @@ static void cmp_node_texture_declare(NodeDeclarationBuilder &b) } // namespace blender::nodes -void register_node_type_cmp_texture(void) +void register_node_type_cmp_texture() { static bNodeType ntype; diff --git a/source/blender/nodes/composite/nodes/node_composite_tonemap.cc b/source/blender/nodes/composite/nodes/node_composite_tonemap.cc index 33d6f98201c..c6015eda08c 100644 --- a/source/blender/nodes/composite/nodes/node_composite_tonemap.cc +++ b/source/blender/nodes/composite/nodes/node_composite_tonemap.cc @@ -21,6 +21,11 @@ * \ingroup cmpnodes */ +#include "RNA_access.h" + +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" namespace blender::nodes { @@ -49,12 +54,35 @@ static void node_composit_init_tonemap(bNodeTree *UNUSED(ntree), bNode *node) node->storage = ntm; } -void register_node_type_cmp_tonemap(void) +static void node_composit_buts_tonemap(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *col; + + col = uiLayoutColumn(layout, false); + uiItemR(col, ptr, "tonemap_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); + if (RNA_enum_get(ptr, "tonemap_type") == 0) { + uiItemR(col, ptr, "key", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); + uiItemR(col, ptr, "offset", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(col, ptr, "gamma", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + } + else { + uiItemR(col, ptr, "intensity", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR( + col, ptr, "contrast", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); + uiItemR( + col, ptr, "adaptation", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); + uiItemR( + col, ptr, "correction", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); + } +} + +void register_node_type_cmp_tonemap() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_TONEMAP, "Tonemap", NODE_CLASS_OP_COLOR, 0); ntype.declare = blender::nodes::cmp_node_tonemap_declare; + ntype.draw_buttons = node_composit_buts_tonemap; node_type_init(&ntype, node_composit_init_tonemap); node_type_storage(&ntype, "NodeTonemap", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_trackpos.cc b/source/blender/nodes/composite/nodes/node_composite_trackpos.cc index 537f7e661db..3be52820f15 100644 --- a/source/blender/nodes/composite/nodes/node_composite_trackpos.cc +++ b/source/blender/nodes/composite/nodes/node_composite_trackpos.cc @@ -21,6 +21,11 @@ * \ingroup cmpnodes */ +#include "RNA_access.h" + +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" namespace blender::nodes { @@ -42,12 +47,61 @@ static void init(bNodeTree *UNUSED(ntree), bNode *node) node->storage = data; } -void register_node_type_cmp_trackpos(void) +static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRNA *ptr) +{ + bNode *node = (bNode *)ptr->data; + + uiTemplateID(layout, + C, + ptr, + "clip", + nullptr, + "CLIP_OT_open", + nullptr, + UI_TEMPLATE_ID_FILTER_ALL, + false, + nullptr); + + if (node->id) { + MovieClip *clip = (MovieClip *)node->id; + MovieTracking *tracking = &clip->tracking; + MovieTrackingObject *object; + uiLayout *col; + PointerRNA tracking_ptr; + NodeTrackPosData *data = (NodeTrackPosData *)node->storage; + + RNA_pointer_create(&clip->id, &RNA_MovieTracking, tracking, &tracking_ptr); + + col = uiLayoutColumn(layout, false); + uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA); + + object = BKE_tracking_object_get_named(tracking, data->tracking_object); + if (object) { + PointerRNA object_ptr; + + RNA_pointer_create(&clip->id, &RNA_MovieTrackingObject, object, &object_ptr); + + uiItemPointerR(col, ptr, "track_name", &object_ptr, "tracks", "", ICON_ANIM_DATA); + } + else { + uiItemR(layout, ptr, "track_name", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_ANIM_DATA); + } + + uiItemR(layout, ptr, "position", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + + if (ELEM(node->custom1, CMP_TRACKPOS_RELATIVE_FRAME, CMP_TRACKPOS_ABSOLUTE_FRAME)) { + uiItemR(layout, ptr, "frame_relative", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + } + } +} + +void register_node_type_cmp_trackpos() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_TRACKPOS, "Track Position", NODE_CLASS_INPUT, 0); ntype.declare = blender::nodes::cmp_node_trackpos_declare; + ntype.draw_buttons = node_composit_buts_trackpos; node_type_init(&ntype, init); node_type_storage( &ntype, "NodeTrackPosData", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_transform.cc b/source/blender/nodes/composite/nodes/node_composite_transform.cc index 1695101cdbf..ad1cc4cd308 100644 --- a/source/blender/nodes/composite/nodes/node_composite_transform.cc +++ b/source/blender/nodes/composite/nodes/node_composite_transform.cc @@ -21,30 +21,43 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* **************** Transform ******************** */ -static bNodeSocketTemplate cmp_node_transform_in[] = { - {SOCK_RGBA, N_("Image"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, - {SOCK_FLOAT, N_("X"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f}, - {SOCK_FLOAT, N_("Y"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f}, - {SOCK_FLOAT, N_("Angle"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f, PROP_ANGLE}, - {SOCK_FLOAT, N_("Scale"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0001f, CMP_SCALE_MAX}, - {-1, ""}, -}; - -static bNodeSocketTemplate cmp_node_transform_out[] = { - {SOCK_RGBA, N_("Image")}, - {-1, ""}, -}; - -void register_node_type_cmp_transform(void) +namespace blender::nodes { + +static void cmp_node_transform_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({0.8f, 0.8f, 0.8f, 1.0f}); + b.add_input<decl::Float>(N_("X")).default_value(0.0f).min(-10000.0f).max(10000.0f); + b.add_input<decl::Float>(N_("Y")).default_value(0.0f).min(-10000.0f).max(10000.0f); + b.add_input<decl::Float>(N_("Angle")) + .default_value(0.0f) + .min(-10000.0f) + .max(10000.0f) + .subtype(PROP_ANGLE); + b.add_input<decl::Float>(N_("Scale")).default_value(1.0f).min(0.0001f).max(CMP_SCALE_MAX); + b.add_output<decl::Color>(N_("Image")); +} + +} // namespace blender::nodes + +static void node_composit_buts_transform(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "filter_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); +} + +void register_node_type_cmp_transform() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_TRANSFORM, "Transform", NODE_CLASS_DISTORT, 0); - node_type_socket_templates(&ntype, cmp_node_transform_in, cmp_node_transform_out); + ntype.declare = blender::nodes::cmp_node_transform_declare; + ntype.draw_buttons = node_composit_buts_transform; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_translate.cc b/source/blender/nodes/composite/nodes/node_composite_translate.cc index 0ee8a41a5ea..ce29cc55ca2 100644 --- a/source/blender/nodes/composite/nodes/node_composite_translate.cc +++ b/source/blender/nodes/composite/nodes/node_composite_translate.cc @@ -21,20 +21,24 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" -/* **************** Translate ******************** */ +/* **************** Translate ******************** */ + +namespace blender::nodes { + +static void cmp_node_translate_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Float>(N_("X")).default_value(0.0f).min(-10000.0f).max(10000.0f); + b.add_input<decl::Float>(N_("Y")).default_value(0.0f).min(-10000.0f).max(10000.0f); + b.add_output<decl::Color>(N_("Image")); +} -static bNodeSocketTemplate cmp_node_translate_in[] = { - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {SOCK_FLOAT, N_("X"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f, PROP_NONE}, - {SOCK_FLOAT, N_("Y"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f, PROP_NONE}, - {-1, ""}, -}; -static bNodeSocketTemplate cmp_node_translate_out[] = { - {SOCK_RGBA, N_("Image")}, - {-1, ""}, -}; +} // namespace blender::nodes static void node_composit_init_translate(bNodeTree *UNUSED(ntree), bNode *node) { @@ -43,12 +47,19 @@ static void node_composit_init_translate(bNodeTree *UNUSED(ntree), bNode *node) node->storage = data; } -void register_node_type_cmp_translate(void) +static void node_composit_buts_translate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "use_relative", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "wrap_axis", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} + +void register_node_type_cmp_translate() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_TRANSLATE, "Translate", NODE_CLASS_DISTORT, 0); - node_type_socket_templates(&ntype, cmp_node_translate_in, cmp_node_translate_out); + ntype.declare = blender::nodes::cmp_node_translate_declare; + ntype.draw_buttons = node_composit_buts_translate; node_type_init(&ntype, node_composit_init_translate); node_type_storage( &ntype, "NodeTranslateData", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc b/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc index a0ab056e657..dca6c9c141c 100644 --- a/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc +++ b/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc @@ -41,7 +41,7 @@ static void node_composit_init_valtorgb(bNodeTree *UNUSED(ntree), bNode *node) node->storage = BKE_colorband_add(true); } -void register_node_type_cmp_valtorgb(void) +void register_node_type_cmp_valtorgb() { static bNodeType ntype; @@ -66,7 +66,7 @@ static void cmp_node_rgbtobw_declare(NodeDeclarationBuilder &b) } // namespace blender::nodes -void register_node_type_cmp_rgbtobw(void) +void register_node_type_cmp_rgbtobw() { static bNodeType ntype; diff --git a/source/blender/nodes/composite/nodes/node_composite_value.cc b/source/blender/nodes/composite/nodes/node_composite_value.cc index 51214d23472..d2274d2d82a 100644 --- a/source/blender/nodes/composite/nodes/node_composite_value.cc +++ b/source/blender/nodes/composite/nodes/node_composite_value.cc @@ -34,7 +34,7 @@ static void cmp_node_value_declare(NodeDeclarationBuilder &b) } // namespace blender::nodes -void register_node_type_cmp_value(void) +void register_node_type_cmp_value() { static bNodeType ntype; diff --git a/source/blender/nodes/composite/nodes/node_composite_vecBlur.cc b/source/blender/nodes/composite/nodes/node_composite_vecBlur.cc index ce6ba659609..c4bea269670 100644 --- a/source/blender/nodes/composite/nodes/node_composite_vecBlur.cc +++ b/source/blender/nodes/composite/nodes/node_composite_vecBlur.cc @@ -21,15 +21,28 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* **************** VECTOR BLUR ******************** */ -static bNodeSocketTemplate cmp_node_vecblur_in[] = { - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {SOCK_FLOAT, N_("Z"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE}, - {SOCK_VECTOR, N_("Speed"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_VELOCITY}, - {-1, ""}}; -static bNodeSocketTemplate cmp_node_vecblur_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}}; + +namespace blender::nodes { + +static void cmp_node_vec_blur_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Float>(N_("Z")).default_value(0.0f).min(0.0f).max(1.0f); + b.add_input<decl::Vector>(N_("Speed")) + .default_value({0.0f, 0.0f, 0.0f}) + .min(0.0f) + .max(1.0f) + .subtype(PROP_VELOCITY); + b.add_output<decl::Color>(N_("Image")); +} + +} // namespace blender::nodes static void node_composit_init_vecblur(bNodeTree *UNUSED(ntree), bNode *node) { @@ -39,13 +52,30 @@ static void node_composit_init_vecblur(bNodeTree *UNUSED(ntree), bNode *node) nbd->fac = 1.0f; } +static void node_composit_buts_vecblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *col; + + col = uiLayoutColumn(layout, false); + uiItemR(col, ptr, "samples", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(col, ptr, "factor", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Blur"), ICON_NONE); + + col = uiLayoutColumn(layout, true); + uiItemL(col, IFACE_("Speed:"), ICON_NONE); + uiItemR(col, ptr, "speed_min", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Min"), ICON_NONE); + uiItemR(col, ptr, "speed_max", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Max"), ICON_NONE); + + uiItemR(layout, ptr, "use_curved", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} + /* custom1: iterations, custom2: max_speed (0 = no_limit). */ -void register_node_type_cmp_vecblur(void) +void register_node_type_cmp_vecblur() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_VECBLUR, "Vector Blur", NODE_CLASS_OP_FILTER, 0); - node_type_socket_templates(&ntype, cmp_node_vecblur_in, cmp_node_vecblur_out); + ntype.declare = blender::nodes::cmp_node_vec_blur_declare; + ntype.draw_buttons = node_composit_buts_vecblur; node_type_init(&ntype, node_composit_init_vecblur); node_type_storage( &ntype, "NodeBlurData", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_viewer.cc b/source/blender/nodes/composite/nodes/node_composite_viewer.cc index 90f9882099b..fcebda3b8a4 100644 --- a/source/blender/nodes/composite/nodes/node_composite_viewer.cc +++ b/source/blender/nodes/composite/nodes/node_composite_viewer.cc @@ -21,11 +21,16 @@ * \ingroup cmpnodes */ -#include "node_composite_util.hh" - #include "BKE_global.h" #include "BKE_image.h" +#include "RNA_access.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "node_composite_util.hh" + /* **************** VIEWER ******************** */ namespace blender::nodes { @@ -50,12 +55,32 @@ static void node_composit_init_viewer(bNodeTree *UNUSED(ntree), bNode *node) node->id = (ID *)BKE_image_ensure_viewer(G.main, IMA_TYPE_COMPOSITE, "Viewer Node"); } -void register_node_type_cmp_viewer(void) +static void node_composit_buts_viewer(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "use_alpha", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} + +static void node_composit_buts_viewer_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *col; + + uiItemR(layout, ptr, "use_alpha", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(layout, ptr, "tile_order", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + if (RNA_enum_get(ptr, "tile_order") == 0) { + col = uiLayoutColumn(layout, true); + uiItemR(col, ptr, "center_x", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(col, ptr, "center_y", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + } +} + +void register_node_type_cmp_viewer() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT, NODE_PREVIEW); ntype.declare = blender::nodes::cmp_node_viewer_declare; + ntype.draw_buttons = node_composit_buts_viewer; + ntype.draw_buttons_ex = node_composit_buts_viewer_ex; node_type_init(&ntype, node_composit_init_viewer); node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_zcombine.cc b/source/blender/nodes/composite/nodes/node_composite_zcombine.cc index 990f9fcd366..dd6872e4dd9 100644 --- a/source/blender/nodes/composite/nodes/node_composite_zcombine.cc +++ b/source/blender/nodes/composite/nodes/node_composite_zcombine.cc @@ -21,29 +21,43 @@ * \ingroup cmpnodes */ +#include "UI_interface.h" +#include "UI_resources.h" + #include "node_composite_util.hh" /* **************** Z COMBINE ******************** */ -/* lazy coder NOTE: node->custom2 is abused to send signal. */ -static bNodeSocketTemplate cmp_node_zcombine_in[] = { - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {SOCK_FLOAT, N_("Z"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 10000.0f, PROP_NONE}, - {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, - {SOCK_FLOAT, N_("Z"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 10000.0f, PROP_NONE}, - {-1, ""}, -}; -static bNodeSocketTemplate cmp_node_zcombine_out[] = { - {SOCK_RGBA, N_("Image")}, - {SOCK_FLOAT, N_("Z")}, - {-1, ""}, -}; - -void register_node_type_cmp_zcombine(void) + +namespace blender::nodes { + +static void cmp_node_zcombine_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Float>(N_("Z")).default_value(1.0f).min(0.f).max(10000.0f); + b.add_input<decl::Color>(N_("Image"), "Image_001").default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Float>(N_("Z"), "Z_001").default_value(1.0f).min(0.f).max(10000.0f); + b.add_output<decl::Color>(N_("Image")); + b.add_output<decl::Float>(N_("Z")); +} + +} // namespace blender::nodes + +static void node_composit_buts_zcombine(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *col; + + col = uiLayoutColumn(layout, true); + uiItemR(col, ptr, "use_alpha", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); + uiItemR(col, ptr, "use_antialias_z", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); +} + +void register_node_type_cmp_zcombine() { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_ZCOMBINE, "Z Combine", NODE_CLASS_OP_COLOR, 0); - node_type_socket_templates(&ntype, cmp_node_zcombine_in, cmp_node_zcombine_out); + ntype.declare = blender::nodes::cmp_node_zcombine_declare; + ntype.draw_buttons = node_composit_buts_zcombine; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/function/node_function_util.cc b/source/blender/nodes/function/node_function_util.cc index a1493d51a11..83f5b571695 100644 --- a/source/blender/nodes/function/node_function_util.cc +++ b/source/blender/nodes/function/node_function_util.cc @@ -17,13 +17,15 @@ #include "node_function_util.hh" #include "node_util.h" +#include "NOD_socket_search_link.hh" + static bool fn_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree, const char **r_disabled_hint) { /* Function nodes are only supported in simulation node trees so far. */ if (!STREQ(ntree->idname, "GeometryNodeTree")) { - *r_disabled_hint = "Not a geometry node tree"; + *r_disabled_hint = TIP_("Not a geometry node tree"); return false; } return true; @@ -34,4 +36,5 @@ void fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclas node_type_base(ntype, type, name, nclass, flag); ntype->poll = fn_node_poll_default; ntype->insert_link = node_insert_link_default; + ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node; } diff --git a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc index ed03cc0025d..4b59b49c632 100644 --- a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc +++ b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc @@ -47,7 +47,10 @@ static void node_boolean_math_update(bNodeTree *ntree, bNode *node) ntree, sockB, ELEM(node->custom1, NODE_BOOLEAN_MATH_AND, NODE_BOOLEAN_MATH_OR)); } -static void node_boolean_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen) +static void node_boolean_math_label(const bNodeTree *UNUSED(ntree), + const bNode *node, + char *label, + int maxlen) { const char *name; bool enum_label = RNA_enum_name(rna_enum_node_boolean_math_items, node->custom1, &name); @@ -92,7 +95,7 @@ void register_node_type_fn_boolean_math() fn_node_type_base(&ntype, FN_NODE_BOOLEAN_MATH, "Boolean Math", NODE_CLASS_CONVERTER, 0); ntype.declare = blender::nodes::fn_node_boolean_math_declare; - node_type_label(&ntype, blender::nodes::node_boolean_math_label); + ntype.labelfunc = blender::nodes::node_boolean_math_label; node_type_update(&ntype, blender::nodes::node_boolean_math_update); ntype.build_multi_function = blender::nodes::fn_node_boolean_math_build_multi_function; ntype.draw_buttons = blender::nodes::fn_node_boolean_math_layout; diff --git a/source/blender/nodes/function/nodes/node_fn_compare.cc b/source/blender/nodes/function/nodes/node_fn_compare.cc new file mode 100644 index 00000000000..e773563ca5f --- /dev/null +++ b/source/blender/nodes/function/nodes/node_fn_compare.cc @@ -0,0 +1,540 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <cmath> + +#include "BLI_listbase.h" +#include "BLI_string.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_enum_types.h" + +#include "node_function_util.hh" + +#include "NOD_socket_search_link.hh" + +namespace blender::nodes::node_fn_compare_cc { + +NODE_STORAGE_FUNCS(NodeFunctionCompare) + +static void fn_node_compare_declare(NodeDeclarationBuilder &b) +{ + b.is_function_node(); + b.add_input<decl::Float>(N_("A")).min(-10000.0f).max(10000.0f); + b.add_input<decl::Float>(N_("B")).min(-10000.0f).max(10000.0f); + + b.add_input<decl::Int>(N_("A"), "A_INT"); + b.add_input<decl::Int>(N_("B"), "B_INT"); + + b.add_input<decl::Vector>(N_("A"), "A_VEC3"); + b.add_input<decl::Vector>(N_("B"), "B_VEC3"); + + b.add_input<decl::Color>(N_("A"), "A_COL"); + b.add_input<decl::Color>(N_("B"), "B_COL"); + + b.add_input<decl::String>(N_("A"), "A_STR"); + b.add_input<decl::String>(N_("B"), "B_STR"); + + b.add_input<decl::Float>(N_("C")).default_value(0.9f); + b.add_input<decl::Float>(N_("Angle")).default_value(0.0872665f).subtype(PROP_ANGLE); + b.add_input<decl::Float>(N_("Epsilon")).default_value(0.001).min(-10000.0f).max(10000.0f); + + b.add_output<decl::Bool>(N_("Result")); +}; + +static void geo_node_compare_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + const NodeFunctionCompare &data = node_storage(*static_cast<const bNode *>(ptr->data)); + uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); + if (data.data_type == SOCK_VECTOR) { + uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); + } + uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); +} + +static void node_compare_update(bNodeTree *ntree, bNode *node) +{ + NodeFunctionCompare *data = (NodeFunctionCompare *)node->storage; + + bNodeSocket *sock_comp = (bNodeSocket *)BLI_findlink(&node->inputs, 10); + bNodeSocket *sock_angle = (bNodeSocket *)BLI_findlink(&node->inputs, 11); + bNodeSocket *sock_epsilon = (bNodeSocket *)BLI_findlink(&node->inputs, 12); + + LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { + nodeSetSocketAvailability(ntree, socket, socket->type == (eNodeSocketDatatype)data->data_type); + } + + nodeSetSocketAvailability(ntree, + sock_epsilon, + ELEM(data->operation, NODE_COMPARE_EQUAL, NODE_COMPARE_NOT_EQUAL) && + !ELEM(data->data_type, SOCK_INT, SOCK_STRING)); + + nodeSetSocketAvailability(ntree, + sock_comp, + ELEM(data->mode, NODE_COMPARE_MODE_DOT_PRODUCT) && + data->data_type == SOCK_VECTOR); + + nodeSetSocketAvailability(ntree, + sock_angle, + ELEM(data->mode, NODE_COMPARE_MODE_DIRECTION) && + data->data_type == SOCK_VECTOR); +} + +static void node_compare_init(bNodeTree *UNUSED(tree), bNode *node) +{ + NodeFunctionCompare *data = (NodeFunctionCompare *)MEM_callocN(sizeof(NodeFunctionCompare), + __func__); + data->operation = NODE_COMPARE_GREATER_THAN; + data->data_type = SOCK_FLOAT; + data->mode = NODE_COMPARE_MODE_ELEMENT; + node->storage = data; +} + +class SocketSearchOp { + public: + std::string socket_name; + eNodeSocketDatatype data_type; + NodeCompareOperation operation; + NodeCompareMode mode = NODE_COMPARE_MODE_ELEMENT; + void operator()(LinkSearchOpParams ¶ms) + { + bNode &node = params.add_node("FunctionNodeCompare"); + node_storage(node).data_type = data_type; + node_storage(node).operation = operation; + node_storage(node).mode = mode; + params.update_and_connect_available_socket(node, socket_name); + } +}; + +static void node_compare_gather_link_searches(GatherLinkSearchOpParams ¶ms) +{ + const NodeDeclaration &declaration = *params.node_type().fixed_declaration; + if (params.in_out() == SOCK_OUT) { + search_link_ops_for_declarations(params, declaration.outputs()); + return; + } + + const eNodeSocketDatatype type = static_cast<eNodeSocketDatatype>(params.other_socket().type); + + if (ELEM(type, SOCK_FLOAT, SOCK_BOOLEAN, SOCK_RGBA, SOCK_VECTOR, SOCK_INT)) { + params.add_item(IFACE_("A"), SocketSearchOp{"A", type, NODE_COMPARE_GREATER_THAN}); + params.add_item(IFACE_("B"), SocketSearchOp{"B", type, NODE_COMPARE_GREATER_THAN}); + params.add_item( + IFACE_("C"), + SocketSearchOp{ + "C", SOCK_VECTOR, NODE_COMPARE_GREATER_THAN, NODE_COMPARE_MODE_DOT_PRODUCT}); + params.add_item( + IFACE_("Angle"), + SocketSearchOp{ + "Angle", SOCK_VECTOR, NODE_COMPARE_GREATER_THAN, NODE_COMPARE_MODE_DIRECTION}); + } + else if (type == SOCK_STRING) { + params.add_item(IFACE_("A"), SocketSearchOp{"A", type, NODE_COMPARE_EQUAL}); + params.add_item(IFACE_("B"), SocketSearchOp{"B", type, NODE_COMPARE_EQUAL}); + } +} + +static void node_compare_label(const bNodeTree *UNUSED(ntree), + const bNode *node, + char *label, + int maxlen) +{ + const NodeFunctionCompare *data = (NodeFunctionCompare *)node->storage; + const char *name; + bool enum_label = RNA_enum_name(rna_enum_node_compare_operation_items, data->operation, &name); + if (!enum_label) { + name = "Unknown"; + } + BLI_strncpy(label, IFACE_(name), maxlen); +} + +static float component_average(float3 a) +{ + return (a.x + a.y + a.z) / 3.0f; +} + +static const fn::MultiFunction *get_multi_function(bNode &node) +{ + const NodeFunctionCompare *data = (NodeFunctionCompare *)node.storage; + + switch (data->data_type) { + case SOCK_FLOAT: + switch (data->operation) { + case NODE_COMPARE_LESS_THAN: { + static fn::CustomMF_SI_SI_SO<float, float, bool> fn{ + "Less Than", [](float a, float b) { return a < b; }}; + return &fn; + } + case NODE_COMPARE_LESS_EQUAL: { + static fn::CustomMF_SI_SI_SO<float, float, bool> fn{ + "Less Equal", [](float a, float b) { return a <= b; }}; + return &fn; + } + case NODE_COMPARE_GREATER_THAN: { + static fn::CustomMF_SI_SI_SO<float, float, bool> fn{ + "Greater Than", [](float a, float b) { return a > b; }}; + return &fn; + } + case NODE_COMPARE_GREATER_EQUAL: { + static fn::CustomMF_SI_SI_SO<float, float, bool> fn{ + "Greater Equal", [](float a, float b) { return a >= b; }}; + return &fn; + } + case NODE_COMPARE_EQUAL: { + static fn::CustomMF_SI_SI_SI_SO<float, float, float, bool> fn{ + "Equal", [](float a, float b, float epsilon) { return std::abs(a - b) <= epsilon; }}; + return &fn; + } + case NODE_COMPARE_NOT_EQUAL: + static fn::CustomMF_SI_SI_SI_SO<float, float, float, bool> fn{ + "Not Equal", + [](float a, float b, float epsilon) { return std::abs(a - b) > epsilon; }}; + return &fn; + } + break; + case SOCK_INT: + switch (data->operation) { + case NODE_COMPARE_LESS_THAN: { + static fn::CustomMF_SI_SI_SO<int, int, bool> fn{"Less Than", + [](int a, int b) { return a < b; }}; + return &fn; + } + case NODE_COMPARE_LESS_EQUAL: { + static fn::CustomMF_SI_SI_SO<int, int, bool> fn{"Less Equal", + [](int a, int b) { return a <= b; }}; + return &fn; + } + case NODE_COMPARE_GREATER_THAN: { + static fn::CustomMF_SI_SI_SO<int, int, bool> fn{"Greater Than", + [](int a, int b) { return a > b; }}; + return &fn; + } + case NODE_COMPARE_GREATER_EQUAL: { + static fn::CustomMF_SI_SI_SO<int, int, bool> fn{"Greater Equal", + [](int a, int b) { return a >= b; }}; + return &fn; + } + case NODE_COMPARE_EQUAL: { + static fn::CustomMF_SI_SI_SO<int, int, bool> fn{"Equal", + [](int a, int b) { return a == b; }}; + return &fn; + } + case NODE_COMPARE_NOT_EQUAL: { + static fn::CustomMF_SI_SI_SO<int, int, bool> fn{"Not Equal", + [](int a, int b) { return a != b; }}; + return &fn; + } + } + break; + case SOCK_VECTOR: + switch (data->operation) { + case NODE_COMPARE_LESS_THAN: + switch (data->mode) { + case NODE_COMPARE_MODE_AVERAGE: { + static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{ + "Less Than - Average", + [](float3 a, float3 b) { return component_average(a) < component_average(b); }}; + return &fn; + } + case NODE_COMPARE_MODE_DOT_PRODUCT: { + static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{ + "Less Than - Dot Product", + [](float3 a, float3 b, float comp) { return float3::dot(a, b) < comp; }}; + return &fn; + } + case NODE_COMPARE_MODE_DIRECTION: { + static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{ + "Less Than - Direction", + [](float3 a, float3 b, float angle) { return angle_v3v3(a, b) < angle; }}; + return &fn; + } + case NODE_COMPARE_MODE_ELEMENT: { + static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{ + "Less Than - Element-wise", + [](float3 a, float3 b) { return a.x < b.x && a.y < b.y && a.z < b.z; }}; + return &fn; + } + case NODE_COMPARE_MODE_LENGTH: { + static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{ + "Less Than - Length", + [](float3 a, float3 b) { return a.length() < b.length(); }}; + return &fn; + } + } + break; + case NODE_COMPARE_LESS_EQUAL: + switch (data->mode) { + case NODE_COMPARE_MODE_AVERAGE: { + static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{ + "Less Equal - Average", + [](float3 a, float3 b) { return component_average(a) <= component_average(b); }}; + return &fn; + } + case NODE_COMPARE_MODE_DOT_PRODUCT: { + static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{ + "Less Equal - Dot Product", + [](float3 a, float3 b, float comp) { return float3::dot(a, b) <= comp; }}; + return &fn; + } + case NODE_COMPARE_MODE_DIRECTION: { + static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{ + "Less Equal - Direction", + [](float3 a, float3 b, float angle) { return angle_v3v3(a, b) <= angle; }}; + return &fn; + } + case NODE_COMPARE_MODE_ELEMENT: { + static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{ + "Less Equal - Element-wise", + [](float3 a, float3 b) { return a.x <= b.x && a.y <= b.y && a.z <= b.z; }}; + return &fn; + } + case NODE_COMPARE_MODE_LENGTH: { + static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{ + "Less Equal - Length", + [](float3 a, float3 b) { return a.length() <= b.length(); }}; + return &fn; + } + } + break; + case NODE_COMPARE_GREATER_THAN: + switch (data->mode) { + case NODE_COMPARE_MODE_AVERAGE: { + static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{ + "Greater Than - Average", + [](float3 a, float3 b) { return component_average(a) > component_average(b); }}; + return &fn; + } + case NODE_COMPARE_MODE_DOT_PRODUCT: { + static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{ + "Greater Than - Dot Product", + [](float3 a, float3 b, float comp) { return float3::dot(a, b) > comp; }}; + return &fn; + } + case NODE_COMPARE_MODE_DIRECTION: { + static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{ + "Greater Than - Direction", + [](float3 a, float3 b, float angle) { return angle_v3v3(a, b) > angle; }}; + return &fn; + } + case NODE_COMPARE_MODE_ELEMENT: { + static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{ + "Greater Than - Element-wise", + [](float3 a, float3 b) { return a.x > b.x && a.y > b.y && a.z > b.z; }}; + return &fn; + } + case NODE_COMPARE_MODE_LENGTH: { + static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{ + "Greater Than - Length", + [](float3 a, float3 b) { return a.length() > b.length(); }}; + return &fn; + } + } + break; + case NODE_COMPARE_GREATER_EQUAL: + switch (data->mode) { + case NODE_COMPARE_MODE_AVERAGE: { + static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{ + "Greater Equal - Average", + [](float3 a, float3 b) { return component_average(a) >= component_average(b); }}; + return &fn; + } + case NODE_COMPARE_MODE_DOT_PRODUCT: { + static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{ + "Greater Equal - Dot Product", + [](float3 a, float3 b, float comp) { return float3::dot(a, b) >= comp; }}; + return &fn; + } + case NODE_COMPARE_MODE_DIRECTION: { + static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{ + "Greater Equal - Direction", + [](float3 a, float3 b, float angle) { return angle_v3v3(a, b) >= angle; }}; + return &fn; + } + case NODE_COMPARE_MODE_ELEMENT: { + static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{ + "Greater Equal - Element-wise", + [](float3 a, float3 b) { return a.x >= b.x && a.y >= b.y && a.z >= b.z; }}; + return &fn; + } + case NODE_COMPARE_MODE_LENGTH: { + static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{ + "Greater Equal - Length", + [](float3 a, float3 b) { return a.length() >= b.length(); }}; + return &fn; + } + } + break; + case NODE_COMPARE_EQUAL: + switch (data->mode) { + case NODE_COMPARE_MODE_AVERAGE: { + static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{ + "Equal - Average", [](float3 a, float3 b, float epsilon) { + return abs(component_average(a) - component_average(b)) <= epsilon; + }}; + return &fn; + } + case NODE_COMPARE_MODE_DOT_PRODUCT: { + static fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float, float, bool> fn{ + "Equal - Dot Product", [](float3 a, float3 b, float comp, float epsilon) { + return abs(float3::dot(a, b) - comp) <= epsilon; + }}; + return &fn; + } + case NODE_COMPARE_MODE_DIRECTION: { + static fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float, float, bool> fn{ + "Equal - Direction", [](float3 a, float3 b, float angle, float epsilon) { + return abs(angle_v3v3(a, b) - angle) <= epsilon; + }}; + return &fn; + } + case NODE_COMPARE_MODE_ELEMENT: { + static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{ + "Equal - Element-wise", [](float3 a, float3 b, float epsilon) { + return abs(a.x - b.x) <= epsilon && abs(a.y - b.y) <= epsilon && + abs(a.z - b.z) <= epsilon; + }}; + return &fn; + } + case NODE_COMPARE_MODE_LENGTH: { + static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{ + "Equal - Length", [](float3 a, float3 b, float epsilon) { + return abs(a.length() - b.length()) <= epsilon; + }}; + return &fn; + } + } + break; + case NODE_COMPARE_NOT_EQUAL: + switch (data->mode) { + case NODE_COMPARE_MODE_AVERAGE: { + static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{ + "Not Equal - Average", [](float3 a, float3 b, float epsilon) { + return abs(component_average(a) - component_average(b)) > epsilon; + }}; + return &fn; + } + case NODE_COMPARE_MODE_DOT_PRODUCT: { + static fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float, float, bool> fn{ + "Not Equal - Dot Product", [](float3 a, float3 b, float comp, float epsilon) { + return abs(float3::dot(a, b) - comp) >= epsilon; + }}; + return &fn; + } + case NODE_COMPARE_MODE_DIRECTION: { + static fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float, float, bool> fn{ + "Not Equal - Direction", [](float3 a, float3 b, float angle, float epsilon) { + return abs(angle_v3v3(a, b) - angle) > epsilon; + }}; + return &fn; + } + case NODE_COMPARE_MODE_ELEMENT: { + static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{ + "Not Equal - Element-wise", [](float3 a, float3 b, float epsilon) { + return abs(a.x - b.x) > epsilon && abs(a.y - b.y) > epsilon && + abs(a.z - b.z) > epsilon; + }}; + return &fn; + } + case NODE_COMPARE_MODE_LENGTH: { + static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{ + "Not Equal - Length", [](float3 a, float3 b, float epsilon) { + return abs(a.length() - b.length()) > epsilon; + }}; + return &fn; + } + } + break; + } + break; + case SOCK_RGBA: + switch (data->operation) { + case NODE_COMPARE_EQUAL: { + static fn::CustomMF_SI_SI_SI_SO<ColorGeometry4f, ColorGeometry4f, float, bool> fn{ + "Equal", [](ColorGeometry4f a, ColorGeometry4f b, float epsilon) { + return abs(a.r - b.r) <= epsilon && abs(a.g - b.g) <= epsilon && + abs(a.b - b.b) <= epsilon; + }}; + return &fn; + } + case NODE_COMPARE_NOT_EQUAL: { + static fn::CustomMF_SI_SI_SI_SO<ColorGeometry4f, ColorGeometry4f, float, bool> fn{ + "Not Equal", [](ColorGeometry4f a, ColorGeometry4f b, float epsilon) { + return abs(a.r - b.r) > epsilon && abs(a.g - b.g) > epsilon && + abs(a.b - b.b) > epsilon; + }}; + return &fn; + } + case NODE_COMPARE_COLOR_BRIGHTER: { + static fn::CustomMF_SI_SI_SO<ColorGeometry4f, ColorGeometry4f, bool> fn{ + "Brighter", [](ColorGeometry4f a, ColorGeometry4f b) { + return rgb_to_grayscale(a) > rgb_to_grayscale(b); + }}; + return &fn; + } + case NODE_COMPARE_COLOR_DARKER: { + static fn::CustomMF_SI_SI_SO<ColorGeometry4f, ColorGeometry4f, bool> fn{ + "Darker", [](ColorGeometry4f a, ColorGeometry4f b) { + return rgb_to_grayscale(a) < rgb_to_grayscale(b); + }}; + return &fn; + } + } + break; + case SOCK_STRING: + switch (data->operation) { + case NODE_COMPARE_EQUAL: { + static fn::CustomMF_SI_SI_SO<std::string, std::string, bool> fn{ + "Equal", [](std::string a, std::string b) { return a == b; }}; + return &fn; + } + case NODE_COMPARE_NOT_EQUAL: { + static fn::CustomMF_SI_SI_SO<std::string, std::string, bool> fn{ + "Not Equal", [](std::string a, std::string b) { return a != b; }}; + return &fn; + } + } + break; + } + return nullptr; +} + +static void fn_node_compare_build_multi_function(NodeMultiFunctionBuilder &builder) +{ + const fn::MultiFunction *fn = get_multi_function(builder.node()); + builder.set_matching_fn(fn); +} + +} // namespace blender::nodes::node_fn_compare_cc + +void register_node_type_fn_compare() +{ + namespace file_ns = blender::nodes::node_fn_compare_cc; + + static bNodeType ntype; + fn_node_type_base(&ntype, FN_NODE_COMPARE, "Compare", NODE_CLASS_CONVERTER, 0); + ntype.declare = file_ns::fn_node_compare_declare; + ntype.labelfunc = file_ns::node_compare_label; + node_type_update(&ntype, file_ns::node_compare_update); + node_type_init(&ntype, file_ns::node_compare_init); + node_type_storage( + &ntype, "NodeFunctionCompare", node_free_standard_storage, node_copy_standard_storage); + ntype.build_multi_function = file_ns::fn_node_compare_build_multi_function; + ntype.draw_buttons = file_ns::geo_node_compare_layout; + ntype.gather_link_search_ops = file_ns::node_compare_gather_link_searches; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/function/nodes/node_fn_float_compare.cc b/source/blender/nodes/function/nodes/node_fn_float_compare.cc deleted file mode 100644 index b31611a1df2..00000000000 --- a/source/blender/nodes/function/nodes/node_fn_float_compare.cc +++ /dev/null @@ -1,121 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include <cmath> - -#include "BLI_listbase.h" -#include "BLI_string.h" - -#include "RNA_enum_types.h" - -#include "UI_interface.h" -#include "UI_resources.h" - -#include "node_function_util.hh" - -namespace blender::nodes { - -static void fn_node_float_compare_declare(NodeDeclarationBuilder &b) -{ - b.is_function_node(); - b.add_input<decl::Float>(N_("A")).min(-10000.0f).max(10000.0f); - b.add_input<decl::Float>(N_("B")).min(-10000.0f).max(10000.0f); - b.add_input<decl::Float>(N_("Epsilon")).default_value(0.001f).min(-10000.0f).max(10000.0f); - b.add_output<decl::Bool>(N_("Result")); -}; - -static void geo_node_float_compare_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); -} - -static void node_float_compare_update(bNodeTree *ntree, bNode *node) -{ - bNodeSocket *sockEpsilon = (bNodeSocket *)BLI_findlink(&node->inputs, 2); - - nodeSetSocketAvailability( - ntree, - sockEpsilon, - ELEM(node->custom1, NODE_FLOAT_COMPARE_EQUAL, NODE_FLOAT_COMPARE_NOT_EQUAL)); -} - -static void node_float_compare_label(bNodeTree *UNUSED(ntree), - bNode *node, - char *label, - int maxlen) -{ - const char *name; - bool enum_label = RNA_enum_name(rna_enum_node_float_compare_items, node->custom1, &name); - if (!enum_label) { - name = "Unknown"; - } - BLI_strncpy(label, IFACE_(name), maxlen); -} - -static const fn::MultiFunction *get_multi_function(bNode &node) -{ - static fn::CustomMF_SI_SI_SO<float, float, bool> less_than_fn{ - "Less Than", [](float a, float b) { return a < b; }}; - static fn::CustomMF_SI_SI_SO<float, float, bool> less_equal_fn{ - "Less Equal", [](float a, float b) { return a <= b; }}; - static fn::CustomMF_SI_SI_SO<float, float, bool> greater_than_fn{ - "Greater Than", [](float a, float b) { return a > b; }}; - static fn::CustomMF_SI_SI_SO<float, float, bool> greater_equal_fn{ - "Greater Equal", [](float a, float b) { return a >= b; }}; - static fn::CustomMF_SI_SI_SI_SO<float, float, float, bool> equal_fn{ - "Equal", [](float a, float b, float epsilon) { return std::abs(a - b) <= epsilon; }}; - static fn::CustomMF_SI_SI_SI_SO<float, float, float, bool> not_equal_fn{ - "Not Equal", [](float a, float b, float epsilon) { return std::abs(a - b) > epsilon; }}; - - switch (node.custom1) { - case NODE_FLOAT_COMPARE_LESS_THAN: - return &less_than_fn; - case NODE_FLOAT_COMPARE_LESS_EQUAL: - return &less_equal_fn; - case NODE_FLOAT_COMPARE_GREATER_THAN: - return &greater_than_fn; - case NODE_FLOAT_COMPARE_GREATER_EQUAL: - return &greater_equal_fn; - case NODE_FLOAT_COMPARE_EQUAL: - return &equal_fn; - case NODE_FLOAT_COMPARE_NOT_EQUAL: - return ¬_equal_fn; - } - - BLI_assert_unreachable(); - return nullptr; -} - -static void fn_node_float_compare_build_multi_function(NodeMultiFunctionBuilder &builder) -{ - const fn::MultiFunction *fn = get_multi_function(builder.node()); - builder.set_matching_fn(fn); -} - -} // namespace blender::nodes - -void register_node_type_fn_float_compare() -{ - static bNodeType ntype; - - fn_node_type_base(&ntype, FN_NODE_COMPARE_FLOATS, "Compare Floats", NODE_CLASS_CONVERTER, 0); - ntype.declare = blender::nodes::fn_node_float_compare_declare; - node_type_label(&ntype, blender::nodes::node_float_compare_label); - node_type_update(&ntype, blender::nodes::node_float_compare_update); - ntype.build_multi_function = blender::nodes::fn_node_float_compare_build_multi_function; - ntype.draw_buttons = blender::nodes::geo_node_float_compare_layout; - nodeRegisterType(&ntype); -} 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 e6ec925f945..21f6734e4aa 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 @@ -39,7 +39,10 @@ static void fn_node_float_to_int_layout(uiLayout *layout, bContext *UNUSED(C), P uiItemR(layout, ptr, "rounding_mode", 0, "", ICON_NONE); } -static void node_float_to_int_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen) +static void node_float_to_int_label(const bNodeTree *UNUSED(ntree), + const bNode *node, + char *label, + int maxlen) { const char *name; bool enum_label = RNA_enum_name(rna_enum_node_float_to_int_items, node->custom1, &name); @@ -86,7 +89,7 @@ void register_node_type_fn_float_to_int() fn_node_type_base(&ntype, FN_NODE_FLOAT_TO_INT, "Float to Integer", NODE_CLASS_CONVERTER, 0); ntype.declare = blender::nodes::fn_node_float_to_int_declare; - node_type_label(&ntype, blender::nodes::node_float_to_int_label); + ntype.labelfunc = blender::nodes::node_float_to_int_label; ntype.build_multi_function = blender::nodes::fn_node_float_to_int_build_multi_function; ntype.draw_buttons = blender::nodes::fn_node_float_to_int_layout; nodeRegisterType(&ntype); 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 9720a39b740..b053482c99d 100644 --- a/source/blender/nodes/function/nodes/node_fn_random_value.cc +++ b/source/blender/nodes/function/nodes/node_fn_random_value.cc @@ -19,11 +19,15 @@ #include "node_function_util.hh" +#include "NOD_socket_search_link.hh" + #include "UI_interface.h" #include "UI_resources.h" namespace blender::nodes { +NODE_STORAGE_FUNCS(NodeRandomValue) + static void fn_node_random_value_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Vector>(N_("Min")).supports_field(); @@ -41,7 +45,8 @@ static void fn_node_random_value_declare(NodeDeclarationBuilder &b) .max(1.0f) .default_value(0.5f) .subtype(PROP_FACTOR) - .supports_field(); + .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_("Seed")).default_value(0).min(-10000).max(10000).supports_field(); @@ -65,7 +70,7 @@ static void fn_node_random_value_init(bNodeTree *UNUSED(tree), bNode *node) static void fn_node_random_value_update(bNodeTree *ntree, bNode *node) { - const NodeRandomValue &storage = *(const NodeRandomValue *)node->storage; + const NodeRandomValue &storage = node_storage(*node); const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); bNodeSocket *sock_min_vector = (bNodeSocket *)node->inputs.first; @@ -95,6 +100,55 @@ static void fn_node_random_value_update(bNodeTree *ntree, bNode *node) nodeSetSocketAvailability(ntree, sock_out_bool, data_type == CD_PROP_BOOL); } +static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSocket &socket) +{ + switch (socket.type) { + case SOCK_FLOAT: + return CD_PROP_FLOAT; + case SOCK_BOOLEAN: + return CD_PROP_BOOL; + case SOCK_INT: + return CD_PROP_INT32; + case SOCK_VECTOR: + return CD_PROP_FLOAT3; + case SOCK_RGBA: + return CD_PROP_COLOR; + default: + return {}; + } +} + +static void fn_node_random_value_gather_link_search(GatherLinkSearchOpParams ¶ms) +{ + const NodeDeclaration &declaration = *params.node_type().fixed_declaration; + const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket()); + if (!type) { + return; + } + if (params.in_out() == SOCK_IN) { + if (ELEM(*type, CD_PROP_INT32, CD_PROP_FLOAT3, CD_PROP_FLOAT)) { + params.add_item(IFACE_("Min"), [type](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("FunctionNodeRandomValue"); + node_storage(node).data_type = *type; + params.update_and_connect_available_socket(node, "Min"); + }); + params.add_item(IFACE_("Max"), [type](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("FunctionNodeRandomValue"); + node_storage(node).data_type = *type; + params.update_and_connect_available_socket(node, "Max"); + }); + } + search_link_ops_for_declarations(params, declaration.inputs().take_back(3)); + } + else { + params.add_item(IFACE_("Value"), [type](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("FunctionNodeRandomValue"); + node_storage(node).data_type = *type; + params.update_and_connect_available_socket(node, "Value"); + }); + } +} + class RandomVectorFunction : public fn::MultiFunction { public: RandomVectorFunction() @@ -203,14 +257,16 @@ class RandomIntFunction : public fn::MultiFunction { const VArray<int> &seeds = params.readonly_single_input<int>(3, "Seed"); MutableSpan<int> values = params.uninitialized_single_output<int>(4, "Value"); + /* Add one to the maximum and use floor to produce an even + * distribution for the first and last values (See T93591). */ for (int64_t i : mask) { const float min_value = min_values[i]; - const float max_value = max_values[i]; + const float max_value = max_values[i] + 1.0f; const int seed = seeds[i]; const int id = ids[i]; const float value = noise::hash_to_float(id, seed); - values[i] = round_fl_to_int(value * (max_value - min_value) + min_value); + values[i] = floor(value * (max_value - min_value) + min_value); } } }; @@ -251,7 +307,7 @@ class RandomBoolFunction : public fn::MultiFunction { static void fn_node_random_value_build_multi_function(NodeMultiFunctionBuilder &builder) { - const NodeRandomValue &storage = *(const NodeRandomValue *)builder.node().storage; + const NodeRandomValue &storage = node_storage(builder.node()); const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); switch (data_type) { @@ -293,6 +349,7 @@ void register_node_type_fn_random_value() ntype.draw_buttons = blender::nodes::fn_node_random_value_layout; ntype.declare = blender::nodes::fn_node_random_value_declare; ntype.build_multi_function = blender::nodes::fn_node_random_value_build_multi_function; + ntype.gather_link_search_ops = blender::nodes::fn_node_random_value_gather_link_search; node_type_storage( &ntype, "NodeRandomValue", node_free_standard_storage, node_copy_standard_storage); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt index 5ee26260790..f9a64381981 100644 --- a/source/blender/nodes/geometry/CMakeLists.txt +++ b/source/blender/nodes/geometry/CMakeLists.txt @@ -39,48 +39,49 @@ set(INC set(SRC - nodes/legacy/node_geo_align_rotation_to_vector.cc - nodes/legacy/node_geo_attribute_clamp.cc - nodes/legacy/node_geo_attribute_color_ramp.cc - nodes/legacy/node_geo_attribute_combine_xyz.cc - nodes/legacy/node_geo_attribute_compare.cc - nodes/legacy/node_geo_attribute_convert.cc - nodes/legacy/node_geo_attribute_curve_map.cc - nodes/legacy/node_geo_attribute_fill.cc - nodes/legacy/node_geo_attribute_map_range.cc - nodes/legacy/node_geo_attribute_math.cc - nodes/legacy/node_geo_attribute_mix.cc - nodes/legacy/node_geo_attribute_proximity.cc - nodes/legacy/node_geo_attribute_randomize.cc - nodes/legacy/node_geo_attribute_sample_texture.cc - nodes/legacy/node_geo_attribute_separate_xyz.cc - nodes/legacy/node_geo_attribute_transfer.cc - nodes/legacy/node_geo_attribute_vector_math.cc - nodes/legacy/node_geo_attribute_vector_rotate.cc - nodes/legacy/node_geo_curve_endpoints.cc - nodes/legacy/node_geo_curve_reverse.cc - nodes/legacy/node_geo_curve_select_by_handle_type.cc - nodes/legacy/node_geo_curve_set_handles.cc - nodes/legacy/node_geo_curve_spline_type.cc - nodes/legacy/node_geo_curve_subdivide.cc - nodes/legacy/node_geo_curve_to_points.cc - nodes/legacy/node_geo_delete_geometry.cc - nodes/legacy/node_geo_edge_split.cc - nodes/legacy/node_geo_material_assign.cc - nodes/legacy/node_geo_mesh_to_curve.cc - nodes/legacy/node_geo_point_distribute.cc - nodes/legacy/node_geo_point_instance.cc - nodes/legacy/node_geo_point_rotate.cc - nodes/legacy/node_geo_point_scale.cc - nodes/legacy/node_geo_point_separate.cc - nodes/legacy/node_geo_point_translate.cc - nodes/legacy/node_geo_points_to_volume.cc - nodes/legacy/node_geo_raycast.cc - nodes/legacy/node_geo_select_by_material.cc - nodes/legacy/node_geo_subdivision_surface.cc - nodes/legacy/node_geo_volume_to_mesh.cc + nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc + nodes/legacy/node_geo_legacy_attribute_clamp.cc + nodes/legacy/node_geo_legacy_attribute_color_ramp.cc + nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc + nodes/legacy/node_geo_legacy_attribute_compare.cc + nodes/legacy/node_geo_legacy_attribute_convert.cc + nodes/legacy/node_geo_legacy_attribute_curve_map.cc + nodes/legacy/node_geo_legacy_attribute_fill.cc + nodes/legacy/node_geo_legacy_attribute_map_range.cc + nodes/legacy/node_geo_legacy_attribute_math.cc + nodes/legacy/node_geo_legacy_attribute_mix.cc + nodes/legacy/node_geo_legacy_attribute_proximity.cc + nodes/legacy/node_geo_legacy_attribute_randomize.cc + nodes/legacy/node_geo_legacy_attribute_sample_texture.cc + nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc + nodes/legacy/node_geo_legacy_attribute_transfer.cc + nodes/legacy/node_geo_legacy_attribute_vector_math.cc + nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc + nodes/legacy/node_geo_legacy_curve_endpoints.cc + nodes/legacy/node_geo_legacy_curve_reverse.cc + nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc + nodes/legacy/node_geo_legacy_curve_set_handles.cc + nodes/legacy/node_geo_legacy_curve_spline_type.cc + nodes/legacy/node_geo_legacy_curve_subdivide.cc + nodes/legacy/node_geo_legacy_curve_to_points.cc + nodes/legacy/node_geo_legacy_delete_geometry.cc + nodes/legacy/node_geo_legacy_edge_split.cc + nodes/legacy/node_geo_legacy_material_assign.cc + nodes/legacy/node_geo_legacy_mesh_to_curve.cc + nodes/legacy/node_geo_legacy_point_distribute.cc + nodes/legacy/node_geo_legacy_point_instance.cc + nodes/legacy/node_geo_legacy_point_rotate.cc + nodes/legacy/node_geo_legacy_point_scale.cc + nodes/legacy/node_geo_legacy_point_separate.cc + nodes/legacy/node_geo_legacy_point_translate.cc + nodes/legacy/node_geo_legacy_points_to_volume.cc + nodes/legacy/node_geo_legacy_raycast.cc + nodes/legacy/node_geo_legacy_select_by_material.cc + nodes/legacy/node_geo_legacy_subdivision_surface.cc + nodes/legacy/node_geo_legacy_volume_to_mesh.cc nodes/node_geo_attribute_capture.cc + nodes/node_geo_attribute_domain_size.cc nodes/node_geo_attribute_remove.cc nodes/node_geo_attribute_statistic.cc nodes/node_geo_boolean.cc @@ -93,7 +94,6 @@ set(SRC nodes/node_geo_curve_fillet.cc nodes/node_geo_curve_handle_type_selection.cc nodes/node_geo_curve_length.cc - nodes/node_geo_curve_parameter.cc nodes/node_geo_curve_primitive_bezier_segment.cc nodes/node_geo_curve_primitive_circle.cc nodes/node_geo_curve_primitive_line.cc @@ -106,13 +106,16 @@ set(SRC nodes/node_geo_curve_sample.cc nodes/node_geo_curve_set_handles.cc nodes/node_geo_curve_spline_type.cc + nodes/node_geo_curve_spline_parameter.cc nodes/node_geo_curve_subdivide.cc nodes/node_geo_curve_to_mesh.cc nodes/node_geo_curve_to_points.cc nodes/node_geo_curve_trim.cc nodes/node_geo_delete_geometry.cc nodes/node_geo_distribute_points_on_faces.cc + nodes/node_geo_dual_mesh.cc nodes/node_geo_edge_split.cc + nodes/node_geo_geometry_to_instance.cc nodes/node_geo_image_texture.cc nodes/node_geo_input_curve_handles.cc nodes/node_geo_input_curve_tilt.cc @@ -120,9 +123,16 @@ set(SRC nodes/node_geo_input_index.cc nodes/node_geo_input_material_index.cc nodes/node_geo_input_material.cc + nodes/node_geo_input_mesh_edge_neighbors.cc + nodes/node_geo_input_mesh_edge_vertices.cc + nodes/node_geo_input_mesh_face_area.cc + nodes/node_geo_input_mesh_face_neighbors.cc + nodes/node_geo_input_mesh_island.cc + nodes/node_geo_input_mesh_vertex_neighbors.cc nodes/node_geo_input_normal.cc nodes/node_geo_input_position.cc nodes/node_geo_input_radius.cc + nodes/node_geo_input_scene_time.cc nodes/node_geo_input_shade_smooth.cc nodes/node_geo_input_spline_cyclic.cc nodes/node_geo_input_spline_length.cc @@ -265,3 +275,8 @@ if(WITH_OPENVDB) endif() blender_add_lib(bf_nodes_geometry "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") + +if(WITH_UNITY_BUILD) + set_target_properties(bf_nodes_geometry PROPERTIES UNITY_BUILD ON) + set_target_properties(bf_nodes_geometry PROPERTIES UNITY_BUILD_BATCH_SIZE 10) +endif() diff --git a/source/blender/nodes/geometry/node_geometry_tree.cc b/source/blender/nodes/geometry/node_geometry_tree.cc index 9747bb63773..89ab4d9961e 100644 --- a/source/blender/nodes/geometry/node_geometry_tree.cc +++ b/source/blender/nodes/geometry/node_geometry_tree.cc @@ -84,15 +84,16 @@ static void foreach_nodeclass(Scene *UNUSED(scene), void *calldata, bNodeClassCa func(calldata, NODE_CLASS_LAYOUT, N_("Layout")); } -static bool geometry_node_tree_validate_link(bNodeTree *UNUSED(ntree), bNodeLink *link) +static bool geometry_node_tree_validate_link(eNodeSocketDatatype type_a, + eNodeSocketDatatype type_b) { /* Geometry, string, object, material, texture and collection sockets can only be connected to * themselves. The other types can be converted between each other. */ - if (ELEM(link->fromsock->type, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_BOOLEAN, SOCK_INT) && - ELEM(link->tosock->type, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_BOOLEAN, SOCK_INT)) { + if (ELEM(type_a, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_BOOLEAN, SOCK_INT) && + ELEM(type_b, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_BOOLEAN, SOCK_INT)) { return true; } - return (link->tosock->type == link->fromsock->type); + return type_a == type_b; } static bool geometry_node_tree_socket_type_valid(bNodeTreeType *UNUSED(ntreetype), @@ -113,7 +114,7 @@ static bool geometry_node_tree_socket_type_valid(bNodeTreeType *UNUSED(ntreetype SOCK_MATERIAL); } -void register_node_tree_type_geo(void) +void register_node_tree_type_geo() { bNodeTreeType *tt = ntreeType_Geometry = static_cast<bNodeTreeType *>( MEM_callocN(sizeof(bNodeTreeType), "geometry node tree type")); diff --git a/source/blender/nodes/geometry/node_geometry_util.cc b/source/blender/nodes/geometry/node_geometry_util.cc index 5c1d507041c..49991a40c1b 100644 --- a/source/blender/nodes/geometry/node_geometry_util.cc +++ b/source/blender/nodes/geometry/node_geometry_util.cc @@ -24,17 +24,12 @@ #include "BKE_mesh_runtime.h" #include "BKE_pointcloud.h" +#include "NOD_socket_search_link.hh" + namespace blender::nodes { using bke::GeometryInstanceGroup; -/** - * Update the availability of a group of input sockets with the same name, - * used for switching between attribute inputs or single values. - * - * \param mode: Controls which socket of the group to make available. - * \param name_is_available: If false, make all sockets with this name unavailable. - */ void update_attribute_input_socket_availabilities(bNodeTree &ntree, bNode &node, const StringRef name, @@ -56,6 +51,31 @@ void update_attribute_input_socket_availabilities(bNodeTree &ntree, } } +std::optional<CustomDataType> node_data_type_to_custom_data_type(const eNodeSocketDatatype type) +{ + switch (type) { + case SOCK_FLOAT: + return CD_PROP_FLOAT; + case SOCK_VECTOR: + return CD_PROP_FLOAT3; + case SOCK_RGBA: + return CD_PROP_COLOR; + case SOCK_BOOLEAN: + return CD_PROP_BOOL; + case SOCK_INT: + return CD_PROP_INT32; + case SOCK_STRING: + return CD_PROP_STRING; + default: + return {}; + } +} + +std::optional<CustomDataType> node_socket_to_custom_data_type(const bNodeSocket &socket) +{ + return node_data_type_to_custom_data_type(static_cast<eNodeSocketDatatype>(socket.type)); +} + } // namespace blender::nodes bool geo_node_poll_default(bNodeType *UNUSED(ntype), @@ -63,7 +83,7 @@ bool geo_node_poll_default(bNodeType *UNUSED(ntype), const char **r_disabled_hint) { if (!STREQ(ntree->idname, "GeometryNodeTree")) { - *r_disabled_hint = "Not a geometry node tree"; + *r_disabled_hint = TIP_("Not a geometry node tree"); return false; } return true; @@ -74,4 +94,5 @@ void geo_node_type_base(bNodeType *ntype, int type, const char *name, short ncla node_type_base(ntype, type, name, nclass, flag); ntype->poll = geo_node_poll_default; ntype->insert_link = node_insert_link_default; + ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node; } diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh index 79fe2ffc42b..3376b75d05b 100644 --- a/source/blender/nodes/geometry/node_geometry_util.hh +++ b/source/blender/nodes/geometry/node_geometry_util.hh @@ -43,6 +43,13 @@ bool geo_node_poll_default(struct bNodeType *ntype, const char **r_disabled_hint); namespace blender::nodes { +/** + * Update the availability of a group of input sockets with the same name, + * used for switching between attribute inputs or single values. + * + * \param mode: Controls which socket of the group to make available. + * \param name_is_available: If false, make all sockets with this name unavailable. + */ void update_attribute_input_socket_availabilities(bNodeTree &ntree, bNode &node, const StringRef name, @@ -126,4 +133,7 @@ void curve_create_default_rotation_attribute(Span<float3> tangents, Span<float3> normals, MutableSpan<float3> rotations); +std::optional<CustomDataType> node_data_type_to_custom_data_type(eNodeSocketDatatype type); +std::optional<CustomDataType> node_socket_to_custom_data_type(const bNodeSocket &socket); + } // namespace blender::nodes diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc index dc7c251d034..4366c6f9234 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc @@ -22,9 +22,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_align_rotation_to_vector_cc { -static void geo_node_align_rotation_to_vector_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Factor")); @@ -40,9 +40,7 @@ static void geo_node_align_rotation_to_vector_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_align_rotation_to_vector_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "axis", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); uiLayoutSetPropSep(layout, true); @@ -53,7 +51,7 @@ static void geo_node_align_rotation_to_vector_layout(uiLayout *layout, uiItemR(col, ptr, "input_type_vector", 0, IFACE_("Vector"), ICON_NONE); } -static void geo_node_align_rotation_to_vector_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryAlignRotationToVector *node_storage = (NodeGeometryAlignRotationToVector *) MEM_callocN(sizeof(NodeGeometryAlignRotationToVector), __func__); @@ -65,7 +63,7 @@ static void geo_node_align_rotation_to_vector_init(bNodeTree *UNUSED(ntree), bNo node->storage = node_storage; } -static void geo_node_align_rotation_to_vector_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryAlignRotationToVector *node_storage = (NodeGeometryAlignRotationToVector *) node->storage; @@ -199,11 +197,11 @@ static void align_rotations_on_component(GeometryComponent &component, rotations.save(); } -static void geo_node_align_rotation_to_vector_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - geometry_set = geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (geometry_set.has<MeshComponent>()) { align_rotations_on_component(geometry_set.get_component_for_write<MeshComponent>(), params); @@ -219,10 +217,12 @@ static void geo_node_align_rotation_to_vector_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_align_rotation_to_vector_cc void register_node_type_geo_align_rotation_to_vector() { + namespace file_ns = blender::nodes::node_geo_legacy_align_rotation_to_vector_cc; + static bNodeType ntype; geo_node_type_base(&ntype, @@ -230,14 +230,14 @@ void register_node_type_geo_align_rotation_to_vector() "Align Rotation to Vector", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_align_rotation_to_vector_init); - node_type_update(&ntype, blender::nodes::geo_node_align_rotation_to_vector_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage(&ntype, "NodeGeometryAlignRotationToVector", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_align_rotation_to_vector_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_align_rotation_to_vector_exec; - ntype.draw_buttons = blender::nodes::geo_node_align_rotation_to_vector_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_clamp.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc index a11a1bd3825..7435152a966 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_clamp.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc @@ -20,9 +20,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_clamp_cc { -static void geo_node_attribute_clamp_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Attribute")); @@ -38,13 +38,13 @@ static void geo_node_attribute_clamp_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_clamp_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); } -static void geo_node_attribute_clamp_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeAttributeClamp *data = (NodeAttributeClamp *)MEM_callocN(sizeof(NodeAttributeClamp), __func__); @@ -53,7 +53,7 @@ static void geo_node_attribute_clamp_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_attribute_clamp_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { bNodeSocket *sock_min_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 3); bNodeSocket *sock_max_vector = sock_min_vector->next; @@ -243,11 +243,11 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam attribute_result.save(); } -static void geo_node_attribute_clamp_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - geometry_set = geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (geometry_set.has<MeshComponent>()) { clamp_attribute(geometry_set.get_component_for_write<MeshComponent>(), params); @@ -262,19 +262,21 @@ static void geo_node_attribute_clamp_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_clamp_cc void register_node_type_geo_attribute_clamp() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_clamp_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CLAMP, "Attribute Clamp", NODE_CLASS_ATTRIBUTE, 0); - node_type_init(&ntype, blender::nodes::geo_node_attribute_clamp_init); - node_type_update(&ntype, blender::nodes::geo_node_attribute_clamp_update); - ntype.declare = blender::nodes::geo_node_attribute_clamp_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_clamp_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_clamp_layout; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; node_type_storage( &ntype, "NodeAttributeClamp", node_free_standard_storage, node_copy_standard_storage); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_color_ramp.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc index 061f5f3d7ee..4efdf786e4e 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_color_ramp.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc @@ -23,9 +23,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attributes_color_ramp_cc { -static void geo_node_attribute_color_ramp_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Attribute")); @@ -33,14 +33,12 @@ static void geo_node_attribute_color_ramp_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_color_ramp_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiTemplateColorRamp(layout, ptr, "color_ramp", false); } -static void geo_node_attribute_color_ramp_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeAttributeColorRamp *node_storage = (NodeAttributeColorRamp *)MEM_callocN( sizeof(NodeAttributeColorRamp), __func__); @@ -100,11 +98,11 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon attribute_result.save(); } -static void geo_node_attribute_color_ramp_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - geometry_set = geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (geometry_set.has<MeshComponent>()) { execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>()); @@ -119,10 +117,12 @@ static void geo_node_attribute_color_ramp_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attributes_color_ramp_cc void register_node_type_geo_attribute_color_ramp() { + namespace file_ns = blender::nodes::node_geo_legacy_attributes_color_ramp_cc; + static bNodeType ntype; geo_node_type_base(&ntype, @@ -132,10 +132,10 @@ void register_node_type_geo_attribute_color_ramp() 0); node_type_storage( &ntype, "NodeAttributeColorRamp", node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_attribute_color_ramp_init); + node_type_init(&ntype, file_ns::node_init); node_type_size_preset(&ntype, NODE_SIZE_LARGE); - ntype.declare = blender::nodes::geo_node_attribute_color_ramp_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_color_ramp_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_color_ramp_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc index a610356955b..7ba64c8db2b 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc @@ -19,9 +19,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_combine_xyz_cc { -static void geo_node_attribute_combine_xyz_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("X")); @@ -34,9 +34,7 @@ static void geo_node_attribute_combine_xyz_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_combine_xyz_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -46,7 +44,7 @@ static void geo_node_attribute_combine_xyz_layout(uiLayout *layout, uiItemR(col, ptr, "input_type_z", 0, IFACE_("Z"), ICON_NONE); } -static void geo_node_attribute_combine_xyz_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeAttributeCombineXYZ *data = (NodeAttributeCombineXYZ *)MEM_callocN( sizeof(NodeAttributeCombineXYZ), __func__); @@ -57,7 +55,7 @@ static void geo_node_attribute_combine_xyz_init(bNodeTree *UNUSED(tree), bNode * node->storage = data; } -static void geo_node_attribute_combine_xyz_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeAttributeCombineXYZ *node_storage = (NodeAttributeCombineXYZ *)node->storage; update_attribute_input_socket_availabilities( @@ -111,11 +109,11 @@ static void combine_attributes(GeometryComponent &component, const GeoNodeExecPa attribute_result.save(); } -static void geo_node_attribute_combine_xyz_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - geometry_set = geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (geometry_set.has<MeshComponent>()) { combine_attributes(geometry_set.get_component_for_write<MeshComponent>(), params); @@ -130,10 +128,12 @@ static void geo_node_attribute_combine_xyz_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_combine_xyz_cc void register_node_type_geo_attribute_combine_xyz() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_combine_xyz_cc; + static bNodeType ntype; geo_node_type_base(&ntype, @@ -141,13 +141,13 @@ void register_node_type_geo_attribute_combine_xyz() "Attribute Combine XYZ", NODE_CLASS_ATTRIBUTE, 0); - node_type_init(&ntype, blender::nodes::geo_node_attribute_combine_xyz_init); - node_type_update(&ntype, blender::nodes::geo_node_attribute_combine_xyz_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeAttributeCombineXYZ", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_attribute_combine_xyz_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_combine_xyz_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_combine_xyz_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_compare.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc index a4ffe884999..8aa1adb0cf3 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_compare.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc @@ -21,9 +21,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_compare_cc { -static void geo_node_attribute_compare_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("A")); @@ -39,9 +39,7 @@ static void geo_node_attribute_compare_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_compare_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); uiLayoutSetPropSep(layout, true); @@ -50,11 +48,11 @@ static void geo_node_attribute_compare_layout(uiLayout *layout, uiItemR(layout, ptr, "input_type_b", 0, IFACE_("B"), ICON_NONE); } -static void geo_node_attribute_compare_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeAttributeCompare *data = (NodeAttributeCompare *)MEM_callocN(sizeof(NodeAttributeCompare), __func__); - data->operation = NODE_FLOAT_COMPARE_GREATER_THAN; + data->operation = NODE_COMPARE_GREATER_THAN; data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; data->input_type_b = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; node->storage = data; @@ -62,10 +60,10 @@ static void geo_node_attribute_compare_init(bNodeTree *UNUSED(tree), bNode *node static bool operation_tests_equality(const NodeAttributeCompare &node_storage) { - return ELEM(node_storage.operation, NODE_FLOAT_COMPARE_EQUAL, NODE_FLOAT_COMPARE_NOT_EQUAL); + return ELEM(node_storage.operation, NODE_COMPARE_EQUAL, NODE_COMPARE_NOT_EQUAL); } -static void geo_node_attribute_compare_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeAttributeCompare *node_storage = (NodeAttributeCompare *)node->storage; update_attribute_input_socket_availabilities( @@ -79,7 +77,7 @@ static void geo_node_attribute_compare_update(bNodeTree *ntree, bNode *node) static void do_math_operation(const VArray<float> &input_a, const VArray<float> &input_b, - const FloatCompareOperation operation, + const NodeCompareOperation operation, MutableSpan<bool> span_result) { const int size = input_a.size(); @@ -243,7 +241,7 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx { const bNode &node = params.node(); NodeAttributeCompare *node_storage = (NodeAttributeCompare *)node.storage; - const FloatCompareOperation operation = static_cast<FloatCompareOperation>( + const NodeCompareOperation operation = static_cast<NodeCompareOperation>( node_storage->operation); const std::string result_name = params.get_input<std::string>("Result"); @@ -273,7 +271,7 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx * conversions and float comparison. In other words, the comparison is not element-wise. */ if (operation_tests_equality(*node_storage)) { const float threshold = params.get_input<float>("Threshold"); - if (operation == NODE_FLOAT_COMPARE_EQUAL) { + if (operation == NODE_COMPARE_EQUAL) { if (input_data_type == CD_PROP_FLOAT) { do_equal_operation_float( attribute_a.typed<float>(), attribute_b.typed<float>(), threshold, result_span); @@ -293,7 +291,7 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx attribute_a.typed<bool>(), attribute_b.typed<bool>(), threshold, result_span); } } - else if (operation == NODE_FLOAT_COMPARE_NOT_EQUAL) { + else if (operation == NODE_COMPARE_NOT_EQUAL) { if (input_data_type == CD_PROP_FLOAT) { do_not_equal_operation_float( attribute_a.typed<float>(), attribute_b.typed<float>(), threshold, result_span); @@ -322,11 +320,11 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx attribute_result.save(); } -static void geo_node_attribute_compare_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - geometry_set = geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (geometry_set.has<MeshComponent>()) { attribute_compare_calc(geometry_set.get_component_for_write<MeshComponent>(), params); @@ -341,20 +339,22 @@ static void geo_node_attribute_compare_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_compare_cc void register_node_type_geo_attribute_compare() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_compare_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_COMPARE, "Attribute Compare", NODE_CLASS_ATTRIBUTE, 0); - ntype.declare = blender::nodes::geo_node_attribute_compare_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_compare_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_compare_layout; - node_type_update(&ntype, blender::nodes::geo_node_attribute_compare_update); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeAttributeCompare", node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_attribute_compare_init); + node_type_init(&ntype, file_ns::node_init); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_convert.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc index 13ba8d13618..28c133871f7 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_convert.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc @@ -19,9 +19,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_convert_cc { -static void geo_node_attribute_convert_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Attribute")); @@ -29,9 +29,7 @@ static void geo_node_attribute_convert_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_convert_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -39,7 +37,7 @@ static void geo_node_attribute_convert_layout(uiLayout *layout, uiItemR(layout, ptr, "data_type", 0, IFACE_("Type"), ICON_NONE); } -static void geo_node_attribute_convert_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeAttributeConvert *data = (NodeAttributeConvert *)MEM_callocN(sizeof(NodeAttributeConvert), __func__); @@ -130,11 +128,11 @@ static void attribute_convert_calc(GeometryComponent &component, result_attribute.save(); } -static void geo_node_attribute_convert_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - geometry_set = geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); const std::string result_name = params.extract_input<std::string>("Result"); const std::string source_name = params.extract_input<std::string>("Attribute"); @@ -143,7 +141,7 @@ static void geo_node_attribute_convert_exec(GeoNodeExecParams params) const AttributeDomain domain = static_cast<AttributeDomain>(node_storage.domain); if (result_name.empty()) { - params.set_output("Geometry", geometry_set); + params.set_default_remaining_outputs(); return; } @@ -175,18 +173,20 @@ static void geo_node_attribute_convert_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_convert_cc void register_node_type_geo_attribute_convert() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_convert_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CONVERT, "Attribute Convert", NODE_CLASS_ATTRIBUTE, 0); - ntype.declare = blender::nodes::geo_node_attribute_convert_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_convert_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_convert_layout; - node_type_init(&ntype, blender::nodes::geo_node_attribute_convert_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + node_type_init(&ntype, file_ns::node_init); node_type_storage( &ntype, "NodeAttributeConvert", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_curve_map.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc index af56df0dc3f..0a7b5dd8463 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_curve_map.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc @@ -24,9 +24,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_curve_map_cc { -static void geo_node_attribute_curve_map_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Attribute")); @@ -34,9 +34,7 @@ static void geo_node_attribute_curve_map_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_curve_map_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); bNode *node = (bNode *)ptr->data; @@ -54,7 +52,7 @@ static void geo_node_attribute_curve_map_layout(uiLayout *layout, } } -static void geo_node_attribute_curve_map_free_storage(bNode *node) +static void node_free_storage(bNode *node) { if (node->storage) { NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)node->storage; @@ -64,9 +62,9 @@ static void geo_node_attribute_curve_map_free_storage(bNode *node) } } -static void geo_node_attribute_curve_map_copy_storage(bNodeTree *UNUSED(dest_ntree), - bNode *dest_node, - const bNode *src_node) +static void node_copy_storage(bNodeTree *UNUSED(dest_ntree), + bNode *dest_node, + const bNode *src_node) { dest_node->storage = MEM_dupallocN(src_node->storage); NodeAttributeCurveMap *src_data = (NodeAttributeCurveMap *)src_node->storage; @@ -75,7 +73,7 @@ static void geo_node_attribute_curve_map_copy_storage(bNodeTree *UNUSED(dest_ntr dest_data->curve_rgb = BKE_curvemapping_copy(src_data->curve_rgb); } -static void geo_node_attribute_curve_map_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)MEM_callocN(sizeof(NodeAttributeCurveMap), __func__); @@ -87,7 +85,7 @@ static void geo_node_attribute_curve_map_init(bNodeTree *UNUSED(ntree), bNode *n node->storage = data; } -static void geo_node_attribute_curve_map_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *UNUSED(ntree), bNode *node) { /* Set the active curve when data type is changed. */ NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)node->storage; @@ -179,7 +177,7 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon attribute_result.save(); } -static void geo_node_attribute_curve_map_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const bNode &bnode = params.node(); NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)bnode.storage; @@ -188,7 +186,7 @@ static void geo_node_attribute_curve_map_exec(GeoNodeExecParams params) GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - geometry_set = geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (geometry_set.has<MeshComponent>()) { execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>()); @@ -203,23 +201,23 @@ static void geo_node_attribute_curve_map_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_curve_map_cc void register_node_type_geo_attribute_curve_map() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_curve_map_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CURVE_MAP, "Attribute Curve Map", NODE_CLASS_ATTRIBUTE, 0); - node_type_update(&ntype, blender::nodes::geo_node_attribute_curve_map_update); - node_type_init(&ntype, blender::nodes::geo_node_attribute_curve_map_init); + node_type_update(&ntype, file_ns::node_update); + node_type_init(&ntype, file_ns::node_init); node_type_size_preset(&ntype, NODE_SIZE_LARGE); - node_type_storage(&ntype, - "NodeAttributeCurveMap", - blender::nodes::geo_node_attribute_curve_map_free_storage, - blender::nodes::geo_node_attribute_curve_map_copy_storage); - ntype.declare = blender::nodes::geo_node_attribute_curve_map_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_curve_map_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_curve_map_layout; + node_type_storage( + &ntype, "NodeAttributeCurveMap", file_ns::node_free_storage, file_ns::node_copy_storage); + 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/legacy/node_geo_attribute_fill.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc index a1b537e9657..a05bcf1bed8 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_fill.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc @@ -19,9 +19,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_fill_cc { -static void geo_node_attribute_fill_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Attribute")).is_attribute_name(); @@ -33,7 +33,7 @@ static void geo_node_attribute_fill_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_fill_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -41,13 +41,13 @@ static void geo_node_attribute_fill_layout(uiLayout *layout, bContext *UNUSED(C) uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); } -static void geo_node_attribute_fill_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { node->custom1 = CD_PROP_FLOAT; node->custom2 = ATTR_DOMAIN_AUTO; } -static void geo_node_attribute_fill_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { bNodeSocket *socket_value_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 2); bNodeSocket *socket_value_float = socket_value_vector->next; @@ -127,11 +127,11 @@ static void fill_attribute(GeometryComponent &component, const GeoNodeExecParams attribute.save(); } -static void geo_node_attribute_fill_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - geometry_set = geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (geometry_set.has<MeshComponent>()) { fill_attribute(geometry_set.get_component_for_write<MeshComponent>(), params); @@ -146,18 +146,20 @@ static void geo_node_attribute_fill_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_fill_cc void register_node_type_geo_attribute_fill() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_fill_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_FILL, "Attribute Fill", NODE_CLASS_ATTRIBUTE, 0); - node_type_init(&ntype, blender::nodes::geo_node_attribute_fill_init); - node_type_update(&ntype, blender::nodes::geo_node_attribute_fill_update); - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_fill_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_fill_layout; - ntype.declare = blender::nodes::geo_node_attribute_fill_declare; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_map_range.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc index 2c70157d586..8ebcf34ad0b 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_map_range.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc @@ -22,9 +22,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_map_range_cc { -static void geo_node_attribute_map_range_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Attribute")); @@ -49,7 +49,7 @@ static void fn_attribute_map_range_layout(uiLayout *layout, bContext *UNUSED(C), uiItemR(layout, ptr, "interpolation_type", 0, "", ICON_NONE); } -static void geo_node_attribute_map_range_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeAttributeMapRange *data = (NodeAttributeMapRange *)MEM_callocN(sizeof(NodeAttributeMapRange), __func__); @@ -58,7 +58,7 @@ static void geo_node_attribute_map_range_init(bNodeTree *UNUSED(ntree), bNode *n node->storage = data; } -static void geo_node_attribute_map_range_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeAttributeMapRange &node_storage = *(NodeAttributeMapRange *)node->storage; @@ -399,7 +399,7 @@ static void map_range_attribute(GeometryComponent &component, const GeoNodeExecP attribute_result.save(); } -static void geo_node_attribute_map_range_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -416,20 +416,22 @@ static void geo_node_attribute_map_range_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_map_range_cc void register_node_type_geo_attribute_map_range() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_map_range_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_MAP_RANGE, "Attribute Map Range", NODE_CLASS_ATTRIBUTE, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_map_range_exec; - node_type_init(&ntype, blender::nodes::geo_node_attribute_map_range_init); - node_type_update(&ntype, blender::nodes::geo_node_attribute_map_range_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeAttributeMapRange", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_attribute_map_range_declare; - ntype.draw_buttons = blender::nodes::fn_attribute_map_range_layout; + ntype.declare = file_ns::node_declare; + ntype.draw_buttons = file_ns::fn_attribute_map_range_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_math.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc index 193db7355f9..e0a829b4100 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_math.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc @@ -25,9 +25,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_math_cc { -static void geo_node_attribute_math_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("A")); @@ -100,7 +100,7 @@ static bool operation_use_input_b(const NodeMathOperation operation) return false; } -static void geo_node_attribute_math_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { bNode *node = (bNode *)ptr->data; NodeAttributeMath *node_storage = (NodeAttributeMath *)node->storage; @@ -119,7 +119,7 @@ static void geo_node_attribute_math_layout(uiLayout *layout, bContext *UNUSED(C) } } -static void geo_node_attribute_math_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeAttributeMath *data = (NodeAttributeMath *)MEM_callocN(sizeof(NodeAttributeMath), __func__); @@ -130,7 +130,10 @@ static void geo_node_attribute_math_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen) +static void geo_node_math_label(const bNodeTree *UNUSED(ntree), + const bNode *node, + char *label, + int maxlen) { NodeAttributeMath &node_storage = *(NodeAttributeMath *)node->storage; const char *name; @@ -141,7 +144,7 @@ static void geo_node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *lab BLI_strncpy(label, IFACE_(name), maxlen); } -static void geo_node_attribute_math_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeAttributeMath &node_storage = *(NodeAttributeMath *)node->storage; NodeMathOperation operation = static_cast<NodeMathOperation>(node_storage.operation); @@ -278,11 +281,11 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP attribute_result.save(); } -static void geo_node_attribute_math_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - geometry_set = geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (geometry_set.has<MeshComponent>()) { attribute_math_calc(geometry_set.get_component_for_write<MeshComponent>(), params); @@ -297,20 +300,22 @@ static void geo_node_attribute_math_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_math_cc void register_node_type_geo_attribute_math() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_math_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_MATH, "Attribute Math", NODE_CLASS_ATTRIBUTE, 0); - ntype.declare = blender::nodes::geo_node_attribute_math_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_math_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_math_layout; - node_type_label(&ntype, blender::nodes::geo_node_math_label); - node_type_update(&ntype, blender::nodes::geo_node_attribute_math_update); - node_type_init(&ntype, blender::nodes::geo_node_attribute_math_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + ntype.labelfunc = file_ns::geo_node_math_label; + node_type_update(&ntype, file_ns::node_update); + node_type_init(&ntype, file_ns::node_init); node_type_storage( &ntype, "NodeAttributeMath", node_free_standard_storage, node_copy_standard_storage); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_mix.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc index 6c7f2313633..4a110e9690a 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_mix.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc @@ -25,9 +25,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_mix_cc { -static void geo_node_mix_attribute_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Factor")); @@ -48,7 +48,7 @@ static void geo_node_mix_attribute_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_mix_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -59,7 +59,7 @@ static void geo_node_attribute_mix_layout(uiLayout *layout, bContext *UNUSED(C), uiItemR(col, ptr, "input_type_b", 0, IFACE_("B"), ICON_NONE); } -static void geo_node_attribute_mix_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeAttributeMix *data = (NodeAttributeMix *)MEM_callocN(sizeof(NodeAttributeMix), "attribute mix node"); @@ -70,7 +70,7 @@ static void geo_node_attribute_mix_init(bNodeTree *UNUSED(ntree), bNode *node) node->storage = data; } -static void geo_node_attribute_mix_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeAttributeMix *node_storage = (NodeAttributeMix *)node->storage; update_attribute_input_socket_availabilities( @@ -222,11 +222,11 @@ static void attribute_mix_calc(GeometryComponent &component, const GeoNodeExecPa attribute_result.save(); } -static void geo_node_attribute_mix_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - geometry_set = geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (geometry_set.has<MeshComponent>()) { attribute_mix_calc(geometry_set.get_component_for_write<MeshComponent>(), params); @@ -241,19 +241,21 @@ static void geo_node_attribute_mix_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_mix_cc void register_node_type_geo_attribute_mix() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_mix_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_MIX, "Attribute Mix", NODE_CLASS_ATTRIBUTE, 0); - node_type_init(&ntype, blender::nodes::geo_node_attribute_mix_init); - node_type_update(&ntype, blender::nodes::geo_node_attribute_mix_update); - ntype.declare = blender::nodes::geo_node_mix_attribute_declare; - ntype.draw_buttons = blender::nodes::geo_node_attribute_mix_layout; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.declare = file_ns::node_declare; + ntype.draw_buttons = file_ns::node_layout; node_type_storage( &ntype, "NodeAttributeMix", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_mix_exec; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_proximity.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc index 0122f9b7598..080bf38a740 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_proximity.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc @@ -26,9 +26,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_proximity_cc { -static void geo_node_attribute_proximity_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Geometry>(N_("Target")); @@ -37,14 +37,12 @@ static void geo_node_attribute_proximity_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_proximity_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "target_geometry_element", 0, "", ICON_NONE); } -static void geo_attribute_proximity_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryAttributeProximity *node_storage = (NodeGeometryAttributeProximity *)MEM_callocN( sizeof(NodeGeometryAttributeProximity), __func__); @@ -203,16 +201,16 @@ static void attribute_calc_proximity(GeometryComponent &component, } } -static void geo_node_attribute_proximity_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); GeometrySet geometry_set_target = params.extract_input<GeometrySet>("Target"); - geometry_set = geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); /* This isn't required. This node should be rewritten to handle instances * for the target geometry set. However, the generic BVH API complicates this. */ - geometry_set_target = geometry_set_realize_instances(geometry_set_target); + geometry_set_target = geometry::realize_instances_legacy(geometry_set_target); if (geometry_set.has<MeshComponent>()) { attribute_calc_proximity( @@ -230,22 +228,24 @@ static void geo_node_attribute_proximity_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_proximity_cc void register_node_type_geo_legacy_attribute_proximity() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_proximity_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_PROXIMITY, "Attribute Proximity", NODE_CLASS_ATTRIBUTE, 0); - node_type_init(&ntype, blender::nodes::geo_attribute_proximity_init); + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryAttributeProximity", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_attribute_proximity_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_proximity_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_proximity_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_randomize.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc index f8d9dcdaf87..ab2bc7b379c 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_randomize.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc @@ -25,7 +25,41 @@ namespace blender::nodes { -static void geo_node_legacy_attribute_randomize_declare(NodeDeclarationBuilder &b) +Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &component, + const AttributeDomain domain) +{ + const int domain_size = component.attribute_domain_size(domain); + + /* Hash the reserved name attribute "id" as a (hopefully) stable seed for each point. */ + GVArray hash_attribute = component.attribute_try_get_for_read("id", domain); + Array<uint32_t> hashes(domain_size); + if (hash_attribute) { + BLI_assert(hashes.size() == hash_attribute.size()); + const CPPType &cpp_type = hash_attribute.type(); + BLI_assert(cpp_type.is_hashable()); + GVArray_GSpan items{hash_attribute}; + threading::parallel_for(hashes.index_range(), 512, [&](IndexRange range) { + for (const int i : range) { + hashes[i] = cpp_type.hash(items[i]); + } + }); + } + else { + /* If there is no "id" attribute for per-point variation, just create it here. */ + RandomNumberGenerator rng(0); + for (const int i : hashes.index_range()) { + hashes[i] = rng.get_uint32(); + } + } + + return hashes; +} + +} // namespace blender::nodes + +namespace blender::nodes::node_geo_legacy_attribute_randomize_cc { + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Attribute")); @@ -39,15 +73,13 @@ static void geo_node_legacy_attribute_randomize_declare(NodeDeclarationBuilder & b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_legacy_attribute_random_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); } -static void geo_node_legacy_attribute_randomize_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeAttributeRandomize *data = (NodeAttributeRandomize *)MEM_callocN( sizeof(NodeAttributeRandomize), __func__); @@ -57,7 +89,7 @@ static void geo_node_legacy_attribute_randomize_init(bNodeTree *UNUSED(tree), bN node->storage = data; } -static void geo_node_legacy_attribute_randomize_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { bNodeSocket *sock_min_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 2); bNodeSocket *sock_max_vector = sock_min_vector->next; @@ -174,36 +206,6 @@ static void randomize_attribute_bool(MutableSpan<bool> span, }); } -Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &component, - const AttributeDomain domain) -{ - const int domain_size = component.attribute_domain_size(domain); - - /* Hash the reserved name attribute "id" as a (hopefully) stable seed for each point. */ - GVArray hash_attribute = component.attribute_try_get_for_read("id", domain); - Array<uint32_t> hashes(domain_size); - if (hash_attribute) { - BLI_assert(hashes.size() == hash_attribute.size()); - const CPPType &cpp_type = hash_attribute.type(); - BLI_assert(cpp_type.is_hashable()); - GVArray_GSpan items{hash_attribute}; - threading::parallel_for(hashes.index_range(), 512, [&](IndexRange range) { - for (const int i : range) { - hashes[i] = cpp_type.hash(items[i]); - } - }); - } - else { - /* If there is no "id" attribute for per-point variation, just create it here. */ - RandomNumberGenerator rng(0); - for (const int i : hashes.index_range()) { - hashes[i] = rng.get_uint32(); - } - } - - return hashes; -} - static AttributeDomain get_result_domain(const GeometryComponent &component, const GeoNodeExecParams ¶ms, const StringRef name) @@ -280,12 +282,12 @@ static void randomize_attribute_on_component(GeometryComponent &component, attribute.save(); } -static void geo_node_legacy_random_attribute_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); const std::string attribute_name = params.get_input<std::string>("Attribute"); if (attribute_name.empty()) { - params.set_output("Geometry", geometry_set); + params.set_default_remaining_outputs(); return; } const int seed = params.get_input<int>("Seed"); @@ -294,7 +296,7 @@ static void geo_node_legacy_random_attribute_exec(GeoNodeExecParams params) const GeometryNodeAttributeRandomizeMode operation = static_cast<GeometryNodeAttributeRandomizeMode>(storage.operation); - geometry_set = geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (geometry_set.has<MeshComponent>()) { randomize_attribute_on_component(geometry_set.get_component_for_write<MeshComponent>(), @@ -324,20 +326,22 @@ static void geo_node_legacy_random_attribute_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_randomize_cc void register_node_type_geo_legacy_attribute_randomize() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_randomize_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_RANDOMIZE, "Attribute Randomize", NODE_CLASS_ATTRIBUTE, 0); - node_type_init(&ntype, blender::nodes::geo_node_legacy_attribute_randomize_init); - node_type_update(&ntype, blender::nodes::geo_node_legacy_attribute_randomize_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); - ntype.declare = blender::nodes::geo_node_legacy_attribute_randomize_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_legacy_random_attribute_exec; - ntype.draw_buttons = blender::nodes::geo_node_legacy_attribute_random_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; node_type_storage( &ntype, "NodeAttributeRandomize", node_free_standard_storage, node_copy_standard_storage); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_sample_texture.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc index 9748ca3f2ad..bc18cb32e73 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_sample_texture.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc @@ -28,9 +28,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_sample_texture_cc { -static void geo_node_attribute_sample_texture_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Texture>(N_("Texture")).hide_label(); @@ -100,11 +100,11 @@ static void execute_on_component(GeometryComponent &component, const GeoNodeExec attribute_out.save(); } -static void geo_node_attribute_sample_texture_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - geometry_set = geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (geometry_set.has<MeshComponent>()) { execute_on_component(geometry_set.get_component_for_write<MeshComponent>(), params); @@ -119,10 +119,12 @@ static void geo_node_attribute_sample_texture_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_sample_texture_cc void register_node_type_geo_sample_texture() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_sample_texture_cc; + static bNodeType ntype; geo_node_type_base(&ntype, @@ -131,7 +133,7 @@ void register_node_type_geo_sample_texture() NODE_CLASS_ATTRIBUTE, 0); node_type_size_preset(&ntype, NODE_SIZE_LARGE); - ntype.declare = blender::nodes::geo_node_attribute_sample_texture_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_sample_texture_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc index bfc69780bf6..c5aac118baf 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc @@ -19,9 +19,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_separate_xyz_cc { -static void geo_node_attribute_separate_xyz_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Vector")); @@ -32,16 +32,14 @@ static void geo_node_attribute_separate_xyz_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_separate_xyz_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); uiItemR(layout, ptr, "input_type", 0, IFACE_("Type"), ICON_NONE); } -static void geo_node_attribute_separate_xyz_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeAttributeSeparateXYZ *data = (NodeAttributeSeparateXYZ *)MEM_callocN( sizeof(NodeAttributeSeparateXYZ), __func__); @@ -49,7 +47,7 @@ static void geo_node_attribute_separate_xyz_init(bNodeTree *UNUSED(tree), bNode node->storage = data; } -static void geo_node_attribute_separate_xyz_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeAttributeSeparateXYZ *node_storage = (NodeAttributeSeparateXYZ *)node->storage; update_attribute_input_socket_availabilities( @@ -132,11 +130,11 @@ static void separate_attribute(GeometryComponent &component, const GeoNodeExecPa } } -static void geo_node_attribute_separate_xyz_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - geometry_set = geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (geometry_set.has<MeshComponent>()) { separate_attribute(geometry_set.get_component_for_write<MeshComponent>(), params); @@ -151,10 +149,12 @@ static void geo_node_attribute_separate_xyz_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_separate_xyz_cc void register_node_type_geo_attribute_separate_xyz() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_separate_xyz_cc; + static bNodeType ntype; geo_node_type_base(&ntype, @@ -162,12 +162,12 @@ void register_node_type_geo_attribute_separate_xyz() "Attribute Separate XYZ", NODE_CLASS_ATTRIBUTE, 0); - ntype.declare = blender::nodes::geo_node_attribute_separate_xyz_declare; - node_type_init(&ntype, blender::nodes::geo_node_attribute_separate_xyz_init); - node_type_update(&ntype, blender::nodes::geo_node_attribute_separate_xyz_update); + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeAttributeSeparateXYZ", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_separate_xyz_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_separate_xyz_layout; + 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/legacy/node_geo_attribute_transfer.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc index b8827f82efc..686edc80f62 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_transfer.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc @@ -29,9 +29,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_transfer_cc { -static void geo_node_attribute_transfer_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Geometry>(N_("Source Geometry")); @@ -40,9 +40,7 @@ static void geo_node_attribute_transfer_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_transfer_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -50,7 +48,7 @@ static void geo_node_attribute_transfer_layout(uiLayout *layout, uiItemR(layout, ptr, "mapping", 0, IFACE_("Mapping"), ICON_NONE); } -static void geo_node_attribute_transfer_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryAttributeTransfer *data = (NodeGeometryAttributeTransfer *)MEM_callocN( sizeof(NodeGeometryAttributeTransfer), __func__); @@ -405,7 +403,7 @@ static void transfer_attribute_nearest(const GeometrySet &src_geometry, data_type); for (const int i : IndexRange(tot_samples)) { if (pointcloud_distances_sq[i] < mesh_distances_sq[i]) { - /* Point-cloud point is closer. */ + /* Point cloud point is closer. */ const int index = pointcloud_indices[i]; pointcloud_src_attribute.varray.get(index, buffer); dst_attribute->set_by_relocate(i, buffer); @@ -477,7 +475,7 @@ static void transfer_attribute(const GeoNodeExecParams ¶ms, } } -static void geo_node_attribute_transfer_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet dst_geometry_set = params.extract_input<GeometrySet>("Geometry"); GeometrySet src_geometry_set = params.extract_input<GeometrySet>("Source Geometry"); @@ -485,12 +483,12 @@ static void geo_node_attribute_transfer_exec(GeoNodeExecParams params) const std::string dst_attribute_name = params.extract_input<std::string>("Destination"); if (src_attribute_name.empty() || dst_attribute_name.empty()) { - params.set_output("Geometry", dst_geometry_set); + params.set_default_remaining_outputs(); return; } - dst_geometry_set = bke::geometry_set_realize_instances(dst_geometry_set); - src_geometry_set = bke::geometry_set_realize_instances(src_geometry_set); + dst_geometry_set = geometry::realize_instances_legacy(dst_geometry_set); + src_geometry_set = geometry::realize_instances_legacy(src_geometry_set); if (dst_geometry_set.has<MeshComponent>()) { transfer_attribute(params, @@ -510,21 +508,23 @@ static void geo_node_attribute_transfer_exec(GeoNodeExecParams params) params.set_output("Geometry", dst_geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_transfer_cc void register_node_type_geo_legacy_attribute_transfer() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_transfer_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER, "Attribute Transfer", NODE_CLASS_ATTRIBUTE, 0); - node_type_init(&ntype, blender::nodes::geo_node_attribute_transfer_init); + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryAttributeTransfer", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_attribute_transfer_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_transfer_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_transfer_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_math.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc index e7fdd0f2eef..68051e81f57 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_math.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc @@ -26,9 +26,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_vector_math_cc { -static void geo_node_attribute_vector_math_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("A")); @@ -66,9 +66,7 @@ static bool operation_use_input_c(const NodeVectorMathOperation operation) NODE_VECTOR_MATH_MULTIPLY_ADD); } -static void geo_node_attribute_vector_math_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { bNode *node = (bNode *)ptr->data; const NodeAttributeVectorMath &node_storage = *(NodeAttributeVectorMath *)node->storage; @@ -103,7 +101,7 @@ static CustomDataType operation_get_read_type_c(const NodeVectorMathOperation op return CD_PROP_FLOAT3; } -static void geo_node_attribute_vector_math_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeAttributeVectorMath *data = (NodeAttributeVectorMath *)MEM_callocN( sizeof(NodeAttributeVectorMath), __func__); @@ -152,8 +150,8 @@ static CustomDataType operation_get_result_type(const NodeVectorMathOperation op return CD_PROP_FLOAT3; } -static void geo_node_vector_math_label(bNodeTree *UNUSED(ntree), - bNode *node, +static void geo_node_vector_math_label(const bNodeTree *UNUSED(ntree), + const bNode *node, char *label, int maxlen) { @@ -166,7 +164,7 @@ static void geo_node_vector_math_label(bNodeTree *UNUSED(ntree), BLI_snprintf(label, maxlen, IFACE_("Vector %s"), IFACE_(name)); } -static void geo_node_attribute_vector_math_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { const NodeAttributeVectorMath *node_storage = (NodeAttributeVectorMath *)node->storage; const NodeVectorMathOperation operation = (const NodeVectorMathOperation)node_storage->operation; @@ -531,11 +529,11 @@ static void attribute_vector_math_calc(GeometryComponent &component, attribute_result.save(); } -static void geo_node_attribute_vector_math_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - geometry_set = geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (geometry_set.has<MeshComponent>()) { attribute_vector_math_calc(geometry_set.get_component_for_write<MeshComponent>(), params); @@ -551,10 +549,12 @@ static void geo_node_attribute_vector_math_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_vector_math_cc void register_node_type_geo_attribute_vector_math() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_vector_math_cc; + static bNodeType ntype; geo_node_type_base(&ntype, @@ -562,12 +562,12 @@ void register_node_type_geo_attribute_vector_math() "Attribute Vector Math", NODE_CLASS_ATTRIBUTE, 0); - ntype.declare = blender::nodes::geo_node_attribute_vector_math_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_vector_math_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_vector_math_layout; - node_type_label(&ntype, blender::nodes::geo_node_vector_math_label); - node_type_update(&ntype, blender::nodes::geo_node_attribute_vector_math_update); - node_type_init(&ntype, blender::nodes::geo_node_attribute_vector_math_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + ntype.labelfunc = file_ns::geo_node_vector_math_label; + node_type_update(&ntype, file_ns::node_update); + node_type_init(&ntype, file_ns::node_init); node_type_storage( &ntype, "NodeAttributeVectorMath", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc index a6cd24ed72d..1ef50e69775 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc @@ -21,9 +21,9 @@ #include "UI_interface.h" #include "UI_resources.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_vector_rotate_cc { -static void geo_node_attribute_vector_rotate_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Vector")); @@ -42,9 +42,7 @@ static void geo_node_attribute_vector_rotate_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_vector_rotate_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { bNode *node = (bNode *)ptr->data; const NodeAttributeVectorRotate &node_storage = *(NodeAttributeVectorRotate *)node->storage; @@ -70,7 +68,7 @@ static void geo_node_attribute_vector_rotate_layout(uiLayout *layout, } } -static void geo_node_attribute_vector_rotate_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { const NodeAttributeVectorRotate *node_storage = (NodeAttributeVectorRotate *)node->storage; const GeometryNodeAttributeVectorRotateMode mode = (const GeometryNodeAttributeVectorRotateMode) @@ -112,7 +110,7 @@ static float3 vector_rotate_around_axis(const float3 vector, return result + center; } -static void geo_node_attribute_vector_rotate_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeAttributeVectorRotate *node_storage = (NodeAttributeVectorRotate *)MEM_callocN( sizeof(NodeAttributeVectorRotate), __func__); @@ -309,11 +307,11 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon attribute_result.save(); } -static void geo_node_attribute_vector_rotate_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - geometry_set = geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (geometry_set.has<MeshComponent>()) { execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>()); @@ -328,10 +326,12 @@ static void geo_node_attribute_vector_rotate_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_vector_rotate_cc void register_node_type_geo_attribute_vector_rotate() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_vector_rotate_cc; + static bNodeType ntype; geo_node_type_base(&ntype, @@ -339,13 +339,13 @@ void register_node_type_geo_attribute_vector_rotate() "Attribute Vector Rotate", NODE_CLASS_ATTRIBUTE, 0); - node_type_update(&ntype, blender::nodes::geo_node_attribute_vector_rotate_update); - node_type_init(&ntype, blender::nodes::geo_node_attribute_vector_rotate_init); + node_type_update(&ntype, file_ns::node_update); + node_type_init(&ntype, file_ns::node_init); node_type_size(&ntype, 165, 100, 600); node_type_storage( &ntype, "NodeAttributeVectorRotate", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_vector_rotate_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_vector_rotate_layout; - ntype.declare = blender::nodes::geo_node_attribute_vector_rotate_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_endpoints.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc index 67c8200a9c2..e61dee4bee1 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_endpoints.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc @@ -25,9 +25,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_curve_endpoints_cc { -static void geo_node_curve_endpoints_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_output<decl::Geometry>(N_("Start Points")); @@ -145,15 +145,14 @@ static void copy_endpoint_attributes(Span<SplinePtr> splines, }); } -static void geo_node_curve_endpoints_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - geometry_set = bke::geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (!geometry_set.has_curve()) { - params.set_output("Start Points", GeometrySet()); - params.set_output("End Points", GeometrySet()); + params.set_default_remaining_outputs(); return; } @@ -168,8 +167,7 @@ static void geo_node_curve_endpoints_exec(GeoNodeExecParams params) const int total_size = offsets.size(); if (total_size == 0) { - params.set_output("Start Points", GeometrySet()); - params.set_output("End Points", GeometrySet()); + params.set_default_remaining_outputs(); return; } @@ -206,16 +204,18 @@ static void geo_node_curve_endpoints_exec(GeoNodeExecParams params) params.set_output("End Points", std::move(end_result)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_curve_endpoints_cc void register_node_type_geo_legacy_curve_endpoints() { + namespace file_ns = blender::nodes::node_geo_legacy_curve_endpoints_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_CURVE_ENDPOINTS, "Curve Endpoints", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_endpoints_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_endpoints_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc index bc4612e2b8b..7c550495b41 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_reverse.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc @@ -20,19 +20,19 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_curve_reverse_cc { -static void geo_node_curve_reverse_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")); b.add_input<decl::String>(N_("Selection")); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_reverse_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); - geometry_set = bke::geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (!geometry_set.has_curve()) { params.set_output("Curve", geometry_set); return; @@ -58,14 +58,16 @@ static void geo_node_curve_reverse_exec(GeoNodeExecParams params) params.set_output("Curve", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_curve_reverse_cc void register_node_type_geo_legacy_curve_reverse() { + namespace file_ns = blender::nodes::node_geo_legacy_curve_reverse_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_CURVE_REVERSE, "Curve Reverse", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_reverse_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_reverse_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc index 40d827ae141..c702e9ff686 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc @@ -23,24 +23,22 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_curve_select_by_handle_type_cc { -static void geo_node_select_by_handle_type_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Selection")); b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_curve_select_by_handle_type_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE); } -static void geo_node_curve_select_by_handle_type_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveSelectHandles *data = (NodeGeometryCurveSelectHandles *)MEM_callocN( sizeof(NodeGeometryCurveSelectHandles), __func__); @@ -94,7 +92,7 @@ static void select_curve_by_handle_type(const CurveEval &curve, }); } -static void geo_node_select_by_handle_type_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryCurveSelectHandles *storage = (const NodeGeometryCurveSelectHandles *)params.node().storage; @@ -103,7 +101,7 @@ static void geo_node_select_by_handle_type_exec(GeoNodeExecParams params) const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)storage->mode; GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - geometry_set = bke::geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>(); const CurveEval *curve = curve_component.get_for_read(); @@ -121,10 +119,12 @@ static void geo_node_select_by_handle_type_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_curve_select_by_handle_type_cc void register_node_type_geo_legacy_select_by_handle_type() { + namespace file_ns = blender::nodes::node_geo_legacy_curve_select_by_handle_type_cc; + static bNodeType ntype; geo_node_type_base(&ntype, @@ -132,14 +132,14 @@ void register_node_type_geo_legacy_select_by_handle_type() "Select by Handle Type", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_select_by_handle_type_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_select_by_handle_type_exec; - node_type_init(&ntype, blender::nodes::geo_node_curve_select_by_handle_type_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryCurveSelectHandles", node_free_standard_storage, node_copy_standard_storage); - ntype.draw_buttons = blender::nodes::geo_node_curve_select_by_handle_type_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc index b92db315d94..1e476d01148 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_set_handles.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc @@ -21,24 +21,22 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_curve_set_handles_cc { -static void geo_node_curve_set_handles_decalre(NodeDeclarationBuilder &b) +static void node_decalre(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")); b.add_input<decl::String>(N_("Selection")); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_set_handles_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE); } -static void geo_node_curve_set_handles_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveSetHandles *data = (NodeGeometryCurveSetHandles *)MEM_callocN( sizeof(NodeGeometryCurveSetHandles), __func__); @@ -64,7 +62,7 @@ static BezierSpline::HandleType handle_type_from_input_type(GeometryNodeCurveHan return BezierSpline::HandleType::Auto; } -static void geo_node_curve_set_handles_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryCurveSetHandles *node_storage = (NodeGeometryCurveSetHandles *)params.node().storage; @@ -72,7 +70,7 @@ static void geo_node_curve_set_handles_exec(GeoNodeExecParams params) const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)node_storage->mode; GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); - geometry_set = bke::geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (!geometry_set.has_curve()) { params.set_output("Curve", geometry_set); return; @@ -124,21 +122,23 @@ static void geo_node_curve_set_handles_exec(GeoNodeExecParams params) params.set_output("Curve", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_curve_set_handles_cc void register_node_type_geo_legacy_curve_set_handles() { + namespace file_ns = blender::nodes::node_geo_legacy_curve_set_handles_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_CURVE_SET_HANDLES, "Set Handle Type", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_set_handles_decalre; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_set_handles_exec; - node_type_init(&ntype, blender::nodes::geo_node_curve_set_handles_init); + ntype.declare = file_ns::node_decalre; + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryCurveSetHandles", node_free_standard_storage, node_copy_standard_storage); - ntype.draw_buttons = blender::nodes::geo_node_curve_set_handles_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc index 36d4519cac3..f3599f4328f 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_spline_type.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc @@ -23,23 +23,21 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_curve_spline_type_cc { -static void geo_node_legacy_curve_spline_type_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")); b.add_input<decl::String>(N_("Selection")); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_legacy_curve_spline_type_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "spline_type", 0, "", ICON_NONE); } -static void geo_node_legacy_curve_spline_type_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveSplineType *data = (NodeGeometryCurveSplineType *)MEM_callocN( sizeof(NodeGeometryCurveSplineType), __func__); @@ -238,14 +236,14 @@ static SplinePtr convert_to_nurbs(const Spline &input) return {}; } -static void geo_node_legacy_curve_spline_type_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryCurveSplineType *storage = (const NodeGeometryCurveSplineType *)params.node().storage; const GeometryNodeSplineType output_type = (const GeometryNodeSplineType)storage->spline_type; GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); - geometry_set = bke::geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (!geometry_set.has_curve()) { params.set_output("Curve", geometry_set); return; @@ -282,21 +280,23 @@ static void geo_node_legacy_curve_spline_type_exec(GeoNodeExecParams params) params.set_output("Curve", GeometrySet::create_with_curve(new_curve.release())); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_curve_spline_type_cc void register_node_type_geo_legacy_curve_spline_type() { + namespace file_ns = blender::nodes::node_geo_legacy_curve_spline_type_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_CURVE_SPLINE_TYPE, "Set Spline Type", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_legacy_curve_spline_type_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_legacy_curve_spline_type_exec; - node_type_init(&ntype, blender::nodes::geo_node_legacy_curve_spline_type_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryCurveSplineType", node_free_standard_storage, node_copy_standard_storage); - ntype.draw_buttons = blender::nodes::geo_node_legacy_curve_spline_type_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc index 603547a8e69..9878402dd35 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc @@ -25,9 +25,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_curve_subdivide_cc { -static void geo_node_curve_subdivide_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Cuts")); @@ -35,14 +35,14 @@ static void geo_node_curve_subdivide_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_curve_subdivide_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); uiItemR(layout, ptr, "cuts_type", 0, IFACE_("Cuts"), ICON_NONE); } -static void geo_node_curve_subdivide_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveSubdivide *data = (NodeGeometryCurveSubdivide *)MEM_callocN( sizeof(NodeGeometryCurveSubdivide), __func__); @@ -51,7 +51,7 @@ static void geo_node_curve_subdivide_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_curve_subdivide_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryPointTranslate &node_storage = *(NodeGeometryPointTranslate *)node->storage; @@ -347,11 +347,11 @@ static std::unique_ptr<CurveEval> subdivide_curve(const CurveEval &input_curve, return output_curve; } -static void geo_node_subdivide_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - geometry_set = bke::geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (!geometry_set.has_curve()) { params.set_output("Geometry", geometry_set); @@ -370,22 +370,24 @@ static void geo_node_subdivide_exec(GeoNodeExecParams params) params.set_output("Geometry", GeometrySet::create_with_curve(output_curve.release())); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_curve_subdivide_cc void register_node_type_geo_legacy_curve_subdivide() { + namespace file_ns = blender::nodes::node_geo_legacy_curve_subdivide_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_CURVE_SUBDIVIDE, "Curve Subdivide", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_subdivide_declare; - ntype.draw_buttons = blender::nodes::geo_node_curve_subdivide_layout; + ntype.declare = file_ns::node_declare; + ntype.draw_buttons = file_ns::node_layout; node_type_storage(&ntype, "NodeGeometryCurveSubdivide", node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_curve_subdivide_init); - node_type_update(&ntype, blender::nodes::geo_node_curve_subdivide_update); - ntype.geometry_node_execute = blender::nodes::geo_node_subdivide_exec; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc index ab51258cc69..3bd03f3cee0 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_to_points.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc @@ -28,7 +28,59 @@ namespace blender::nodes { -static void geo_node_curve_to_points_declare(NodeDeclarationBuilder &b) +static GMutableSpan create_attribute_and_retrieve_span(PointCloudComponent &points, + const AttributeIDRef &attribute_id, + const CustomDataType data_type) +{ + points.attribute_try_create(attribute_id, ATTR_DOMAIN_POINT, data_type, AttributeInitDefault()); + WriteAttributeLookup attribute = points.attribute_try_get_for_write(attribute_id); + BLI_assert(attribute); + return attribute.varray.get_internal_span(); +} + +template<typename T> +static MutableSpan<T> create_attribute_and_retrieve_span(PointCloudComponent &points, + const AttributeIDRef &attribute_id) +{ + GMutableSpan attribute = create_attribute_and_retrieve_span( + points, attribute_id, bke::cpp_type_to_custom_data_type(CPPType::get<T>())); + return attribute.typed<T>(); +} + +CurveToPointsResults curve_to_points_create_result_attributes(PointCloudComponent &points, + const CurveEval &curve) +{ + CurveToPointsResults attributes; + + attributes.result_size = points.attribute_domain_size(ATTR_DOMAIN_POINT); + + attributes.positions = create_attribute_and_retrieve_span<float3>(points, "position"); + attributes.radii = create_attribute_and_retrieve_span<float>(points, "radius"); + attributes.tilts = create_attribute_and_retrieve_span<float>(points, "tilt"); + + /* Because of the invariants of the curve component, we use the attributes of the + * first spline as a representative for the attribute meta data all splines. */ + curve.splines().first()->attributes.foreach_attribute( + [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { + attributes.point_attributes.add_new( + attribute_id, + create_attribute_and_retrieve_span(points, attribute_id, meta_data.data_type)); + return true; + }, + ATTR_DOMAIN_POINT); + + attributes.tangents = create_attribute_and_retrieve_span<float3>(points, "tangent"); + attributes.normals = create_attribute_and_retrieve_span<float3>(points, "normal"); + attributes.rotations = create_attribute_and_retrieve_span<float3>(points, "rotation"); + + return attributes; +} + +} // namespace blender::nodes + +namespace blender::nodes::node_geo_legacy_curve_to_points_cc { + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Int>(N_("Count")).default_value(10).min(2).max(100000); @@ -36,12 +88,12 @@ static void geo_node_curve_to_points_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_curve_to_points_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); } -static void geo_node_curve_to_points_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveToPoints *data = (NodeGeometryCurveToPoints *)MEM_callocN( sizeof(NodeGeometryCurveToPoints), __func__); @@ -50,7 +102,7 @@ static void geo_node_curve_to_points_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_curve_to_points_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryCurveToPoints &node_storage = *(NodeGeometryCurveToPoints *)node->storage; const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode; @@ -114,54 +166,6 @@ static Array<int> calculate_spline_point_offsets(GeoNodeExecParams ¶ms, return {0}; } -static GMutableSpan create_attribute_and_retrieve_span(PointCloudComponent &points, - const AttributeIDRef &attribute_id, - const CustomDataType data_type) -{ - points.attribute_try_create(attribute_id, ATTR_DOMAIN_POINT, data_type, AttributeInitDefault()); - WriteAttributeLookup attribute = points.attribute_try_get_for_write(attribute_id); - BLI_assert(attribute); - return attribute.varray.get_internal_span(); -} - -template<typename T> -static MutableSpan<T> create_attribute_and_retrieve_span(PointCloudComponent &points, - const AttributeIDRef &attribute_id) -{ - GMutableSpan attribute = create_attribute_and_retrieve_span( - points, attribute_id, bke::cpp_type_to_custom_data_type(CPPType::get<T>())); - return attribute.typed<T>(); -} - -CurveToPointsResults curve_to_points_create_result_attributes(PointCloudComponent &points, - const CurveEval &curve) -{ - CurveToPointsResults attributes; - - attributes.result_size = points.attribute_domain_size(ATTR_DOMAIN_POINT); - - attributes.positions = create_attribute_and_retrieve_span<float3>(points, "position"); - attributes.radii = create_attribute_and_retrieve_span<float>(points, "radius"); - attributes.tilts = create_attribute_and_retrieve_span<float>(points, "tilt"); - - /* Because of the invariants of the curve component, we use the attributes of the - * first spline as a representative for the attribute meta data all splines. */ - curve.splines().first()->attributes.foreach_attribute( - [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { - attributes.point_attributes.add_new( - attribute_id, - create_attribute_and_retrieve_span(points, attribute_id, meta_data.data_type)); - return true; - }, - ATTR_DOMAIN_POINT); - - attributes.tangents = create_attribute_and_retrieve_span<float3>(points, "tangent"); - attributes.normals = create_attribute_and_retrieve_span<float3>(points, "normal"); - attributes.rotations = create_attribute_and_retrieve_span<float3>(points, "rotation"); - - return attributes; -} - /** * TODO: For non-poly splines, this has double copies that could be avoided as part * of a general look at optimizing uses of #Spline::interpolate_to_evaluated. @@ -286,13 +290,13 @@ static void copy_spline_domain_attributes(const CurveComponent &curve_component, }); } -static void geo_node_curve_to_points_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { NodeGeometryCurveToPoints &node_storage = *(NodeGeometryCurveToPoints *)params.node().storage; const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode; GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - geometry_set = bke::geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (!geometry_set.has_curve()) { params.set_output("Geometry", GeometrySet()); @@ -340,21 +344,23 @@ static void geo_node_curve_to_points_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(result)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_curve_to_points_cc void register_node_type_geo_legacy_curve_to_points() { + namespace file_ns = blender::nodes::node_geo_legacy_curve_to_points_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_CURVE_TO_POINTS, "Curve to Points", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_to_points_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_to_points_exec; - ntype.draw_buttons = blender::nodes::geo_node_curve_to_points_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; node_type_storage( &ntype, "NodeGeometryCurveToPoints", node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_curve_to_points_init); - node_type_update(&ntype, blender::nodes::geo_node_curve_to_points_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc index f62a22d7934..abd75e710ae 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_delete_geometry.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc @@ -29,23 +29,23 @@ using blender::bke::CustomDataAttributes; /* Code from the mask modifier in MOD_mask.cc. */ -extern void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh, - Mesh &dst_mesh, - blender::Span<int> vertex_map); -extern void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, - Mesh &dst_mesh, - blender::Span<int> vertex_map, - blender::Span<int> edge_map); -extern void copy_masked_polys_to_new_mesh(const Mesh &src_mesh, - Mesh &dst_mesh, - blender::Span<int> vertex_map, - blender::Span<int> edge_map, - blender::Span<int> masked_poly_indices, - blender::Span<int> new_loop_starts); - -namespace blender::nodes { - -static void geo_node_delete_geometry_declare(NodeDeclarationBuilder &b) +void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + blender::Span<int> vertex_map); +void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + blender::Span<int> vertex_map, + blender::Span<int> edge_map); +void copy_masked_polys_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + blender::Span<int> vertex_map, + blender::Span<int> edge_map, + blender::Span<int> masked_poly_indices, + blender::Span<int> new_loop_starts); + +namespace blender::nodes::node_geo_legacy_delete_geometry_cc { + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Selection")); @@ -627,10 +627,10 @@ static void delete_mesh_selection(MeshComponent &component, component.replace(mesh_out); } -static void geo_node_delete_geometry_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - geometry_set = bke::geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); const bool invert = params.extract_input<bool>("Invert"); const std::string selection_name = params.extract_input<std::string>("Selection"); @@ -662,16 +662,18 @@ static void geo_node_delete_geometry_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(out_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_delete_geometry_cc void register_node_type_geo_legacy_delete_geometry() { + namespace file_ns = blender::nodes::node_geo_legacy_delete_geometry_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_DELETE_GEOMETRY, "Delete Geometry", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_delete_geometry_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_delete_geometry_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc index 8f2bf05d2b4..c046fda4686 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_edge_split.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc @@ -22,9 +22,9 @@ extern "C" { Mesh *doEdgeSplit(const Mesh *mesh, EdgeSplitModifierData *emd); } -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_edge_split_cc { -static void geo_node_edge_split_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Bool>(N_("Edge Angle")).default_value(true); @@ -37,11 +37,11 @@ static void geo_node_edge_split_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_edge_split_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - geometry_set = geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (!geometry_set.has_mesh()) { params.set_output("Geometry", std::move(geometry_set)); @@ -76,14 +76,16 @@ static void geo_node_edge_split_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_edge_split_cc void register_node_type_geo_legacy_edge_split() { + namespace file_ns = blender::nodes::node_geo_legacy_edge_split_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_LEGACY_EDGE_SPLIT, "Edge Split", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_edge_split_exec; - ntype.declare = blender::nodes::geo_node_edge_split_declare; + 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/legacy/node_geo_material_assign.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc index 58374679a95..88e8374f5d6 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_material_assign.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc @@ -24,9 +24,9 @@ #include "BKE_material.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_material_assign_cc { -static void geo_node_legacy_material_assign_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Material>(N_("Material")).hide_label(true); @@ -59,14 +59,14 @@ static void assign_material_to_faces(Mesh &mesh, const VArray<bool> &face_mask, } } -static void geo_node_legacy_material_assign_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Material *material = params.extract_input<Material *>("Material"); const std::string mask_name = params.extract_input<std::string>("Selection"); GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - geometry_set = geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (geometry_set.has<MeshComponent>()) { MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>(); @@ -81,15 +81,17 @@ static void geo_node_legacy_material_assign_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_material_assign_cc void register_node_type_geo_legacy_material_assign() { + namespace file_ns = blender::nodes::node_geo_legacy_material_assign_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_MATERIAL_ASSIGN, "Material Assign", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_legacy_material_assign_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_legacy_material_assign_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc index 321de24a3dc..2ff7410f3f6 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_mesh_to_curve.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc @@ -18,23 +18,23 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_mesh_to_curve_cc { -static void geo_node_legacy_mesh_to_curve_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Mesh")); b.add_input<decl::String>(N_("Selection")); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); - geometry_set = bke::geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (!geometry_set.has_mesh()) { - params.set_output("Curve", GeometrySet()); + params.set_default_remaining_outputs(); return; } @@ -55,7 +55,7 @@ static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params) } if (selected_edge_indices.size() == 0) { - params.set_output("Curve", GeometrySet()); + params.set_default_remaining_outputs(); return; } @@ -65,15 +65,17 @@ static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params) params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_mesh_to_curve_cc void register_node_type_geo_legacy_mesh_to_curve() { + namespace file_ns = blender::nodes::node_geo_legacy_mesh_to_curve_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_MESH_TO_CURVE, "Mesh to Curve", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_legacy_mesh_to_curve_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_legacy_mesh_to_curve_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc index 4e13a490d89..2451a7447ec 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_distribute.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc @@ -36,11 +36,11 @@ #include "node_geometry_util.hh" -using blender::bke::GeometryInstanceGroup; +namespace blender::nodes::node_geo_legacy_point_distribute_cc { -namespace blender::nodes { +using blender::bke::GeometryInstanceGroup; -static void geo_node_point_distribute_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Float>(N_("Distance Min")).min(0.0f).max(100000.0f).subtype(PROP_DISTANCE); @@ -54,9 +54,7 @@ static void geo_node_point_distribute_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_point_distribute_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "distribute_method", 0, "", ICON_NONE); } @@ -541,7 +539,7 @@ static void distribute_points_poisson_disk(Span<GeometryInstanceGroup> set_group } } -static void geo_node_point_distribute_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -554,14 +552,14 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params) "Density Attribute"); if (density <= 0.0f) { - params.set_output("Geometry", GeometrySet()); + params.set_default_remaining_outputs(); return; } Vector<GeometryInstanceGroup> set_groups; geometry_set_gather_instances(geometry_set, set_groups); if (set_groups.is_empty()) { - params.set_output("Geometry", GeometrySet()); + params.set_default_remaining_outputs(); return; } @@ -575,7 +573,7 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params) if (set_groups.is_empty()) { params.error_message_add(NodeWarningType::Error, TIP_("Input geometry must contain a mesh")); - params.set_output("Geometry", GeometrySet()); + params.set_default_remaining_outputs(); return; } @@ -625,7 +623,7 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params) } if (final_points_len == 0) { - params.set_output("Geometry", GeometrySet()); + params.set_default_remaining_outputs(); return; } @@ -655,17 +653,19 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set_out)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_point_distribute_cc void register_node_type_geo_point_distribute() { + namespace file_ns = blender::nodes::node_geo_legacy_point_distribute_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_POINT_DISTRIBUTE, "Point Distribute", NODE_CLASS_GEOMETRY, 0); - node_type_update(&ntype, blender::nodes::node_point_distribute_update); - ntype.declare = blender::nodes::geo_node_point_distribute_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_point_distribute_exec; - ntype.draw_buttons = blender::nodes::geo_node_point_distribute_layout; + node_type_update(&ntype, file_ns::node_point_distribute_update); + 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/legacy/node_geo_point_instance.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc index 713971941ea..8915a58feb1 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc @@ -24,9 +24,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_point_instance_cc { -static void geo_node_point_instance_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Object>(N_("Object")).hide_label(); @@ -36,7 +36,7 @@ static void geo_node_point_instance_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_point_instance_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "instance_type", 0, "", ICON_NONE); if (RNA_enum_get(ptr, "instance_type") == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION) { @@ -44,7 +44,7 @@ static void geo_node_point_instance_layout(uiLayout *layout, bContext *UNUSED(C) } } -static void geo_node_point_instance_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryPointInstance *data = (NodeGeometryPointInstance *)MEM_callocN( sizeof(NodeGeometryPointInstance), __func__); @@ -53,7 +53,7 @@ static void geo_node_point_instance_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_point_instance_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { bNodeSocket *object_socket = (bNodeSocket *)BLI_findlink(&node->inputs, 1); bNodeSocket *collection_socket = object_socket->next; @@ -173,6 +173,9 @@ static void add_instances_from_component(InstancesComponent &instances, const AttributeDomain domain = ATTR_DOMAIN_POINT; const int domain_size = src_geometry.attribute_domain_size(domain); + if (domain_size == 0) { + return; + } VArray<float3> positions = src_geometry.attribute_get_for_read<float3>( "position", domain, {0, 0, 0}); @@ -186,7 +189,9 @@ static void add_instances_from_component(InstancesComponent &instances, instances.resize(start_len + domain_size); MutableSpan<int> handles = instances.instance_reference_handles().slice(start_len, domain_size); MutableSpan<float4x4> transforms = instances.instance_transforms().slice(start_len, domain_size); - MutableSpan<int> instance_ids = instances.instance_ids_ensure().slice(start_len, domain_size); + OutputAttribute_Typed<int> instance_id_attribute = + instances.attribute_try_get_for_output_only<int>("id", ATTR_DOMAIN_INSTANCE); + MutableSpan<int> instance_ids = instance_id_attribute.as_span(); /* Skip all of the randomness handling if there is only a single possible instance * (anything except for collection mode with "Whole Collection" turned off). */ @@ -213,16 +218,18 @@ static void add_instances_from_component(InstancesComponent &instances, } }); } + + instance_id_attribute.save(); } -static void geo_node_point_instance_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); GeometrySet geometry_set_out; /* TODO: This node should be able to instance on the input instances component * rather than making the entire input geometry set real. */ - geometry_set = geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); const Vector<InstanceReference> possible_references = get_instance_references(params); if (possible_references.is_empty()) { @@ -255,20 +262,22 @@ static void geo_node_point_instance_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set_out)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_point_instance_cc void register_node_type_geo_point_instance() { + namespace file_ns = blender::nodes::node_geo_legacy_point_instance_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_POINT_INSTANCE, "Point Instance", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_point_instance_init); + node_type_init(&ntype, file_ns::node_init); node_type_storage( &ntype, "NodeGeometryPointInstance", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_point_instance_declare; - ntype.draw_buttons = blender::nodes::geo_node_point_instance_layout; - node_type_update(&ntype, blender::nodes::geo_node_point_instance_update); - ntype.geometry_node_execute = blender::nodes::geo_node_point_instance_exec; + ntype.declare = file_ns::node_declare; + ntype.draw_buttons = file_ns::node_layout; + node_type_update(&ntype, file_ns::node_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_rotate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc index ab1d68bfe4f..a0a7674797a 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_rotate.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc @@ -21,9 +21,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_point_rotate_cc { -static void geo_node_point_rotate_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Axis")); @@ -37,7 +37,7 @@ static void geo_node_point_rotate_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_point_rotate_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { NodeGeometryRotatePoints *storage = (NodeGeometryRotatePoints *)((bNode *)ptr->data)->storage; @@ -57,7 +57,7 @@ static void geo_node_point_rotate_layout(uiLayout *layout, bContext *UNUSED(C), } } -static void geo_node_point_rotate_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryRotatePoints *node_storage = (NodeGeometryRotatePoints *)MEM_callocN( sizeof(NodeGeometryRotatePoints), __func__); @@ -71,7 +71,7 @@ static void geo_node_point_rotate_init(bNodeTree *UNUSED(ntree), bNode *node) node->storage = node_storage; } -static void geo_node_point_rotate_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryRotatePoints *node_storage = (NodeGeometryRotatePoints *)node->storage; update_attribute_input_socket_availabilities( @@ -199,11 +199,11 @@ static void point_rotate_on_component(GeometryComponent &component, rotation_attribute.save(); } -static void geo_node_point_rotate_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - geometry_set = geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (geometry_set.has<MeshComponent>()) { point_rotate_on_component(geometry_set.get_component_for_write<MeshComponent>(), params); @@ -218,19 +218,21 @@ static void geo_node_point_rotate_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_point_rotate_cc void register_node_type_geo_point_rotate() { + namespace file_ns = blender::nodes::node_geo_legacy_point_rotate_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_LEGACY_POINT_ROTATE, "Point Rotate", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_point_rotate_init); - node_type_update(&ntype, blender::nodes::geo_node_point_rotate_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeGeometryRotatePoints", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_point_rotate_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_point_rotate_exec; - ntype.draw_buttons = blender::nodes::geo_node_point_rotate_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_scale.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc index 8d6345ce6b1..d38df124979 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_scale.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc @@ -21,9 +21,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_point_scale_cc { -static void geo_node_point_scale_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Factor")); @@ -34,14 +34,14 @@ static void geo_node_point_scale_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_point_scale_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); uiItemR(layout, ptr, "input_type", 0, IFACE_("Type"), ICON_NONE); } -static void geo_node_point_scale_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryPointScale *data = (NodeGeometryPointScale *)MEM_callocN( sizeof(NodeGeometryPointScale), __func__); @@ -50,7 +50,7 @@ static void geo_node_point_scale_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_point_scale_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryPointScale &node_storage = *(NodeGeometryPointScale *)node->storage; @@ -101,11 +101,11 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co scale_attribute.save(); } -static void geo_node_point_scale_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - geometry_set = geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (geometry_set.has<MeshComponent>()) { execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>()); @@ -120,20 +120,22 @@ static void geo_node_point_scale_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_point_scale_cc void register_node_type_geo_point_scale() { + namespace file_ns = blender::nodes::node_geo_legacy_point_scale_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_LEGACY_POINT_SCALE, "Point Scale", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_point_scale_declare; - node_type_init(&ntype, blender::nodes::geo_node_point_scale_init); - node_type_update(&ntype, blender::nodes::geo_node_point_scale_update); + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeGeometryPointScale", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_point_scale_exec; - ntype.draw_buttons = blender::nodes::geo_node_point_scale_layout; + 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/legacy/node_geo_point_separate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc index 3539fe2de64..9260928b311 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_separate.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc @@ -25,14 +25,6 @@ namespace blender::nodes { -static void geo_node_point_instance_declare(NodeDeclarationBuilder &b) -{ - b.add_input<decl::Geometry>(N_("Geometry")); - b.add_input<decl::String>(N_("Mask")); - b.add_output<decl::Geometry>(N_("Geometry 1")); - b.add_output<decl::Geometry>(N_("Geometry 2")); -} - template<typename T> static void copy_data_based_on_mask(Span<T> data, Span<bool> masks, @@ -78,6 +70,18 @@ void copy_point_attributes_based_on_mask(const GeometryComponent &in_component, } } +} // namespace blender::nodes + +namespace blender::nodes::node_geo_legacy_point_separate_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Geometry>(N_("Geometry")); + b.add_input<decl::String>(N_("Mask")); + b.add_output<decl::Geometry>(N_("Geometry 1")); + b.add_output<decl::Geometry>(N_("Geometry 2")); +} + static void create_component_points(GeometryComponent &component, const int total) { switch (component.type()) { @@ -133,7 +137,7 @@ static GeometrySet separate_geometry_set(const GeometrySet &set_in, return set_out; } -static void geo_node_point_separate_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { bool wait_for_inputs = false; wait_for_inputs |= params.lazy_require_input("Geometry"); @@ -146,7 +150,7 @@ static void geo_node_point_separate_exec(GeoNodeExecParams params) /* TODO: This is not necessary-- the input geometry set can be read only, * but it must be rewritten to handle instance groups. */ - geometry_set = geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (params.lazy_output_is_required("Geometry 1")) { params.set_output("Geometry 1", @@ -158,16 +162,18 @@ static void geo_node_point_separate_exec(GeoNodeExecParams params) } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_point_separate_cc void register_node_type_geo_point_separate() { + namespace file_ns = blender::nodes::node_geo_legacy_point_separate_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_POINT_SEPARATE, "Point Separate", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_point_instance_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_point_separate_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.geometry_node_execute_supports_laziness = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_translate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc index 3b2959beb86..c70478182ec 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_translate.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc @@ -19,9 +19,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_point_translate_cc { -static void geo_node_point_translate_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Translation")); @@ -29,7 +29,7 @@ static void geo_node_point_translate_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_point_translate_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -53,11 +53,11 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co position_attribute.save(); } -static void geo_node_point_translate_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - geometry_set = geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (geometry_set.has<MeshComponent>()) { execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>()); @@ -72,7 +72,7 @@ static void geo_node_point_translate_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -static void geo_node_point_translate_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryPointTranslate *data = (NodeGeometryPointTranslate *)MEM_callocN( sizeof(NodeGeometryPointTranslate), __func__); @@ -81,7 +81,7 @@ static void geo_node_point_translate_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_point_translate_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryPointTranslate &node_storage = *(NodeGeometryPointTranslate *)node->storage; @@ -89,22 +89,24 @@ static void geo_node_point_translate_update(bNodeTree *ntree, bNode *node) *ntree, *node, "Translation", (GeometryNodeAttributeInputMode)node_storage.input_type); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_point_translate_cc void register_node_type_geo_point_translate() { + namespace file_ns = blender::nodes::node_geo_legacy_point_translate_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_POINT_TRANSLATE, "Point Translate", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_point_translate_init); - node_type_update(&ntype, blender::nodes::geo_node_point_translate_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage(&ntype, "NodeGeometryPointTranslate", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_point_translate_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_point_translate_exec; - ntype.draw_buttons = blender::nodes::geo_node_point_translate_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc index d465a9ab1a8..ec1ab67b530 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_points_to_volume.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc @@ -28,9 +28,9 @@ #include "UI_interface.h" #include "UI_resources.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_points_to_volume_cc { -static void geo_node_points_to_volume_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Float>(N_("Density")).default_value(1.0f).min(0.0f); @@ -41,9 +41,7 @@ static void geo_node_points_to_volume_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_points_to_volume_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -51,7 +49,7 @@ static void geo_node_points_to_volume_layout(uiLayout *layout, uiItemR(layout, ptr, "input_type_radius", 0, IFACE_("Radius"), ICON_NONE); } -static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)MEM_callocN( sizeof(NodeGeometryPointsToVolume), __func__); @@ -65,7 +63,7 @@ static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node STRNCPY(radius_attribute_socket_value->value, "radius"); } -static void geo_node_points_to_volume_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)node->storage; bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size"); @@ -244,13 +242,13 @@ static void initialize_volume_component_from_points(const GeometrySet &geometry_ } #endif -static void geo_node_points_to_volume_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set_in = params.extract_input<GeometrySet>("Geometry"); GeometrySet geometry_set_out; /* TODO: Read-only access to instances should be supported here, for now they are made real. */ - geometry_set_in = geometry_set_realize_instances(geometry_set_in); + geometry_set_in = geometry::realize_instances_legacy(geometry_set_in); #ifdef WITH_OPENVDB initialize_volume_component_from_points(geometry_set_in, geometry_set_out, params); @@ -259,10 +257,12 @@ static void geo_node_points_to_volume_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set_out)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_points_to_volume_cc void register_node_type_geo_legacy_points_to_volume() { + namespace file_ns = blender::nodes::node_geo_legacy_points_to_volume_cc; + static bNodeType ntype; geo_node_type_base( @@ -272,10 +272,10 @@ void register_node_type_geo_legacy_points_to_volume() node_free_standard_storage, node_copy_standard_storage); node_type_size(&ntype, 170, 120, 700); - node_type_init(&ntype, blender::nodes::geo_node_points_to_volume_init); - node_type_update(&ntype, blender::nodes::geo_node_points_to_volume_update); - ntype.declare = blender::nodes::geo_node_points_to_volume_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_points_to_volume_exec; - ntype.draw_buttons = blender::nodes::geo_node_points_to_volume_layout; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc index 5aa683ca232..599ffd617a5 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_raycast.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc @@ -24,9 +24,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_raycast_cc { -static void geo_node_raycast_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Geometry>(N_("Target Geometry")); @@ -47,7 +47,7 @@ static void geo_node_raycast_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_raycast_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -56,7 +56,7 @@ static void geo_node_raycast_layout(uiLayout *layout, bContext *UNUSED(C), Point uiItemR(layout, ptr, "input_type_ray_length", 0, IFACE_("Ray Length"), ICON_NONE); } -static void geo_node_raycast_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryRaycast *data = (NodeGeometryRaycast *)MEM_callocN(sizeof(NodeGeometryRaycast), __func__); @@ -65,7 +65,7 @@ static void geo_node_raycast_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_raycast_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryRaycast *node_storage = (NodeGeometryRaycast *)node->storage; update_attribute_input_socket_availabilities( @@ -272,7 +272,7 @@ static void raycast_from_points(const GeoNodeExecParams ¶ms, } } -static void geo_node_raycast_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); GeometrySet target_geometry_set = params.extract_input<GeometrySet>("Target Geometry"); @@ -285,8 +285,8 @@ static void geo_node_raycast_exec(GeoNodeExecParams params) const Array<std::string> hit_names = {params.extract_input<std::string>("Target Attribute")}; const Array<std::string> hit_output_names = {params.extract_input<std::string>("Hit Attribute")}; - geometry_set = bke::geometry_set_realize_instances(geometry_set); - target_geometry_set = bke::geometry_set_realize_instances(target_geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); + target_geometry_set = geometry::realize_instances_legacy(target_geometry_set); static const Array<GeometryComponentType> types = { GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}; @@ -307,20 +307,22 @@ static void geo_node_raycast_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_raycast_cc void register_node_type_geo_legacy_raycast() { + namespace file_ns = blender::nodes::node_geo_legacy_raycast_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_LEGACY_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY, 0); node_type_size_preset(&ntype, NODE_SIZE_LARGE); - node_type_init(&ntype, blender::nodes::geo_node_raycast_init); - node_type_update(&ntype, blender::nodes::geo_node_raycast_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeGeometryRaycast", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_raycast_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_raycast_exec; - ntype.draw_buttons = blender::nodes::geo_node_raycast_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_select_by_material.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc index a8d6f33a5fd..b61ba5ff67e 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_select_by_material.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc @@ -26,9 +26,9 @@ #include "BKE_material.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_select_by_material_cc { -static void geo_node_legacy_select_by_material_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Material>(N_("Material")).hide_label(); @@ -54,13 +54,13 @@ static void select_mesh_by_material(const Mesh &mesh, }); } -static void geo_node_legacy_select_by_material_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Material *material = params.extract_input<Material *>("Material"); const std::string selection_name = params.extract_input<std::string>("Selection"); GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - geometry_set = geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (geometry_set.has<MeshComponent>()) { MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>(); @@ -78,15 +78,17 @@ static void geo_node_legacy_select_by_material_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_select_by_material_cc void register_node_type_geo_legacy_select_by_material() { + namespace file_ns = blender::nodes::node_geo_legacy_select_by_material_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_SELECT_BY_MATERIAL, "Select by Material", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_legacy_select_by_material_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_legacy_select_by_material_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc index 295cd05fd01..819ffb2c20c 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_subdivision_surface.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc @@ -23,9 +23,9 @@ #include "UI_resources.h" #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_subdivision_surface_cc { -static void geo_node_subdivision_surface_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Int>(N_("Level")).default_value(1).min(0).max(6); @@ -33,9 +33,7 @@ static void geo_node_subdivision_surface_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_subdivision_surface_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { #ifdef WITH_OPENSUBDIV uiLayoutSetPropSep(layout, true); @@ -47,7 +45,7 @@ static void geo_node_subdivision_surface_layout(uiLayout *layout, #endif } -static void geo_node_subdivision_surface_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometrySubdivisionSurface *data = (NodeGeometrySubdivisionSurface *)MEM_callocN( sizeof(NodeGeometrySubdivisionSurface), __func__); @@ -56,11 +54,11 @@ static void geo_node_subdivision_surface_init(bNodeTree *UNUSED(ntree), bNode *n node->storage = data; } -static void geo_node_subdivision_surface_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - geometry_set = geometry_set_realize_instances(geometry_set); + geometry_set = geometry::realize_instances_legacy(geometry_set); if (!geometry_set.has_mesh()) { params.set_output("Geometry", geometry_set); @@ -126,18 +124,20 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_subdivision_surface_cc void register_node_type_geo_legacy_subdivision_surface() { + namespace file_ns = blender::nodes::node_geo_legacy_subdivision_surface_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_subdivision_surface_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_subdivision_surface_exec; - ntype.draw_buttons = blender::nodes::geo_node_subdivision_surface_layout; - node_type_init(&ntype, blender::nodes::geo_node_subdivision_surface_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + node_type_init(&ntype, file_ns::node_init); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); node_type_storage(&ntype, "NodeGeometrySubdivisionSurface", diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc index 6a52b943967..acff0be7126 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_volume_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc @@ -35,9 +35,9 @@ #include "UI_interface.h" #include "UI_resources.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_volume_to_mesh_cc { -static void geo_node_volume_to_mesh_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Density")); @@ -48,14 +48,14 @@ static void geo_node_volume_to_mesh_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_volume_to_mesh_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); uiItemR(layout, ptr, "resolution_mode", 0, IFACE_("Resolution"), ICON_NONE); } -static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)MEM_callocN( sizeof(NodeGeometryVolumeToMesh), __func__); @@ -68,7 +68,7 @@ static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node) node->storage = data; } -static void geo_node_volume_to_mesh_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)node->storage; @@ -140,7 +140,7 @@ static void create_mesh_from_volume(GeometrySet &geometry_set_in, #endif /* WITH_OPENVDB */ -static void geo_node_volume_to_mesh_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set_in = params.extract_input<GeometrySet>("Geometry"); GeometrySet geometry_set_out; @@ -155,21 +155,23 @@ static void geo_node_volume_to_mesh_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set_out); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_volume_to_mesh_cc void register_node_type_geo_legacy_volume_to_mesh() { + namespace file_ns = blender::nodes::node_geo_legacy_volume_to_mesh_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_VOLUME_TO_MESH, "Volume to Mesh", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_volume_to_mesh_declare; + ntype.declare = file_ns::node_declare; node_type_storage( &ntype, "NodeGeometryVolumeToMesh", node_free_standard_storage, node_copy_standard_storage); node_type_size(&ntype, 170, 120, 700); - node_type_init(&ntype, blender::nodes::geo_node_volume_to_mesh_init); - node_type_update(&ntype, blender::nodes::geo_node_volume_to_mesh_update); - ntype.geometry_node_execute = blender::nodes::geo_node_volume_to_mesh_exec; - ntype.draw_buttons = blender::nodes::geo_node_volume_to_mesh_layout; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + 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_attribute_capture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc index 19deb761948..be0baa706af 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc @@ -19,11 +19,15 @@ #include "BKE_attribute_math.hh" +#include "NOD_socket_search_link.hh" + #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_attribute_capture_cc { + +NODE_STORAGE_FUNCS(NodeGeometryAttributeCapture) -static void geo_node_attribute_capture_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Vector>(N_("Value")).supports_field(); @@ -40,9 +44,7 @@ static void geo_node_attribute_capture_declare(NodeDeclarationBuilder &b) b.add_output<decl::Int>(N_("Attribute"), "Attribute_004").field_source(); } -static void geo_node_attribute_capture_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -50,7 +52,7 @@ static void geo_node_attribute_capture_layout(uiLayout *layout, uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); } -static void geo_node_attribute_capture_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryAttributeCapture *data = (NodeGeometryAttributeCapture *)MEM_callocN( sizeof(NodeGeometryAttributeCapture), __func__); @@ -60,10 +62,9 @@ static void geo_node_attribute_capture_init(bNodeTree *UNUSED(tree), bNode *node node->storage = data; } -static void geo_node_attribute_capture_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { - const NodeGeometryAttributeCapture &storage = *(const NodeGeometryAttributeCapture *) - node->storage; + const NodeGeometryAttributeCapture &storage = node_storage(*node); const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); bNodeSocket *socket_value_geometry = (bNodeSocket *)node->inputs.first; @@ -93,6 +94,33 @@ static void geo_node_attribute_capture_update(bNodeTree *ntree, bNode *node) nodeSetSocketAvailability(ntree, out_socket_value_int32, data_type == CD_PROP_INT32); } +static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) +{ + const NodeDeclaration &declaration = *params.node_type().fixed_declaration; + search_link_ops_for_declarations(params, declaration.inputs().take_front(1)); + search_link_ops_for_declarations(params, declaration.outputs().take_front(1)); + + const bNodeType &node_type = params.node_type(); + const std::optional<CustomDataType> type = node_data_type_to_custom_data_type( + (eNodeSocketDatatype)params.other_socket().type); + if (type && *type != CD_PROP_STRING) { + if (params.in_out() == SOCK_OUT) { + params.add_item(IFACE_("Attribute"), [node_type, type](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node(node_type); + node_storage(node).data_type = *type; + params.update_and_connect_available_socket(node, "Attribute"); + }); + } + else { + params.add_item(IFACE_("Value"), [node_type, type](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node(node_type); + node_storage(node).data_type = *type; + params.update_and_connect_available_socket(node, "Value"); + }); + } + } +} + static void try_capture_field_on_geometry(GeometryComponent &component, const AttributeIDRef &attribute_id, const AttributeDomain domain, @@ -113,13 +141,11 @@ static void try_capture_field_on_geometry(GeometryComponent &component, output_attribute.save(); } -static void geo_node_attribute_capture_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - const bNode &node = params.node(); - const NodeGeometryAttributeCapture &storage = *(const NodeGeometryAttributeCapture *) - node.storage; + const NodeGeometryAttributeCapture &storage = node_storage(params.node()); const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain); @@ -147,16 +173,27 @@ static void geo_node_attribute_capture_exec(GeoNodeExecParams params) WeakAnonymousAttributeID anonymous_id{"Attribute"}; const CPPType &type = field.cpp_type(); - static const Array<GeometryComponentType> types = { - GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}; - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { - for (const GeometryComponentType type : types) { - if (geometry_set.has(type)) { - GeometryComponent &component = geometry_set.get_component_for_write(type); - try_capture_field_on_geometry(component, anonymous_id.get(), domain, field); - } + /* Run on the instances component separately to only affect the top level of instances. */ + if (domain == ATTR_DOMAIN_INSTANCE) { + if (geometry_set.has_instances()) { + GeometryComponent &component = geometry_set.get_component_for_write( + GEO_COMPONENT_TYPE_INSTANCES); + try_capture_field_on_geometry(component, anonymous_id.get(), domain, field); } - }); + } + else { + static const Array<GeometryComponentType> types = { + GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}; + + geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + for (const GeometryComponentType type : types) { + if (geometry_set.has(type)) { + GeometryComponent &component = geometry_set.get_component_for_write(type); + try_capture_field_on_geometry(component, anonymous_id.get(), domain, field); + } + } + }); + } GField output_field{std::make_shared<bke::AnonymousAttributeFieldInput>( std::move(anonymous_id), type, params.attribute_producer_name())}; @@ -189,10 +226,12 @@ static void geo_node_attribute_capture_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_attribute_capture_cc void register_node_type_geo_attribute_capture() { + namespace file_ns = blender::nodes::node_geo_attribute_capture_cc; + static bNodeType ntype; geo_node_type_base( @@ -201,10 +240,11 @@ void register_node_type_geo_attribute_capture() "NodeGeometryAttributeCapture", node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_attribute_capture_init); - node_type_update(&ntype, blender::nodes::geo_node_attribute_capture_update); - ntype.declare = blender::nodes::geo_node_attribute_capture_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_capture_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_capture_layout; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + ntype.gather_link_search_ops = file_ns::node_gather_link_searches; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc new file mode 100644 index 00000000000..d6662e4e637 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc @@ -0,0 +1,155 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_attribute_domain_size_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Geometry>("Geometry"); + b.add_output<decl::Int>("Point Count").make_available([](bNode &node) { + node.custom1 = GEO_COMPONENT_TYPE_MESH; + }); + b.add_output<decl::Int>("Edge Count").make_available([](bNode &node) { + node.custom1 = GEO_COMPONENT_TYPE_MESH; + }); + b.add_output<decl::Int>("Face Count").make_available([](bNode &node) { + node.custom1 = GEO_COMPONENT_TYPE_MESH; + }); + b.add_output<decl::Int>("Face Corner Count").make_available([](bNode &node) { + node.custom1 = GEO_COMPONENT_TYPE_MESH; + }); + b.add_output<decl::Int>("Spline Count").make_available([](bNode &node) { + node.custom1 = GEO_COMPONENT_TYPE_CURVE; + }); + b.add_output<decl::Int>("Instance Count").make_available([](bNode &node) { + node.custom1 = GEO_COMPONENT_TYPE_INSTANCES; + }); +} + +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "component", 0, "", ICON_NONE); +} + +static void node_init(bNodeTree *UNUSED(tree), bNode *node) +{ + node->custom1 = GEO_COMPONENT_TYPE_MESH; +} + +static void node_update(bNodeTree *ntree, bNode *node) +{ + bNodeSocket *point_socket = (bNodeSocket *)node->outputs.first; + bNodeSocket *edge_socket = point_socket->next; + bNodeSocket *face_socket = edge_socket->next; + bNodeSocket *face_corner_socket = face_socket->next; + bNodeSocket *spline_socket = face_corner_socket->next; + bNodeSocket *instances_socket = spline_socket->next; + + nodeSetSocketAvailability(ntree, + point_socket, + ELEM(node->custom1, + GEO_COMPONENT_TYPE_MESH, + GEO_COMPONENT_TYPE_CURVE, + GEO_COMPONENT_TYPE_POINT_CLOUD)); + nodeSetSocketAvailability(ntree, edge_socket, node->custom1 == GEO_COMPONENT_TYPE_MESH); + nodeSetSocketAvailability(ntree, face_socket, node->custom1 == GEO_COMPONENT_TYPE_MESH); + nodeSetSocketAvailability(ntree, face_corner_socket, node->custom1 == GEO_COMPONENT_TYPE_MESH); + nodeSetSocketAvailability(ntree, spline_socket, node->custom1 == GEO_COMPONENT_TYPE_CURVE); + nodeSetSocketAvailability( + ntree, instances_socket, node->custom1 == GEO_COMPONENT_TYPE_INSTANCES); +} + +static void node_geo_exec(GeoNodeExecParams params) +{ + GeometryComponentType component = (GeometryComponentType)params.node().custom1; + GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); + + switch (component) { + case GEO_COMPONENT_TYPE_MESH: { + if (geometry_set.has_mesh()) { + const MeshComponent *component = geometry_set.get_component_for_read<MeshComponent>(); + params.set_output("Point Count", component->attribute_domain_size(ATTR_DOMAIN_POINT)); + params.set_output("Edge Count", component->attribute_domain_size(ATTR_DOMAIN_EDGE)); + params.set_output("Face Count", component->attribute_domain_size(ATTR_DOMAIN_FACE)); + params.set_output("Face Corner Count", + component->attribute_domain_size(ATTR_DOMAIN_CORNER)); + } + else { + params.set_default_remaining_outputs(); + } + break; + } + case GEO_COMPONENT_TYPE_CURVE: { + if (geometry_set.has_curve()) { + const CurveComponent *component = geometry_set.get_component_for_read<CurveComponent>(); + params.set_output("Point Count", component->attribute_domain_size(ATTR_DOMAIN_POINT)); + params.set_output("Spline Count", component->attribute_domain_size(ATTR_DOMAIN_CURVE)); + } + else { + params.set_default_remaining_outputs(); + } + break; + } + case GEO_COMPONENT_TYPE_POINT_CLOUD: { + if (geometry_set.has_pointcloud()) { + const PointCloudComponent *component = + geometry_set.get_component_for_read<PointCloudComponent>(); + params.set_output("Point Count", component->attribute_domain_size(ATTR_DOMAIN_POINT)); + } + else { + params.set_default_remaining_outputs(); + } + break; + } + case GEO_COMPONENT_TYPE_INSTANCES: { + if (geometry_set.has_instances()) { + const InstancesComponent *component = + geometry_set.get_component_for_read<InstancesComponent>(); + params.set_output("Instance Count", + component->attribute_domain_size(ATTR_DOMAIN_INSTANCE)); + } + else { + params.set_default_remaining_outputs(); + } + break; + } + default: + BLI_assert_unreachable(); + } +} + +} // namespace blender::nodes::node_geo_attribute_domain_size_cc + +void register_node_type_geo_attribute_domain_size() +{ + namespace file_ns = blender::nodes::node_geo_attribute_domain_size_cc; + + static bNodeType ntype; + geo_node_type_base( + &ntype, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, "Domain Size", NODE_CLASS_ATTRIBUTE, 0); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; + ntype.draw_buttons = file_ns::node_layout; + node_type_init(&ntype, file_ns::node_init); + ntype.updatefunc = file_ns::node_update; + + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc index f80b8ccc971..6f26b2c756b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_attribute_remove_cc { -static void geo_node_attribute_remove_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Attribute")).multi_input(); @@ -42,7 +42,7 @@ static void remove_attribute(GeometryComponent &component, } } -static void geo_node_attribute_remove_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); Vector<std::string> attribute_names = params.extract_multi_input<std::string>("Attribute"); @@ -66,15 +66,17 @@ static void geo_node_attribute_remove_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_attribute_remove_cc void register_node_type_geo_attribute_remove() { + namespace file_ns = blender::nodes::node_geo_attribute_remove_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_ATTRIBUTE_REMOVE, "Attribute Remove", NODE_CLASS_ATTRIBUTE, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_remove_exec; - ntype.declare = blender::nodes::geo_node_attribute_remove_declare; + 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_attribute_statistic.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc index d9513332078..b79125d43d1 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc @@ -22,13 +22,16 @@ #include "BLI_math_base_safe.h" +#include "NOD_socket_search_link.hh" + #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_attribute_statistic_cc { -static void geo_node_attribute_statistic_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); + b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value(); b.add_input<decl::Float>(N_("Attribute")).hide_value().supports_field(); b.add_input<decl::Vector>(N_("Attribute"), "Attribute_001").hide_value().supports_field(); @@ -51,24 +54,23 @@ static void geo_node_attribute_statistic_declare(NodeDeclarationBuilder &b) b.add_output<decl::Vector>(N_("Variance"), "Variance_001"); } -static void geo_node_attribute_statistic_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +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); } -static void geo_node_attribute_statistic_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { node->custom1 = CD_PROP_FLOAT; node->custom2 = ATTR_DOMAIN_POINT; } -static void geo_node_attribute_statistic_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { bNodeSocket *socket_geo = (bNodeSocket *)node->inputs.first; - bNodeSocket *socket_float_attr = socket_geo->next; + 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; @@ -112,6 +114,54 @@ static void geo_node_attribute_statistic_update(bNodeTree *ntree, bNode *node) nodeSetSocketAvailability(ntree, socket_vector_variance, data_type == CD_PROP_FLOAT3); } +static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSocket &socket) +{ + switch (socket.type) { + case SOCK_FLOAT: + case SOCK_BOOLEAN: + case SOCK_INT: + return CD_PROP_FLOAT; + case SOCK_VECTOR: + case SOCK_RGBA: + return CD_PROP_FLOAT3; + default: + return {}; + } +} + +static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) +{ + const bNodeType &node_type = params.node_type(); + const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket()); + if (params.in_out() == SOCK_IN) { + if (params.other_socket().type == SOCK_GEOMETRY) { + params.add_item(IFACE_("Geometry"), [node_type](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node(node_type); + params.connect_available_socket(node, "Geometry"); + }); + } + if (type) { + params.add_item(IFACE_("Attribute"), [&](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node(node_type); + node.custom1 = *type; + params.update_and_connect_available_socket(node, "Attribute"); + }); + } + } + else if (type) { + /* Only use the first 8 declarations since we set the type automatically. */ + const NodeDeclaration &declaration = *params.node_type().fixed_declaration; + for (const SocketDeclarationPtr &socket_decl : declaration.outputs().take_front(8)) { + StringRefNull name = socket_decl->name(); + params.add_item(IFACE_(name.c_str()), [node_type, name, type](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node(node_type); + node.custom1 = *type; + params.update_and_connect_available_socket(node, name); + }); + } + } +} + template<typename T> static T compute_sum(const Span<T> data) { return std::accumulate(data.begin(), data.end(), T()); @@ -146,65 +196,40 @@ static float median_of_sorted_span(const Span<float> data) } return median; } -static void set_empty(CustomDataType data_type, GeoNodeExecParams ¶ms) -{ - if (data_type == CD_PROP_FLOAT) { - params.set_output("Mean", 0.0f); - params.set_output("Median", 0.0f); - params.set_output("Sum", 0.0f); - params.set_output("Min", 0.0f); - params.set_output("Max", 0.0f); - params.set_output("Range", 0.0f); - params.set_output("Standard Deviation", 0.0f); - params.set_output("Variance", 0.0f); - } - else if (data_type == CD_PROP_FLOAT3) { - params.set_output("Mean_001", float3{0.0f, 0.0f, 0.0f}); - params.set_output("Median_001", float3{0.0f, 0.0f, 0.0f}); - params.set_output("Sum_001", float3{0.0f, 0.0f, 0.0f}); - params.set_output("Min_001", float3{0.0f, 0.0f, 0.0f}); - params.set_output("Max_001", float3{0.0f, 0.0f, 0.0f}); - params.set_output("Range_001", float3{0.0f, 0.0f, 0.0f}); - params.set_output("Standard Deviation_001", float3{0.0f, 0.0f, 0.0f}); - params.set_output("Variance_001", float3{0.0f, 0.0f, 0.0f}); - } -} -static void geo_node_attribute_statistic_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.get_input<GeometrySet>("Geometry"); - const bNode &node = params.node(); const CustomDataType data_type = static_cast<CustomDataType>(node.custom1); const AttributeDomain domain = static_cast<AttributeDomain>(node.custom2); - - int64_t total_size = 0; Vector<const GeometryComponent *> components = geometry_set.get_components_for_read(); - for (const GeometryComponent *component : components) { - if (component->attribute_domain_supported(domain)) { - total_size += component->attribute_domain_size(domain); - } - } - if (total_size == 0) { - set_empty(data_type, params); - return; - } + const Field<bool> selection_field = params.get_input<Field<bool>>("Selection"); switch (data_type) { case CD_PROP_FLOAT: { const Field<float> input_field = params.get_input<Field<float>>("Attribute"); - Array<float> data = Array<float>(total_size); - int offset = 0; + Vector<float> data; for (const GeometryComponent *component : components) { if (component->attribute_domain_supported(domain)) { GeometryComponentFieldContext field_context{*component, domain}; const int domain_size = component->attribute_domain_size(domain); + fn::FieldEvaluator data_evaluator{field_context, domain_size}; - MutableSpan<float> component_result = data.as_mutable_span().slice(offset, domain_size); - data_evaluator.add_with_destination(input_field, component_result); + data_evaluator.add(input_field); + data_evaluator.set_selection(selection_field); data_evaluator.evaluate(); - offset += domain_size; + const VArray<float> &component_data = data_evaluator.get_evaluated<float>(0); + const IndexMask selection = data_evaluator.get_evaluated_selection_as_mask(); + + const int next_data_index = data.size(); + data.resize(next_data_index + selection.size()); + MutableSpan<float> selected_data = data.as_mutable_span().slice(next_data_index, + selection.size()); + for (const int i : selection.index_range()) { + selected_data[i] = component_data[selection[i]]; + } } } @@ -225,7 +250,7 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params) const bool variance_required = params.output_is_required("Standard Deviation") || params.output_is_required("Variance"); - if (total_size != 0) { + if (data.size() != 0) { if (sort_required) { std::sort(data.begin(), data.end()); median = median_of_sorted_span(data); @@ -236,7 +261,7 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params) } if (sum_required || variance_required) { sum = compute_sum<float>(data); - mean = sum / total_size; + mean = sum / data.size(); if (variance_required) { variance = compute_variance(data, mean); @@ -263,18 +288,26 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params) } case CD_PROP_FLOAT3: { const Field<float3> input_field = params.get_input<Field<float3>>("Attribute_001"); - - Array<float3> data = Array<float3>(total_size); - int offset = 0; + Vector<float3> data; for (const GeometryComponent *component : components) { if (component->attribute_domain_supported(domain)) { GeometryComponentFieldContext field_context{*component, domain}; const int domain_size = component->attribute_domain_size(domain); + fn::FieldEvaluator data_evaluator{field_context, domain_size}; - MutableSpan<float3> component_result = data.as_mutable_span().slice(offset, domain_size); - data_evaluator.add_with_destination(input_field, component_result); + data_evaluator.add(input_field); + data_evaluator.set_selection(selection_field); data_evaluator.evaluate(); - offset += domain_size; + const VArray<float3> &component_data = data_evaluator.get_evaluated<float3>(0); + const IndexMask selection = data_evaluator.get_evaluated_selection_as_mask(); + + const int next_data_index = data.size(); + data.resize(data.size() + selection.size()); + MutableSpan<float3> selected_data = data.as_mutable_span().slice(next_data_index, + selection.size()); + for (const int i : selection.index_range()) { + selected_data[i] = component_data[selection[i]]; + } } } @@ -299,9 +332,9 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params) Array<float> data_y; Array<float> data_z; if (sort_required || variance_required) { - data_x.reinitialize(total_size); - data_y.reinitialize(total_size); - data_z.reinitialize(total_size); + data_x.reinitialize(data.size()); + data_y.reinitialize(data.size()); + data_z.reinitialize(data.size()); for (const int i : data.index_range()) { data_x[i] = data[i].x; data_y[i] = data[i].y; @@ -309,7 +342,7 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params) } } - if (total_size != 0) { + if (data.size() != 0) { if (sort_required) { std::sort(data_x.begin(), data_x.end()); std::sort(data_y.begin(), data_y.end()); @@ -326,7 +359,7 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params) } if (sum_required || variance_required) { sum = compute_sum(data.as_span()); - mean = sum / total_size; + mean = sum / data.size(); if (variance_required) { const float x_variance = compute_variance(data_x, mean.x); @@ -360,19 +393,22 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params) } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_attribute_statistic_cc void register_node_type_geo_attribute_statistic() { + namespace file_ns = blender::nodes::node_geo_attribute_statistic_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_ATTRIBUTE_STATISTIC, "Attribute Statistic", NODE_CLASS_ATTRIBUTE, 0); - ntype.declare = blender::nodes::geo_node_attribute_statistic_declare; - node_type_init(&ntype, blender::nodes::geo_node_attribute_statistic_init); - node_type_update(&ntype, blender::nodes::geo_node_attribute_statistic_update); - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_statistic_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_statistic_layout; + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + 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_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc index dba051fe13d..0947632cc09 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc @@ -23,9 +23,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_boolean_cc { -static void geo_node_boolean_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Mesh 1")) .only_realized_data() @@ -36,12 +36,12 @@ static void geo_node_boolean_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Mesh")); } -static void geo_node_boolean_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); } -static void geo_node_boolean_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { GeometryNodeBooleanOperation operation = (GeometryNodeBooleanOperation)node->custom1; @@ -63,12 +63,12 @@ static void geo_node_boolean_update(bNodeTree *ntree, bNode *node) } } -static void geo_node_boolean_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { node->custom1 = GEO_NODE_BOOLEAN_DIFFERENCE; } -static void geo_node_boolean_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometryNodeBooleanOperation operation = (GeometryNodeBooleanOperation)params.node().custom1; const bool use_self = params.get_input<bool>("Self Intersection"); @@ -119,17 +119,19 @@ static void geo_node_boolean_exec(GeoNodeExecParams params) params.set_output("Mesh", GeometrySet::create_with_mesh(result)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_boolean_cc void register_node_type_geo_boolean() { + namespace file_ns = blender::nodes::node_geo_boolean_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_MESH_BOOLEAN, "Mesh Boolean", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_boolean_declare; - ntype.draw_buttons = blender::nodes::geo_node_boolean_layout; - ntype.updatefunc = blender::nodes::geo_node_boolean_update; - node_type_init(&ntype, blender::nodes::geo_node_boolean_init); - ntype.geometry_node_execute = blender::nodes::geo_node_boolean_exec; + ntype.declare = file_ns::node_declare; + ntype.draw_buttons = file_ns::node_layout; + ntype.updatefunc = file_ns::node_update; + node_type_init(&ntype, file_ns::node_init); + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc index e7c9715934a..da1f9a00c69 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_bounding_box_cc { -static void geo_node_bounding_box_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_output<decl::Geometry>(N_("Bounding Box")); @@ -26,7 +26,7 @@ static void geo_node_bounding_box_declare(NodeDeclarationBuilder &b) b.add_output<decl::Vector>(N_("Max")); } -static void geo_node_bounding_box_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -78,14 +78,16 @@ static void geo_node_bounding_box_exec(GeoNodeExecParams params) } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_bounding_box_cc void register_node_type_geo_bounding_box() { + namespace file_ns = blender::nodes::node_geo_bounding_box_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_BOUNDING_BOX, "Bounding Box", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_bounding_box_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_bounding_box_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc index 503711fedfe..6b8c895879d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc @@ -27,9 +27,11 @@ #include <algorithm> -namespace blender::nodes { +namespace blender::nodes::node_geo_collection_info_cc { -static void geo_node_collection_info_declare(NodeDeclarationBuilder &b) +NODE_STORAGE_FUNCS(NodeGeometryCollectionInfo) + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Collection>(N_("Collection")).hide_label(); b.add_input<decl::Bool>(N_("Separate Children")) @@ -42,12 +44,12 @@ static void geo_node_collection_info_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_collection_info_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "transform_space", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_collection_info_node_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCollectionInfo *data = (NodeGeometryCollectionInfo *)MEM_callocN( sizeof(NodeGeometryCollectionInfo), __func__); @@ -61,14 +63,12 @@ struct InstanceListEntry { float4x4 transform; }; -static void geo_node_collection_info_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Collection *collection = params.get_input<Collection *>("Collection"); - GeometrySet geometry_set_out; - if (collection == nullptr) { - params.set_output("Geometry", geometry_set_out); + params.set_default_remaining_outputs(); return; } const Object *self_object = params.self_object(); @@ -76,15 +76,15 @@ static void geo_node_collection_info_exec(GeoNodeExecParams params) (Object *)self_object); if (is_recursive) { params.error_message_add(NodeWarningType::Error, "Collection contains current object"); - params.set_output("Geometry", geometry_set_out); + params.set_default_remaining_outputs(); return; } - const bNode &bnode = params.node(); - NodeGeometryCollectionInfo *node_storage = (NodeGeometryCollectionInfo *)bnode.storage; - const bool use_relative_transform = (node_storage->transform_space == + const NodeGeometryCollectionInfo &storage = node_storage(params.node()); + const bool use_relative_transform = (storage.transform_space == GEO_NODE_TRANSFORM_SPACE_RELATIVE); + GeometrySet geometry_set_out; InstancesComponent &instances = geometry_set_out.get_component_for_write<InstancesComponent>(); const bool separate_children = params.get_input<bool>("Separate Children"); @@ -155,20 +155,22 @@ static void geo_node_collection_info_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set_out); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_collection_info_cc void register_node_type_geo_collection_info() { + namespace file_ns = blender::nodes::node_geo_collection_info_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_COLLECTION_INFO, "Collection Info", NODE_CLASS_INPUT, 0); - ntype.declare = blender::nodes::geo_node_collection_info_declare; - node_type_init(&ntype, blender::nodes::geo_node_collection_info_node_init); + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::node_node_init); node_type_storage(&ntype, "NodeGeometryCollectionInfo", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_collection_info_exec; - ntype.draw_buttons = blender::nodes::geo_node_collection_info_layout; + 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_common.cc b/source/blender/nodes/geometry/nodes/node_geo_common.cc index 9ebbdd349de..64b7a80bdb4 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_common.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_common.cc @@ -22,7 +22,7 @@ #include "node_common.h" #include "node_geometry_util.hh" -void register_node_type_geo_group(void) +void register_node_type_geo_group() { static bNodeType ntype; @@ -37,7 +37,7 @@ void register_node_type_geo_group(void) node_type_socket_templates(&ntype, nullptr, nullptr); node_type_size(&ntype, 140, 60, 400); - node_type_label(&ntype, node_group_label); + ntype.labelfunc = node_group_label; node_type_group_update(&ntype, node_group_update); nodeRegisterType(&ntype); 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 221fb421ab4..56c1e95bd70 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc @@ -28,9 +28,9 @@ # include "RBI_hull_api.h" #endif -namespace blender::nodes { +namespace blender::nodes::node_geo_convex_hull_cc { -static void geo_node_convex_hull_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_output<decl::Geometry>(N_("Convex Hull")); @@ -296,7 +296,7 @@ static Mesh *convex_hull_from_instances(const GeometrySet &geometry_set) #endif /* WITH_BULLET */ -static void geo_node_convex_hull_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -312,18 +312,20 @@ static void geo_node_convex_hull_exec(GeoNodeExecParams params) #else params.error_message_add(NodeWarningType::Error, TIP_("Disabled, Blender was compiled without Bullet")); - params.set_output("Convex Hull", geometry_set); + params.set_default_remaining_outputs(); #endif /* WITH_BULLET */ } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_convex_hull_cc void register_node_type_geo_convex_hull() { + namespace file_ns = blender::nodes::node_geo_convex_hull_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_CONVEX_HULL, "Convex Hull", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_convex_hull_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_convex_hull_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc index c41b76412e9..fc407414667 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc @@ -21,9 +21,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_endpoint_select_cc { -static void geo_node_curve_endpoint_selection_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Int>(N_("Start Size")) .min(0) @@ -51,69 +51,61 @@ static void select_by_spline(const int start, const int end, MutableSpan<bool> r r_selection.slice(size - end_use, end_use).fill(true); } -class EndpointFieldInput final : public fn::FieldInput { +class EndpointFieldInput final : public GeometryFieldInput { Field<int> start_size_; Field<int> end_size_; public: EndpointFieldInput(Field<int> start_size, Field<int> end_size) - : FieldInput(CPPType::get<bool>(), "Endpoint Selection node"), + : GeometryFieldInput(CPPType::get<bool>(), "Endpoint Selection node"), start_size_(start_size), end_size_(end_size) { category_ = Category::Generated; } - GVArray get_varray_for_context(const fn::FieldContext &context, - IndexMask UNUSED(mask), - ResourceScope &UNUSED(scope)) const final + GVArray get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask UNUSED(mask)) const final { - if (const GeometryComponentFieldContext *geometry_context = - dynamic_cast<const GeometryComponentFieldContext *>(&context)) { + if (component.type() != GEO_COMPONENT_TYPE_CURVE || domain != ATTR_DOMAIN_POINT) { + return nullptr; + } - const GeometryComponent &component = geometry_context->geometry_component(); - const AttributeDomain domain = geometry_context->domain(); - if (component.type() != GEO_COMPONENT_TYPE_CURVE || domain != ATTR_DOMAIN_POINT) { - return nullptr; - } + const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); + const CurveEval *curve = curve_component.get_for_read(); - const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); - const CurveEval *curve = curve_component.get_for_read(); + Array<int> control_point_offsets = curve->control_point_offsets(); - Array<int> control_point_offsets = curve->control_point_offsets(); + if (curve == nullptr || control_point_offsets.last() == 0) { + return nullptr; + } - if (curve == nullptr || control_point_offsets.last() == 0) { - return nullptr; + GeometryComponentFieldContext size_context{curve_component, ATTR_DOMAIN_CURVE}; + fn::FieldEvaluator evaluator{size_context, curve->splines().size()}; + evaluator.add(start_size_); + evaluator.add(end_size_); + evaluator.evaluate(); + const VArray<int> &start_size = evaluator.get_evaluated<int>(0); + const VArray<int> &end_size = evaluator.get_evaluated<int>(1); + + const int point_size = control_point_offsets.last(); + Array<bool> selection(point_size, false); + int current_point = 0; + MutableSpan<bool> selection_span = selection.as_mutable_span(); + for (int i : IndexRange(curve->splines().size())) { + const SplinePtr &spline = curve->splines()[i]; + if (start_size[i] <= 0 && end_size[i] <= 0) { + selection_span.slice(current_point, spline->size()).fill(false); } - - GeometryComponentFieldContext size_context{curve_component, ATTR_DOMAIN_CURVE}; - fn::FieldEvaluator evaluator{size_context, curve->splines().size()}; - evaluator.add(start_size_); - evaluator.add(end_size_); - evaluator.evaluate(); - const VArray<int> &start_size = evaluator.get_evaluated<int>(0); - const VArray<int> &end_size = evaluator.get_evaluated<int>(1); - - const int point_size = control_point_offsets.last(); - Array<bool> selection(point_size, false); - int current_point = 0; - MutableSpan<bool> selection_span = selection.as_mutable_span(); - for (int i : IndexRange(curve->splines().size())) { - const SplinePtr &spline = curve->splines()[i]; - if (start_size[i] <= 0 && end_size[i] <= 0) { - selection_span.slice(current_point, spline->size()).fill(false); - } - else { - int start_use = std::max(start_size[i], 0); - int end_use = std::max(end_size[i], 0); - select_by_spline( - start_use, end_use, selection_span.slice(current_point, spline->size())); - } - current_point += spline->size(); + else { + int start_use = std::max(start_size[i], 0); + int end_use = std::max(end_size[i], 0); + select_by_spline(start_use, end_use, selection_span.slice(current_point, spline->size())); } - return VArray<bool>::ForContainer(std::move(selection)); + current_point += spline->size(); } - return {}; + return VArray<bool>::ForContainer(std::move(selection)); }; uint64_t hash() const override @@ -131,23 +123,25 @@ class EndpointFieldInput final : public fn::FieldInput { } }; -static void geo_node_curve_endpoint_selection_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<int> start_size = params.extract_input<Field<int>>("Start Size"); Field<int> end_size = params.extract_input<Field<int>>("End Size"); Field<bool> selection_field{std::make_shared<EndpointFieldInput>(start_size, end_size)}; params.set_output("Selection", std::move(selection_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_endpoint_select_cc void register_node_type_geo_curve_endpoint_selection() { + namespace file_ns = blender::nodes::node_geo_curve_endpoint_select_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_CURVE_ENDPOINT_SELECTION, "Endpoint Selection", NODE_CLASS_INPUT, 0); - ntype.declare = blender::nodes::geo_node_curve_endpoint_selection_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_endpoint_selection_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc index 219effadec4..3aabf8e21eb 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc @@ -31,20 +31,22 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_fill_cc { -static void geo_node_curve_fill_declare(NodeDeclarationBuilder &b) +NODE_STORAGE_FUNCS(NodeGeometryCurveFill) + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_output<decl::Geometry>(N_("Mesh")); } -static void geo_node_curve_fill_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_curve_fill_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryCurveFill *data = (NodeGeometryCurveFill *)MEM_callocN(sizeof(NodeGeometryCurveFill), __func__); @@ -147,11 +149,11 @@ static void curve_fill_calculate(GeometrySet &geometry_set, const GeometryNodeCu geometry_set.replace_curve(nullptr); } -static void geo_node_curve_fill_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); - const NodeGeometryCurveFill &storage = *(const NodeGeometryCurveFill *)params.node().storage; + const NodeGeometryCurveFill &storage = node_storage(params.node()); const GeometryNodeCurveFillMode mode = (GeometryNodeCurveFillMode)storage.mode; geometry_set.modify_geometry_sets( @@ -160,19 +162,21 @@ static void geo_node_curve_fill_exec(GeoNodeExecParams params) params.set_output("Mesh", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_fill_cc void register_node_type_geo_curve_fill() { + namespace file_ns = blender::nodes::node_geo_curve_fill_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_FILL_CURVE, "Fill Curve", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_curve_fill_init); + node_type_init(&ntype, file_ns::node_init); node_type_storage( &ntype, "NodeGeometryCurveFill", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_curve_fill_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_fill_exec; - ntype.draw_buttons = blender::nodes::geo_node_curve_fill_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } 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 a320f35c539..a438c1d6086 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc @@ -25,12 +25,19 @@ #include "BKE_spline.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_fillet_cc { -static void geo_node_curve_fillet_declare(NodeDeclarationBuilder &b) +NODE_STORAGE_FUNCS(NodeGeometryCurveFillet) + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); - b.add_input<decl::Int>(N_("Count")).default_value(1).min(1).max(1000).supports_field(); + b.add_input<decl::Int>(N_("Count")) + .default_value(1) + .min(1) + .max(1000) + .supports_field() + .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_FILLET_POLY; }); b.add_input<decl::Float>(N_("Radius")) .min(0.0f) .max(FLT_MAX) @@ -41,12 +48,12 @@ static void geo_node_curve_fillet_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_fillet_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_curve_fillet_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveFillet *data = (NodeGeometryCurveFillet *)MEM_callocN( sizeof(NodeGeometryCurveFillet), __func__); @@ -76,10 +83,10 @@ struct FilletData { Array<int> counts; }; -static void geo_node_curve_fillet_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { - NodeGeometryCurveFillet &node_storage = *(NodeGeometryCurveFillet *)node->storage; - const GeometryNodeCurveFilletMode mode = (GeometryNodeCurveFilletMode)node_storage.mode; + const NodeGeometryCurveFillet &storage = node_storage(*node); + const GeometryNodeCurveFilletMode mode = (GeometryNodeCurveFilletMode)storage.mode; bNodeSocket *poly_socket = ((bNodeSocket *)node->inputs.first)->next; @@ -332,14 +339,17 @@ static void copy_common_attributes_by_mapping(const Spline &src, copy_attribute_by_mapping(src.radii(), dst.radii(), mapping); copy_attribute_by_mapping(src.tilts(), dst.tilts(), mapping); - dst.attributes.reallocate(1); src.attributes.foreach_attribute( [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { std::optional<GSpan> src_attribute = src.attributes.get_for_read(attribute_id); if (dst.attributes.create(attribute_id, meta_data.data_type)) { std::optional<GMutableSpan> dst_attribute = dst.attributes.get_for_write(attribute_id); if (dst_attribute) { - src_attribute->type().copy_assign(src_attribute->data(), dst_attribute->data()); + attribute_math::convert_to_static_type(dst_attribute->type(), [&](auto dummy) { + using T = decltype(dummy); + copy_attribute_by_mapping( + src_attribute->typed<T>(), dst_attribute->typed<T>(), mapping); + }); return true; } } @@ -607,12 +617,12 @@ static void calculate_curve_fillet(GeometrySet &geometry_set, geometry_set.replace_curve(output_curve.release()); } -static void geo_node_fillet_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); - NodeGeometryCurveFillet &node_storage = *(NodeGeometryCurveFillet *)params.node().storage; - const GeometryNodeCurveFilletMode mode = (GeometryNodeCurveFilletMode)node_storage.mode; + const NodeGeometryCurveFillet &storage = node_storage(params.node()); + const GeometryNodeCurveFilletMode mode = (GeometryNodeCurveFilletMode)storage.mode; Field<float> radius_field = params.extract_input<Field<float>>("Radius"); const bool limit_radius = params.extract_input<bool>("Limit Radius"); @@ -629,19 +639,21 @@ static void geo_node_fillet_exec(GeoNodeExecParams params) params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_fillet_cc void register_node_type_geo_curve_fillet() { + namespace file_ns = blender::nodes::node_geo_curve_fillet_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_FILLET_CURVE, "Fillet Curve", NODE_CLASS_GEOMETRY, 0); - ntype.draw_buttons = blender::nodes::geo_node_curve_fillet_layout; + ntype.draw_buttons = file_ns::node_layout; node_type_storage( &ntype, "NodeGeometryCurveFillet", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_curve_fillet_declare; - node_type_init(&ntype, blender::nodes::geo_node_curve_fillet_init); - node_type_update(&ntype, blender::nodes::geo_node_curve_fillet_update); - ntype.geometry_node_execute = blender::nodes::geo_node_fillet_exec; + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } 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 5fb17270301..381bb0fc1d0 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 @@ -21,22 +21,22 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_handle_type_selection_cc { -static void geo_node_curve_handle_type_selection_declare(NodeDeclarationBuilder &b) +NODE_STORAGE_FUNCS(NodeGeometryCurveSelectHandles) + +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Bool>(N_("Selection")).field_source(); } -static void geo_node_curve_handle_type_selection_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE); } -static void geo_node_curve_handle_type_selection_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveSelectHandles *data = (NodeGeometryCurveSelectHandles *)MEM_callocN( sizeof(NodeGeometryCurveSelectHandles), __func__); @@ -85,44 +85,40 @@ static void select_by_handle_type(const CurveEval &curve, } } -class HandleTypeFieldInput final : public fn::FieldInput { +class HandleTypeFieldInput final : public GeometryFieldInput { BezierSpline::HandleType type_; GeometryNodeCurveHandleMode mode_; public: HandleTypeFieldInput(BezierSpline::HandleType type, GeometryNodeCurveHandleMode mode) - : FieldInput(CPPType::get<bool>(), "Handle Type Selection node"), type_(type), mode_(mode) + : GeometryFieldInput(CPPType::get<bool>(), "Handle Type Selection node"), + type_(type), + mode_(mode) { category_ = Category::Generated; } - GVArray get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &UNUSED(scope)) const final + GVArray get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask mask) const final { - if (const GeometryComponentFieldContext *geometry_context = - dynamic_cast<const GeometryComponentFieldContext *>(&context)) { - - const GeometryComponent &component = geometry_context->geometry_component(); - const AttributeDomain domain = geometry_context->domain(); - if (component.type() != GEO_COMPONENT_TYPE_CURVE) { - return {}; - } + if (component.type() != GEO_COMPONENT_TYPE_CURVE) { + return {}; + } - const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); - const CurveEval *curve = curve_component.get_for_read(); - if (curve == nullptr) { - return {}; - } + const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); + const CurveEval *curve = curve_component.get_for_read(); + if (curve == nullptr) { + return {}; + } - if (domain == ATTR_DOMAIN_POINT) { - Array<bool> selection(mask.min_array_size()); - select_by_handle_type(*curve, type_, mode_, selection); - return VArray<bool>::ForContainer(std::move(selection)); - } + if (domain == ATTR_DOMAIN_POINT) { + Array<bool> selection(mask.min_array_size()); + select_by_handle_type(*curve, type_, mode_, selection); + return VArray<bool>::ForContainer(std::move(selection)); } return {}; - }; + } uint64_t hash() const override { @@ -140,34 +136,35 @@ class HandleTypeFieldInput final : public fn::FieldInput { } }; -static void geo_node_curve_handle_type_selection_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { - const NodeGeometryCurveSelectHandles *storage = - (const NodeGeometryCurveSelectHandles *)params.node().storage; + const NodeGeometryCurveSelectHandles &storage = node_storage(params.node()); const BezierSpline::HandleType handle_type = handle_type_from_input_type( - (GeometryNodeCurveHandleType)storage->handle_type); - const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)storage->mode; + (GeometryNodeCurveHandleType)storage.handle_type); + const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)storage.mode; Field<bool> selection_field{std::make_shared<HandleTypeFieldInput>(handle_type, mode)}; params.set_output("Selection", std::move(selection_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_handle_type_selection_cc void register_node_type_geo_curve_handle_type_selection() { + namespace file_ns = blender::nodes::node_geo_curve_handle_type_selection_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_CURVE_HANDLE_TYPE_SELECTION, "Handle Type Selection", NODE_CLASS_INPUT, 0); - ntype.declare = blender::nodes::geo_node_curve_handle_type_selection_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_handle_type_selection_exec; - node_type_init(&ntype, blender::nodes::geo_node_curve_handle_type_selection_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryCurveSelectHandles", node_free_standard_storage, node_copy_standard_storage); - ntype.draw_buttons = blender::nodes::geo_node_curve_handle_type_selection_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc index 0d0dc0ec89c..73ad8a8cf65 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc @@ -17,19 +17,19 @@ #include "BKE_spline.hh" #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_length_cc { -static void geo_node_curve_length_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_output<decl::Float>(N_("Length")); } -static void geo_node_curve_length_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet curve_set = params.extract_input<GeometrySet>("Curve"); if (!curve_set.has_curve()) { - params.set_output("Length", 0.0f); + params.set_default_remaining_outputs(); return; } const CurveEval &curve = *curve_set.get_curve_for_read(); @@ -40,14 +40,16 @@ static void geo_node_curve_length_exec(GeoNodeExecParams params) params.set_output("Length", length); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_length_cc void register_node_type_geo_curve_length() { + namespace file_ns = blender::nodes::node_geo_curve_length_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_CURVE_LENGTH, "Curve Length", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_length_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_length_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc index 673a5095044..4299b5cc022 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc @@ -21,9 +21,11 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_primitive_bezier_segment_cc { -static void geo_node_curve_primitive_bezier_segment_declare(NodeDeclarationBuilder &b) +NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveBezierSegment) + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Int>(N_("Resolution")) .default_value(16) @@ -53,14 +55,12 @@ static void geo_node_curve_primitive_bezier_segment_declare(NodeDeclarationBuild b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_primitive_bezier_segment_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_curve_primitive_bezier_segment_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurvePrimitiveBezierSegment *data = (NodeGeometryCurvePrimitiveBezierSegment *) MEM_callocN(sizeof(NodeGeometryCurvePrimitiveBezierSegment), __func__); @@ -120,12 +120,11 @@ static std::unique_ptr<CurveEval> create_bezier_segment_curve( return curve; } -static void geo_node_curve_primitive_bezier_segment_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { - const NodeGeometryCurvePrimitiveBezierSegment *node_storage = - (NodeGeometryCurvePrimitiveBezierSegment *)params.node().storage; + const NodeGeometryCurvePrimitiveBezierSegment &storage = node_storage(params.node()); const GeometryNodeCurvePrimitiveBezierSegmentMode mode = - (const GeometryNodeCurvePrimitiveBezierSegmentMode)node_storage->mode; + (const GeometryNodeCurvePrimitiveBezierSegmentMode)storage.mode; std::unique_ptr<CurveEval> curve = create_bezier_segment_curve( params.extract_input<float3>("Start"), @@ -137,20 +136,22 @@ static void geo_node_curve_primitive_bezier_segment_exec(GeoNodeExecParams param params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_primitive_bezier_segment_cc void register_node_type_geo_curve_primitive_bezier_segment() { + namespace file_ns = blender::nodes::node_geo_curve_primitive_bezier_segment_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT, "Bezier Segment", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_curve_primitive_bezier_segment_init); + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryCurvePrimitiveBezierSegment", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_curve_primitive_bezier_segment_declare; - ntype.draw_buttons = blender::nodes::geo_node_curve_primitive_bezier_segment_layout; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_bezier_segment_exec; + ntype.declare = file_ns::node_declare; + ntype.draw_buttons = file_ns::node_layout; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } 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 5d8beb9c9d8..70abf4c64a7 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 @@ -21,9 +21,11 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_primitive_circle_cc { -static void geo_node_curve_primitive_circle_declare(NodeDeclarationBuilder &b) +NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveCircle) + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Int>(N_("Resolution")) .default_value(32) @@ -54,17 +56,17 @@ static void geo_node_curve_primitive_circle_declare(NodeDeclarationBuilder &b) .subtype(PROP_DISTANCE) .description(N_("Distance of the points from the origin")); b.add_output<decl::Geometry>(N_("Curve")); - b.add_output<decl::Vector>(N_("Center")); + b.add_output<decl::Vector>(N_("Center")).make_available([](bNode &node) { + node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS; + }); } -static void geo_node_curve_primitive_circle_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_curve_primitive_circle_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurvePrimitiveCircle *data = (NodeGeometryCurvePrimitiveCircle *)MEM_callocN( sizeof(NodeGeometryCurvePrimitiveCircle), __func__); @@ -73,12 +75,11 @@ static void geo_node_curve_primitive_circle_init(bNodeTree *UNUSED(tree), bNode node->storage = data; } -static void geo_node_curve_primitive_circle_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { - const NodeGeometryCurvePrimitiveCircle *node_storage = (NodeGeometryCurvePrimitiveCircle *) - node->storage; - const GeometryNodeCurvePrimitiveCircleMode mode = (const GeometryNodeCurvePrimitiveCircleMode) - node_storage->mode; + const NodeGeometryCurvePrimitiveCircle &storage = node_storage(*node); + const GeometryNodeCurvePrimitiveCircleMode mode = (GeometryNodeCurvePrimitiveCircleMode) + storage.mode; bNodeSocket *start_socket = ((bNodeSocket *)node->inputs.first)->next; bNodeSocket *middle_socket = start_socket->next; @@ -195,13 +196,11 @@ static std::unique_ptr<CurveEval> create_radius_circle_curve(const int resolutio return curve; } -static void geo_node_curve_primitive_circle_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { - const NodeGeometryCurvePrimitiveCircle *node_storage = - (NodeGeometryCurvePrimitiveCircle *)params.node().storage; - + const NodeGeometryCurvePrimitiveCircle &storage = node_storage(params.node()); const GeometryNodeCurvePrimitiveCircleMode mode = (GeometryNodeCurvePrimitiveCircleMode) - node_storage->mode; + storage.mode; std::unique_ptr<CurveEval> curve; if (mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS) { @@ -222,26 +221,28 @@ static void geo_node_curve_primitive_circle_exec(GeoNodeExecParams params) params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); } else { - params.set_output("Curve", GeometrySet()); + params.set_default_remaining_outputs(); } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_primitive_circle_cc void register_node_type_geo_curve_primitive_circle() { + namespace file_ns = blender::nodes::node_geo_curve_primitive_circle_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, "Curve Circle", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_curve_primitive_circle_init); - node_type_update(&ntype, blender::nodes::geo_node_curve_primitive_circle_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage(&ntype, "NodeGeometryCurvePrimitiveCircle", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_curve_primitive_circle_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_circle_exec; - ntype.draw_buttons = blender::nodes::geo_node_curve_primitive_circle_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } 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 238fc77e1cc..6d71c97b15a 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 @@ -21,9 +21,11 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_primitive_line_cc { -static void geo_node_curve_primitive_line_declare(NodeDeclarationBuilder &b) +NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveLine) + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Vector>(N_("Start")) .subtype(PROP_TRANSLATION) @@ -43,14 +45,12 @@ static void geo_node_curve_primitive_line_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_primitive_line_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_curve_primitive_line_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurvePrimitiveLine *data = (NodeGeometryCurvePrimitiveLine *)MEM_callocN( sizeof(NodeGeometryCurvePrimitiveLine), __func__); @@ -59,12 +59,10 @@ static void geo_node_curve_primitive_line_init(bNodeTree *UNUSED(tree), bNode *n node->storage = data; } -static void geo_node_curve_primitive_line_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { - const NodeGeometryCurvePrimitiveLine *node_storage = (NodeGeometryCurvePrimitiveLine *) - node->storage; - const GeometryNodeCurvePrimitiveLineMode mode = (const GeometryNodeCurvePrimitiveLineMode) - node_storage->mode; + const NodeGeometryCurvePrimitiveLine &storage = node_storage(*node); + const GeometryNodeCurvePrimitiveLineMode mode = (GeometryNodeCurvePrimitiveLineMode)storage.mode; bNodeSocket *p2_socket = ((bNodeSocket *)node->inputs.first)->next; bNodeSocket *direction_socket = p2_socket->next; @@ -112,13 +110,10 @@ static std::unique_ptr<CurveEval> create_direction_line_curve(const float3 start return curve; } -static void geo_node_curve_primitive_line_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { - - const NodeGeometryCurvePrimitiveLine *node_storage = - (NodeGeometryCurvePrimitiveLine *)params.node().storage; - - GeometryNodeCurvePrimitiveLineMode mode = (GeometryNodeCurvePrimitiveLineMode)node_storage->mode; + const NodeGeometryCurvePrimitiveLine &storage = node_storage(params.node()); + const GeometryNodeCurvePrimitiveLineMode mode = (GeometryNodeCurvePrimitiveLineMode)storage.mode; std::unique_ptr<CurveEval> curve; if (mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS) { @@ -134,20 +129,22 @@ static void geo_node_curve_primitive_line_exec(GeoNodeExecParams params) params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_primitive_line_cc void register_node_type_geo_curve_primitive_line() { + namespace file_ns = blender::nodes::node_geo_curve_primitive_line_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_LINE, "Curve Line", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_curve_primitive_line_init); - node_type_update(&ntype, blender::nodes::geo_node_curve_primitive_line_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage(&ntype, "NodeGeometryCurvePrimitiveLine", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_curve_primitive_line_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_line_exec; - ntype.draw_buttons = blender::nodes::geo_node_curve_primitive_line_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc index 27bf4a310df..92a9b1b4966 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc @@ -17,9 +17,9 @@ #include "BKE_spline.hh" #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_primitive_quadratic_bezier_cc { -static void geo_node_curve_primitive_quadratic_bezier_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Int>(N_("Resolution")) .default_value(16) @@ -64,7 +64,7 @@ static std::unique_ptr<CurveEval> create_quadratic_bezier_curve(const float3 p1, return curve; } -static void geo_node_curve_primitive_quadratic_bezier_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { std::unique_ptr<CurveEval> curve = create_quadratic_bezier_curve( params.extract_input<float3>("Start"), @@ -74,17 +74,19 @@ static void geo_node_curve_primitive_quadratic_bezier_exec(GeoNodeExecParams par params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_primitive_quadratic_bezier_cc void register_node_type_geo_curve_primitive_quadratic_bezier() { + namespace file_ns = blender::nodes::node_geo_curve_primitive_quadratic_bezier_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_QUADRATIC_BEZIER, "Quadratic Bezier", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_primitive_quadratic_bezier_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_quadratic_bezier_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc index 114ae441d99..ff6294b9b6b 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 @@ -17,11 +17,16 @@ #include "BKE_spline.hh" #include "UI_interface.h" #include "UI_resources.h" + +#include "NOD_socket_search_link.hh" + #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_primitive_quadrilaterial_cc { + +NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveQuad) -static void geo_node_curve_primitive_quadrilateral_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Float>(N_("Width")) .default_value(2.0f) @@ -77,14 +82,12 @@ static void geo_node_curve_primitive_quadrilateral_declare(NodeDeclarationBuilde b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_primitive_quadrilateral_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); } -static void geo_node_curve_primitive_quadrilateral_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurvePrimitiveQuad *data = (NodeGeometryCurvePrimitiveQuad *)MEM_callocN( sizeof(NodeGeometryCurvePrimitiveQuad), __func__); @@ -92,11 +95,11 @@ static void geo_node_curve_primitive_quadrilateral_init(bNodeTree *UNUSED(tree), node->storage = data; } -static void geo_node_curve_primitive_quadrilateral_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { - NodeGeometryCurvePrimitiveQuad &node_storage = *(NodeGeometryCurvePrimitiveQuad *)node->storage; + const NodeGeometryCurvePrimitiveQuad &storage = node_storage(*node); GeometryNodeCurvePrimitiveQuadMode mode = static_cast<GeometryNodeCurvePrimitiveQuadMode>( - node_storage.mode); + storage.mode); bNodeSocket *width = ((bNodeSocket *)node->inputs.first); bNodeSocket *height = width->next; @@ -142,6 +145,41 @@ static void geo_node_curve_primitive_quadrilateral_update(bNodeTree *ntree, bNod } } +class SocketSearchOp { + public: + std::string socket_name; + GeometryNodeCurvePrimitiveQuadMode quad_mode; + void operator()(LinkSearchOpParams ¶ms) + { + bNode &node = params.add_node("GeometryNodeCurvePrimitiveQuadrilateral"); + node_storage(node).mode = quad_mode; + params.update_and_connect_available_socket(node, socket_name); + } +}; + +static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) +{ + const NodeDeclaration &declaration = *params.node_type().fixed_declaration; + if (params.in_out() == SOCK_OUT) { + 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)) { + params.add_item(IFACE_("Width"), + SocketSearchOp{"Width", GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE}); + params.add_item(IFACE_("Height"), + SocketSearchOp{"Height", GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE}); + params.add_item(IFACE_("Bottom Width"), + SocketSearchOp{"Bottom Width", GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID}); + params.add_item(IFACE_("Top Width"), + SocketSearchOp{"Top Width", GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID}); + params.add_item(IFACE_("Offset"), + SocketSearchOp{"Offset", GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_PARALLELOGRAM}); + params.add_item(IFACE_("Point 1"), + SocketSearchOp{"Point 1", GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_POINTS}); + } +} + static void create_rectangle_curve(MutableSpan<float3> positions, const float height, const float width) @@ -197,12 +235,10 @@ static void create_kite_curve(MutableSpan<float3> positions, positions[3] = float3(-width / 2.0f, 0, 0); } -static void geo_node_curve_primitive_quadrilateral_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { - const NodeGeometryCurvePrimitiveQuad &node_storage = - *(NodeGeometryCurvePrimitiveQuad *)(params.node()).storage; - const GeometryNodeCurvePrimitiveQuadMode mode = static_cast<GeometryNodeCurvePrimitiveQuadMode>( - node_storage.mode); + const NodeGeometryCurvePrimitiveQuad &storage = node_storage(params.node()); + const GeometryNodeCurvePrimitiveQuadMode mode = (GeometryNodeCurvePrimitiveQuadMode)storage.mode; std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>(); std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>(); @@ -246,7 +282,7 @@ static void geo_node_curve_primitive_quadrilateral_exec(GeoNodeExecParams params params.extract_input<float3>("Point 4")); break; default: - params.set_output("Curve", GeometrySet()); + params.set_default_remaining_outputs(); return; } @@ -255,21 +291,24 @@ static void geo_node_curve_primitive_quadrilateral_exec(GeoNodeExecParams params params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_primitive_quadrilaterial_cc void register_node_type_geo_curve_primitive_quadrilateral() { + namespace file_ns = blender::nodes::node_geo_curve_primitive_quadrilaterial_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, "Quadrilateral", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_primitive_quadrilateral_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_quadrilateral_exec; - ntype.draw_buttons = blender::nodes::geo_node_curve_primitive_quadrilateral_layout; - node_type_update(&ntype, blender::nodes::geo_node_curve_primitive_quadrilateral_update); - node_type_init(&ntype, blender::nodes::geo_node_curve_primitive_quadrilateral_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + node_type_update(&ntype, file_ns::node_update); + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryCurvePrimitiveQuad", node_free_standard_storage, node_copy_standard_storage); + ntype.gather_link_search_ops = file_ns::node_gather_link_searches; nodeRegisterType(&ntype); } 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 1384165e520..d5ae3551904 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 @@ -18,9 +18,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_primitive_spiral_cc { -static void geo_node_curve_primitive_spiral_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Int>(N_("Resolution")) .default_value(32) @@ -81,11 +81,11 @@ static std::unique_ptr<CurveEval> create_spiral_curve(const float rotations, return curve; } -static void geo_node_curve_primitive_spiral_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const float rotations = std::max(params.extract_input<float>("Rotations"), 0.0f); if (rotations == 0.0f) { - params.set_output("Curve", GeometrySet()); + params.set_default_remaining_outputs(); return; } @@ -99,14 +99,16 @@ static void geo_node_curve_primitive_spiral_exec(GeoNodeExecParams params) params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_primitive_spiral_cc void register_node_type_geo_curve_primitive_spiral() { + namespace file_ns = blender::nodes::node_geo_curve_primitive_spiral_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_SPIRAL, "Spiral", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_primitive_spiral_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_spiral_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc index 9004681c246..731be0f0f49 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc @@ -18,9 +18,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_primitive_star_cc { -static void geo_node_curve_primitive_star_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Int>(N_("Points")) .default_value(8) @@ -85,7 +85,7 @@ static void create_selection_output(CurveComponent &component, attribute.save(); } -static void geo_node_curve_primitive_star_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { std::unique_ptr<CurveEval> curve = create_star_curve( std::max(params.extract_input<float>("Inner Radius"), 0.0f), @@ -103,13 +103,15 @@ static void geo_node_curve_primitive_star_exec(GeoNodeExecParams params) } params.set_output("Curve", std::move(output)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_primitive_star_cc void register_node_type_geo_curve_primitive_star() { + namespace file_ns = blender::nodes::node_geo_curve_primitive_star_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_STAR, "Star", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_primitive_star_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_star_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc index f72978bae50..7e465714265 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc @@ -26,9 +26,11 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_resample_cc { -static void geo_node_curve_resample_declare(NodeDeclarationBuilder &b) +NODE_STORAGE_FUNCS(NodeGeometryCurveResample) + +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).supports_field().hide_value(); @@ -41,12 +43,12 @@ static void geo_node_curve_resample_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_resample_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); } -static void geo_node_curve_resample_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveResample *data = (NodeGeometryCurveResample *)MEM_callocN( sizeof(NodeGeometryCurveResample), __func__); @@ -55,10 +57,10 @@ static void geo_node_curve_resample_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_curve_resample_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { - NodeGeometryCurveResample &node_storage = *(NodeGeometryCurveResample *)node->storage; - const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode; + const NodeGeometryCurveResample &storage = node_storage(*node); + const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)storage.mode; bNodeSocket *count_socket = ((bNodeSocket *)node->inputs.first)->next->next; bNodeSocket *length_socket = count_socket->next; @@ -189,7 +191,7 @@ static std::unique_ptr<CurveEval> resample_curve(const CurveComponent *component threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) { for (const int i : range) { BLI_assert(mode_param.count); - if (selections[i]) { + if (selections[i] && input_splines[i]->evaluated_points_size() > 0) { output_splines[i] = resample_spline(*input_splines[i], std::max(cuts[i], 1)); } else { @@ -208,7 +210,7 @@ static std::unique_ptr<CurveEval> resample_curve(const CurveComponent *component threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) { for (const int i : range) { - if (selections[i]) { + if (selections[i] && input_splines[i]->evaluated_points_size() > 0) { /* Don't allow asymptotic count increase for low resolution values. */ const float divide_length = std::max(lengths[i], 0.0001f); const float spline_length = input_splines[i]->length(); @@ -229,7 +231,7 @@ static std::unique_ptr<CurveEval> resample_curve(const CurveComponent *component threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) { for (const int i : range) { - if (selections[i]) { + if (selections[i] && input_splines[i]->evaluated_points_size() > 0) { output_splines[i] = resample_spline_evaluated(*input_splines[i]); } else { @@ -255,12 +257,12 @@ static void geometry_set_curve_resample(GeometrySet &geometry_set, geometry_set.replace_curve(output_curve.release()); } -static void geo_node_resample_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); - NodeGeometryCurveResample &node_storage = *(NodeGeometryCurveResample *)params.node().storage; - const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode; + const NodeGeometryCurveResample &storage = node_storage(params.node()); + const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)storage.mode; SampleModeParam mode_param; mode_param.mode = mode; @@ -269,7 +271,7 @@ static void geo_node_resample_exec(GeoNodeExecParams params) if (mode == GEO_NODE_CURVE_RESAMPLE_COUNT) { Field<int> count = params.extract_input<Field<int>>("Count"); if (count < 1) { - params.set_output("Curve", GeometrySet()); + params.set_default_remaining_outputs(); return; } mode_param.count.emplace(count); @@ -285,19 +287,21 @@ static void geo_node_resample_exec(GeoNodeExecParams params) params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_resample_cc void register_node_type_geo_curve_resample() { + namespace file_ns = blender::nodes::node_geo_curve_resample_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_RESAMPLE_CURVE, "Resample Curve", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_resample_declare; - ntype.draw_buttons = blender::nodes::geo_node_curve_resample_layout; + ntype.declare = file_ns::node_declare; + ntype.draw_buttons = file_ns::node_layout; node_type_storage( &ntype, "NodeGeometryCurveResample", node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_curve_resample_init); - node_type_update(&ntype, blender::nodes::geo_node_curve_resample_update); - ntype.geometry_node_execute = blender::nodes::geo_node_resample_exec; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc index b1dc45a426a..d07e89ec7f2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc @@ -20,16 +20,16 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_reverse_cc { -static void geo_node_curve_reverse_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_reverse_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); @@ -60,13 +60,15 @@ static void geo_node_curve_reverse_exec(GeoNodeExecParams params) params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_reverse_cc void register_node_type_geo_curve_reverse() { + namespace file_ns = blender::nodes::node_geo_curve_reverse_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_REVERSE_CURVE, "Reverse Curve", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_reverse_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_reverse_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc index 8f42aacab43..eff760266f5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc @@ -23,27 +23,37 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_sample_cc { -static void geo_node_curve_sample_declare(NodeDeclarationBuilder &b) +NODE_STORAGE_FUNCS(NodeGeometryCurveSample) + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")) .only_realized_data() .supported_type(GEO_COMPONENT_TYPE_CURVE); - b.add_input<decl::Float>(N_("Factor")).min(0.0f).max(1.0f).subtype(PROP_FACTOR).supports_field(); - b.add_input<decl::Float>(N_("Length")).min(0.0f).subtype(PROP_DISTANCE).supports_field(); - + b.add_input<decl::Float>(N_("Factor")) + .min(0.0f) + .max(1.0f) + .subtype(PROP_FACTOR) + .supports_field() + .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_FACTOR; }); + b.add_input<decl::Float>(N_("Length")) + .min(0.0f) + .subtype(PROP_DISTANCE) + .supports_field() + .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_LENGTH; }); b.add_output<decl::Vector>(N_("Position")).dependent_field(); b.add_output<decl::Vector>(N_("Tangent")).dependent_field(); b.add_output<decl::Vector>(N_("Normal")).dependent_field(); } -static void geo_node_curve_sample_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_curve_sample_type_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_type_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveSample *data = (NodeGeometryCurveSample *)MEM_callocN( sizeof(NodeGeometryCurveSample), __func__); @@ -51,10 +61,10 @@ static void geo_node_curve_sample_type_init(bNodeTree *UNUSED(tree), bNode *node node->storage = data; } -static void geo_node_curve_sample_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { - const NodeGeometryCurveSample &node_storage = *(NodeGeometryCurveSample *)node->storage; - const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode; + const NodeGeometryCurveSample &storage = node_storage(*node); + const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)storage.mode; bNodeSocket *factor = ((bNodeSocket *)node->inputs.first)->next; bNodeSocket *length = factor->next; @@ -200,8 +210,8 @@ class SampleCurveFunction : public fn::MultiFunction { static Field<float> get_length_input_field(const GeoNodeExecParams ¶ms, const float curve_total_length) { - const NodeGeometryCurveSample &node_storage = *(NodeGeometryCurveSample *)params.node().storage; - const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode; + const NodeGeometryCurveSample &storage = node_storage(params.node()); + const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)storage.mode; if (mode == GEO_NODE_CURVE_SAMPLE_LENGTH) { /* Just make sure the length is in bounds of the curve. */ @@ -229,34 +239,32 @@ static Field<float> get_length_input_field(const GeoNodeExecParams ¶ms, return Field<float>(std::move(process_op), 0); } -static void geo_node_curve_sample_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); - auto return_default = [&]() { - params.set_output("Position", fn::make_constant_field<float3>({0.0f, 0.0f, 0.0f})); - params.set_output("Tangent", fn::make_constant_field<float3>({0.0f, 0.0f, 0.0f})); - params.set_output("Normal", fn::make_constant_field<float3>({0.0f, 0.0f, 0.0f})); - }; - const CurveComponent *component = geometry_set.get_component_for_read<CurveComponent>(); if (component == nullptr) { - return return_default(); + params.set_default_remaining_outputs(); + return; } const CurveEval *curve = component->get_for_read(); if (curve == nullptr) { - return return_default(); + params.set_default_remaining_outputs(); + return; } if (curve->splines().is_empty()) { - return return_default(); + params.set_default_remaining_outputs(); + return; } Array<float> spline_lengths = curve->accumulated_spline_lengths(); const float total_length = spline_lengths.last(); if (total_length == 0.0f) { - return return_default(); + params.set_default_remaining_outputs(); + return; } Field<float> length_field = get_length_input_field(params, total_length); @@ -271,20 +279,22 @@ static void geo_node_curve_sample_exec(GeoNodeExecParams params) params.set_output("Normal", Field<float3>(sample_op, 2)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_sample_cc void register_node_type_geo_curve_sample() { + namespace file_ns = blender::nodes::node_geo_curve_sample_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SAMPLE_CURVE, " Sample Curve", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_curve_sample_exec; - ntype.declare = blender::nodes::geo_node_curve_sample_declare; - node_type_init(&ntype, blender::nodes::geo_node_curve_sample_type_init); - node_type_update(&ntype, blender::nodes::geo_node_curve_sample_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::node_type_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeGeometryCurveSample", node_free_standard_storage, node_copy_standard_storage); - ntype.draw_buttons = blender::nodes::geo_node_curve_sample_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc index 8b0a6ca840c..8c0827570c6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc @@ -21,24 +21,24 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_set_handles_cc { -static void geo_node_curve_set_handles_declare(NodeDeclarationBuilder &b) +NODE_STORAGE_FUNCS(NodeGeometryCurveSetHandles) + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_set_handles_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE); } -static void geo_node_curve_set_handles_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveSetHandles *data = (NodeGeometryCurveSetHandles *)MEM_callocN( sizeof(NodeGeometryCurveSetHandles), __func__); @@ -64,12 +64,11 @@ static BezierSpline::HandleType handle_type_from_input_type(GeometryNodeCurveHan return BezierSpline::HandleType::Auto; } -static void geo_node_curve_set_handles_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { - const NodeGeometryCurveSetHandles *node_storage = - (NodeGeometryCurveSetHandles *)params.node().storage; - const GeometryNodeCurveHandleType type = (GeometryNodeCurveHandleType)node_storage->handle_type; - const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)node_storage->mode; + const NodeGeometryCurveSetHandles &storage = node_storage(params.node()); + const GeometryNodeCurveHandleType type = (GeometryNodeCurveHandleType)storage.handle_type; + const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)storage.mode; GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -130,21 +129,23 @@ static void geo_node_curve_set_handles_exec(GeoNodeExecParams params) } params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_set_handles_cc void register_node_type_geo_curve_set_handles() { + namespace file_ns = blender::nodes::node_geo_curve_set_handles_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_CURVE_SET_HANDLES, "Set Handle Type", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_set_handles_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_set_handles_exec; - node_type_init(&ntype, blender::nodes::geo_node_curve_set_handles_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryCurveSetHandles", node_free_standard_storage, node_copy_standard_storage); - ntype.draw_buttons = blender::nodes::geo_node_curve_set_handles_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc index 63518b38090..de352d217ed 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc @@ -20,9 +20,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_spline_parameter_cc { -static void geo_node_curve_parameter_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Float>(N_("Factor")) .field_source() @@ -34,6 +34,9 @@ static void geo_node_curve_parameter_declare(NodeDeclarationBuilder &b) .description( N_("For points, the distance along the control point's spline, For splines, the " "distance along the entire curve")); + b.add_output<decl::Int>(N_("Index")) + .field_source() + .description(N_("Each control point's index on its spline")); } /** @@ -182,29 +185,39 @@ static VArray<float> construct_curve_length_varray(const CurveEval &curve, return {}; } -class CurveParameterFieldInput final : public fn::FieldInput { +static VArray<int> construct_index_on_spline_varray(const CurveEval &curve, + const IndexMask UNUSED(mask), + const AttributeDomain domain) +{ + if (domain == ATTR_DOMAIN_POINT) { + Array<int> output(curve.total_control_point_size()); + int output_index = 0; + for (int spline_index : curve.splines().index_range()) { + for (int point_index : IndexRange(curve.splines()[spline_index]->size())) { + output[output_index++] = point_index; + } + } + return VArray<int>::ForContainer(std::move(output)); + } + return {}; +} + +class CurveParameterFieldInput final : public GeometryFieldInput { public: - CurveParameterFieldInput() : fn::FieldInput(CPPType::get<float>(), "Curve Parameter node") + CurveParameterFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Curve Parameter node") { category_ = Category::Generated; } - GVArray get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &UNUSED(scope)) const final + GVArray get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask mask) const final { - if (const GeometryComponentFieldContext *geometry_context = - dynamic_cast<const GeometryComponentFieldContext *>(&context)) { - - const GeometryComponent &component = geometry_context->geometry_component(); - const AttributeDomain domain = geometry_context->domain(); - - if (component.type() == GEO_COMPONENT_TYPE_CURVE) { - const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); - const CurveEval *curve = curve_component.get_for_read(); - if (curve) { - return construct_curve_parameter_varray(*curve, mask, domain); - } + if (component.type() == GEO_COMPONENT_TYPE_CURVE) { + const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); + const CurveEval *curve = curve_component.get_for_read(); + if (curve) { + return construct_curve_parameter_varray(*curve, mask, domain); } } return {}; @@ -222,28 +235,22 @@ class CurveParameterFieldInput final : public fn::FieldInput { } }; -class CurveLengthFieldInput final : public fn::FieldInput { +class CurveLengthFieldInput final : public GeometryFieldInput { public: - CurveLengthFieldInput() : fn::FieldInput(CPPType::get<float>(), "Curve Length node") + CurveLengthFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Curve Length node") { category_ = Category::Generated; } - GVArray get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &UNUSED(scope)) const final + GVArray get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask mask) const final { - if (const GeometryComponentFieldContext *geometry_context = - dynamic_cast<const GeometryComponentFieldContext *>(&context)) { - - const GeometryComponent &component = geometry_context->geometry_component(); - const AttributeDomain domain = geometry_context->domain(); - if (component.type() == GEO_COMPONENT_TYPE_CURVE) { - const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); - const CurveEval *curve = curve_component.get_for_read(); - if (curve) { - return construct_curve_length_varray(*curve, mask, domain); - } + if (component.type() == GEO_COMPONENT_TYPE_CURVE) { + const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); + const CurveEval *curve = curve_component.get_for_read(); + if (curve) { + return construct_curve_length_varray(*curve, mask, domain); } } return {}; @@ -261,21 +268,59 @@ class CurveLengthFieldInput final : public fn::FieldInput { } }; -static void geo_node_curve_parameter_exec(GeoNodeExecParams params) +class IndexOnSplineFieldInput final : public GeometryFieldInput { + public: + IndexOnSplineFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Spline Index") + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask mask) const final + { + if (component.type() == GEO_COMPONENT_TYPE_CURVE) { + const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); + const CurveEval *curve = curve_component.get_for_read(); + if (curve) { + return construct_index_on_spline_varray(*curve, mask, domain); + } + } + return {}; + } + + uint64_t hash() const override + { + /* Some random constant hash. */ + return 4536246522; + } + + bool is_equal_to(const fn::FieldNode &other) const override + { + return dynamic_cast<const IndexOnSplineFieldInput *>(&other) != nullptr; + } +}; + +static void node_geo_exec(GeoNodeExecParams params) { Field<float> parameter_field{std::make_shared<CurveParameterFieldInput>()}; Field<float> length_field{std::make_shared<CurveLengthFieldInput>()}; + Field<int> index_on_spline_field{std::make_shared<IndexOnSplineFieldInput>()}; params.set_output("Factor", std::move(parameter_field)); params.set_output("Length", std::move(length_field)); + params.set_output("Index", std::move(index_on_spline_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_spline_parameter_cc -void register_node_type_geo_curve_parameter() +void register_node_type_geo_curve_spline_parameter() { + namespace file_ns = blender::nodes::node_geo_curve_spline_parameter_cc; + static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_CURVE_PARAMETER, "Curve Parameter", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_curve_parameter_exec; - ntype.declare = blender::nodes::geo_node_curve_parameter_declare; + geo_node_type_base( + &ntype, GEO_NODE_CURVE_SPLINE_PARAMETER, "Spline Parameter", NODE_CLASS_INPUT, 0); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc index ae4453929ac..eef8c1b0db5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc @@ -23,23 +23,23 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_spline_type_cc { -static void geo_node_curve_spline_type_declare(NodeDeclarationBuilder &b) +NODE_STORAGE_FUNCS(NodeGeometryCurveSplineType) + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_spline_type_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "spline_type", 0, "", ICON_NONE); } -static void geo_node_curve_spline_type_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveSplineType *data = (NodeGeometryCurveSplineType *)MEM_callocN( sizeof(NodeGeometryCurveSplineType), __func__); @@ -238,11 +238,10 @@ static SplinePtr convert_to_nurbs(const Spline &input) return {}; } -static void geo_node_curve_spline_type_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { - const NodeGeometryCurveSplineType *storage = - (const NodeGeometryCurveSplineType *)params.node().storage; - const GeometryNodeSplineType output_type = (const GeometryNodeSplineType)storage->spline_type; + const NodeGeometryCurveSplineType &storage = node_storage(params.node()); + const GeometryNodeSplineType output_type = (const GeometryNodeSplineType)storage.spline_type; GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -263,24 +262,28 @@ static void geo_node_curve_spline_type_exec(GeoNodeExecParams params) const VArray<bool> &selection = selection_evaluator.get_evaluated<bool>(0); std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>(); - for (const int i : curve.splines().index_range()) { - if (selection[i]) { - switch (output_type) { - case GEO_NODE_SPLINE_TYPE_POLY: - new_curve->add_spline(convert_to_poly_spline(*curve.splines()[i])); - break; - case GEO_NODE_SPLINE_TYPE_BEZIER: - new_curve->add_spline(convert_to_bezier(*curve.splines()[i], params)); - break; - case GEO_NODE_SPLINE_TYPE_NURBS: - new_curve->add_spline(convert_to_nurbs(*curve.splines()[i])); - break; + new_curve->resize(curve.splines().size()); + + threading::parallel_for(curve.splines().index_range(), 512, [&](IndexRange range) { + for (const int i : range) { + if (selection[i]) { + switch (output_type) { + case GEO_NODE_SPLINE_TYPE_POLY: + new_curve->splines()[i] = convert_to_poly_spline(*curve.splines()[i]); + break; + case GEO_NODE_SPLINE_TYPE_BEZIER: + new_curve->splines()[i] = convert_to_bezier(*curve.splines()[i], params); + break; + case GEO_NODE_SPLINE_TYPE_NURBS: + new_curve->splines()[i] = convert_to_nurbs(*curve.splines()[i]); + break; + } + } + else { + new_curve->splines()[i] = curve.splines()[i]->copy(); } } - else { - new_curve->add_spline(curve.splines()[i]->copy()); - } - } + }); new_curve->attributes = curve.attributes; geometry_set.replace_curve(new_curve.release()); }); @@ -288,21 +291,23 @@ static void geo_node_curve_spline_type_exec(GeoNodeExecParams params) params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_spline_type_cc void register_node_type_geo_curve_spline_type() { + namespace file_ns = blender::nodes::node_geo_curve_spline_type_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_CURVE_SPLINE_TYPE, "Set Spline Type", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_spline_type_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_spline_type_exec; - node_type_init(&ntype, blender::nodes::geo_node_curve_spline_type_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryCurveSplineType", node_free_standard_storage, node_copy_standard_storage); - ntype.draw_buttons = blender::nodes::geo_node_curve_spline_type_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } 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 7c4c17e69e0..6de188fc1c4 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc @@ -25,9 +25,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_subdivide_cc { -static void geo_node_curve_subdivide_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Int>(N_("Cuts")).default_value(1).min(0).max(1000).supports_field(); @@ -322,7 +322,7 @@ static std::unique_ptr<CurveEval> subdivide_curve(const CurveEval &input_curve, return output_curve; } -static void geo_node_subdivide_exec(GeoNodeExecParams params) +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"); @@ -351,14 +351,16 @@ static void geo_node_subdivide_exec(GeoNodeExecParams params) params.set_output("Curve", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_subdivide_cc void register_node_type_geo_curve_subdivide() { + namespace file_ns = blender::nodes::node_geo_curve_subdivide_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE_CURVE, "Subdivide Curve", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_subdivide_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_subdivide_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc index 1977b465de4..ff3e85cb6b7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc @@ -23,9 +23,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_to_mesh_cc { -static void geo_node_curve_to_mesh_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Geometry>(N_("Profile Curve")) @@ -54,7 +54,7 @@ static void geometry_set_curve_to_mesh(GeometrySet &geometry_set, } } -static void geo_node_curve_to_mesh_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet curve_set = params.extract_input<GeometrySet>("Curve"); GeometrySet profile_set = params.extract_input<GeometrySet>("Profile Curve"); @@ -72,14 +72,16 @@ static void geo_node_curve_to_mesh_exec(GeoNodeExecParams params) params.set_output("Mesh", std::move(curve_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_to_mesh_cc void register_node_type_geo_curve_to_mesh() { + namespace file_ns = blender::nodes::node_geo_curve_to_mesh_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_CURVE_TO_MESH, "Curve to Mesh", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_to_mesh_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_to_mesh_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc index b9f129a5f75..0e9425246cb 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 @@ -27,24 +27,50 @@ #include "node_geometry_util.hh" namespace blender::nodes { +void curve_create_default_rotation_attribute(Span<float3> tangents, + Span<float3> normals, + MutableSpan<float3> rotations) +{ + threading::parallel_for(IndexRange(rotations.size()), 512, [&](IndexRange range) { + for (const int i : range) { + rotations[i] = + float4x4::from_normalized_axis_data({0, 0, 0}, normals[i], tangents[i]).to_euler(); + } + }); +} +} // namespace blender::nodes + +namespace blender::nodes::node_geo_curve_to_points_cc { + +NODE_STORAGE_FUNCS(NodeGeometryCurveToPoints) -static void geo_node_curve_to_points_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); - b.add_input<decl::Int>(N_("Count")).default_value(10).min(2).max(100000); - b.add_input<decl::Float>(N_("Length")).default_value(0.1f).min(0.001f).subtype(PROP_DISTANCE); + b.add_input<decl::Int>(N_("Count")) + .default_value(10) + .min(2) + .max(100000) + .make_available( + [](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_RESAMPLE_COUNT; }); + b.add_input<decl::Float>(N_("Length")) + .default_value(0.1f) + .min(0.001f) + .subtype(PROP_DISTANCE) + .make_available( + [](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_RESAMPLE_LENGTH; }); b.add_output<decl::Geometry>(N_("Points")); b.add_output<decl::Vector>(N_("Tangent")).field_source(); b.add_output<decl::Vector>(N_("Normal")).field_source(); b.add_output<decl::Vector>(N_("Rotation")).field_source(); } -static void geo_node_curve_to_points_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); } -static void geo_node_curve_to_points_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveToPoints *data = (NodeGeometryCurveToPoints *)MEM_callocN( sizeof(NodeGeometryCurveToPoints), __func__); @@ -53,10 +79,10 @@ static void geo_node_curve_to_points_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_curve_to_points_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { - NodeGeometryCurveToPoints &node_storage = *(NodeGeometryCurveToPoints *)node->storage; - const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode; + const NodeGeometryCurveToPoints &storage = node_storage(*node); + const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)storage.mode; bNodeSocket *count_socket = ((bNodeSocket *)node->inputs.first)->next; bNodeSocket *length_socket = count_socket->next; @@ -78,9 +104,14 @@ static Array<int> calculate_spline_point_offsets(GeoNodeExecParams ¶ms, return {0}; } Array<int> offsets(size + 1); - for (const int i : offsets.index_range()) { - offsets[i] = count * i; + int offset = 0; + for (const int i : IndexRange(size)) { + offsets[i] = offset; + if (splines[i]->evaluated_points_size() > 0) { + offset += count; + } } + offsets.last() = offset; return offsets; } case GEO_NODE_CURVE_RESAMPLE_LENGTH: { @@ -90,7 +121,9 @@ static Array<int> calculate_spline_point_offsets(GeoNodeExecParams ¶ms, int offset = 0; for (const int i : IndexRange(size)) { offsets[i] = offset; - offset += splines[i]->length() / resolution + 1; + if (splines[i]->evaluated_points_size() > 0) { + offset += splines[i]->length() / resolution + 1; + } } offsets.last() = offset; return offsets; @@ -289,22 +322,10 @@ static void copy_spline_domain_attributes(const CurveEval &curve, ATTR_DOMAIN_CURVE); } -void curve_create_default_rotation_attribute(Span<float3> tangents, - Span<float3> normals, - MutableSpan<float3> rotations) +static void node_geo_exec(GeoNodeExecParams params) { - threading::parallel_for(IndexRange(rotations.size()), 512, [&](IndexRange range) { - for (const int i : range) { - rotations[i] = - float4x4::from_normalized_axis_data({0, 0, 0}, normals[i], tangents[i]).to_euler(); - } - }); -} - -static void geo_node_curve_to_points_exec(GeoNodeExecParams params) -{ - NodeGeometryCurveToPoints &node_storage = *(NodeGeometryCurveToPoints *)params.node().storage; - const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode; + const NodeGeometryCurveToPoints &storage = node_storage(params.node()); + const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)storage.mode; GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); AnonymousAttributeIDs attribute_outputs; @@ -374,20 +395,21 @@ static void geo_node_curve_to_points_exec(GeoNodeExecParams params) } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_to_points_cc void register_node_type_geo_curve_to_points() { + namespace file_ns = blender::nodes::node_geo_curve_to_points_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_CURVE_TO_POINTS, "Curve to Points", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_to_points_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_to_points_exec; - ntype.draw_buttons = blender::nodes::geo_node_curve_to_points_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; node_type_storage( &ntype, "NodeGeometryCurveToPoints", node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_curve_to_points_init); - node_type_update(&ntype, blender::nodes::geo_node_curve_to_points_update); - + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc index b281876d314..746392a66cc 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc @@ -20,40 +20,52 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "NOD_socket_search_link.hh" + #include "node_geometry_util.hh" +namespace blender::nodes::node_geo_curve_trim_cc { + using blender::attribute_math::mix2; -namespace blender::nodes { +NODE_STORAGE_FUNCS(NodeGeometryCurveTrim) -static void geo_node_curve_trim_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); - b.add_input<decl::Float>(N_("Start")).min(0.0f).max(1.0f).subtype(PROP_FACTOR).supports_field(); + b.add_input<decl::Float>(N_("Start")) + .min(0.0f) + .max(1.0f) + .subtype(PROP_FACTOR) + .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_FACTOR; }) + .supports_field(); b.add_input<decl::Float>(N_("End")) .min(0.0f) .max(1.0f) .default_value(1.0f) .subtype(PROP_FACTOR) + .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_FACTOR; }) .supports_field(); b.add_input<decl::Float>(N_("Start"), "Start_001") .min(0.0f) .subtype(PROP_DISTANCE) + .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_LENGTH; }) .supports_field(); b.add_input<decl::Float>(N_("End"), "End_001") .min(0.0f) .default_value(1.0f) .subtype(PROP_DISTANCE) + .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_LENGTH; }) .supports_field(); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_trim_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_curve_trim_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveTrim *data = (NodeGeometryCurveTrim *)MEM_callocN(sizeof(NodeGeometryCurveTrim), __func__); @@ -62,10 +74,10 @@ static void geo_node_curve_trim_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_curve_trim_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { - const NodeGeometryCurveTrim &node_storage = *(NodeGeometryCurveTrim *)node->storage; - const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode; + const NodeGeometryCurveTrim &storage = node_storage(*node); + const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)storage.mode; bNodeSocket *start_fac = ((bNodeSocket *)node->inputs.first)->next; bNodeSocket *end_fac = start_fac->next; @@ -78,6 +90,38 @@ static void geo_node_curve_trim_update(bNodeTree *ntree, bNode *node) nodeSetSocketAvailability(ntree, end_len, mode == GEO_NODE_CURVE_SAMPLE_LENGTH); } +class SocketSearchOp { + public: + StringRef socket_name; + GeometryNodeCurveSampleMode mode; + void operator()(LinkSearchOpParams ¶ms) + { + bNode &node = params.add_node("GeometryNodeTrimCurve"); + node_storage(node).mode = mode; + params.update_and_connect_available_socket(node, socket_name); + } +}; + +static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) +{ + const NodeDeclaration &declaration = *params.node_type().fixed_declaration; + + search_link_ops_for_declarations(params, declaration.outputs()); + 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)) { + 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}); + params.add_item(IFACE_("Start (Length)"), + SocketSearchOp{"Start", GEO_NODE_CURVE_SAMPLE_LENGTH}); + params.add_item(IFACE_("End (Length)"), SocketSearchOp{"End", GEO_NODE_CURVE_SAMPLE_LENGTH}); + } + } +} + struct TrimLocation { /* Control point index at the start side of the trim location. */ int left_index; @@ -532,10 +576,10 @@ static void geometry_set_curve_trim(GeometrySet &geometry_set, }); } -static void geo_node_curve_trim_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { - const NodeGeometryCurveTrim &node_storage = *(NodeGeometryCurveTrim *)params.node().storage; - const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode; + const NodeGeometryCurveTrim &storage = node_storage(params.node()); + const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)storage.mode; GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); @@ -557,18 +601,21 @@ static void geo_node_curve_trim_exec(GeoNodeExecParams params) params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_trim_cc void register_node_type_geo_curve_trim() { + namespace file_ns = blender::nodes::node_geo_curve_trim_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_TRIM_CURVE, "Trim Curve", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_curve_trim_exec; - ntype.draw_buttons = blender::nodes::geo_node_curve_trim_layout; - ntype.declare = blender::nodes::geo_node_curve_trim_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + ntype.declare = file_ns::node_declare; node_type_storage( &ntype, "NodeGeometryCurveTrim", node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_curve_trim_init); - node_type_update(&ntype, blender::nodes::geo_node_curve_trim_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.gather_link_search_ops = file_ns::node_gather_link_searches; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc index d07644f8403..1de809b30e4 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc @@ -29,63 +29,26 @@ #include "node_geometry_util.hh" -using blender::bke::CustomDataAttributes; - -/* Code from the mask modifier in MOD_mask.cc. */ -extern void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh, - Mesh &dst_mesh, - blender::Span<int> vertex_map); -extern void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, - Mesh &dst_mesh, - blender::Span<int> vertex_map, - blender::Span<int> edge_map); -extern void copy_masked_polys_to_new_mesh(const Mesh &src_mesh, - Mesh &dst_mesh, - blender::Span<int> vertex_map, - blender::Span<int> edge_map, - blender::Span<int> masked_poly_indices, - blender::Span<int> new_loop_starts); - namespace blender::nodes { -static void geo_node_delete_geometry_declare(NodeDeclarationBuilder &b) -{ - b.add_input<decl::Geometry>(N_("Geometry")); - b.add_input<decl::Bool>(N_("Selection")) - .default_value(true) - .hide_value() - .supports_field() - .description(N_("The parts of the geometry to be deleted")); - b.add_output<decl::Geometry>(N_("Geometry")); -} +using blender::bke::CustomDataAttributes; -static void geo_node_delete_geometry_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +template<typename T> +static void copy_data_based_on_mask(Span<T> data, MutableSpan<T> r_data, IndexMask mask) { - const bNode *node = static_cast<bNode *>(ptr->data); - const NodeGeometryDeleteGeometry &storage = *(const NodeGeometryDeleteGeometry *)node->storage; - const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain); - - uiItemR(layout, ptr, "domain", 0, "", ICON_NONE); - /* Only show the mode when it is relevant. */ - if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE)) { - uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); + for (const int i_out : mask.index_range()) { + r_data[i_out] = data[mask[i_out]]; } } -static void geo_node_delete_geometry_init(bNodeTree *UNUSED(tree), bNode *node) -{ - NodeGeometryDeleteGeometry *data = (NodeGeometryDeleteGeometry *)MEM_callocN( - sizeof(NodeGeometryDeleteGeometry), __func__); - data->domain = ATTR_DOMAIN_POINT; - data->mode = GEO_NODE_DELETE_GEOMETRY_MODE_ALL; - - node->storage = data; -} - -template<typename T> static void copy_data(Span<T> data, MutableSpan<T> r_data, IndexMask mask) +template<typename T> +static void copy_data_based_on_map(Span<T> src, MutableSpan<T> dst, Span<int> index_map) { - for (const int i_out : mask.index_range()) { - r_data[i_out] = data[mask[i_out]]; + for (const int i_src : index_map.index_range()) { + const int i_dst = index_map[i_src]; + if (i_dst != -1) { + dst[i_dst] = src[i_src]; + } } } @@ -102,23 +65,6 @@ static IndexMask index_mask_indices(Span<bool> mask, const bool invert, Vector<i return IndexMask(indices); } -/** Utility function for making an IndexMask from an array of integers, where the negative integers - * are seen as false. The indices vector should live at least as long as the returned IndexMask. - */ -static IndexMask index_mask_indices(Span<int> mask, - const int num_indices, - Vector<int64_t> &indices) -{ - indices.clear(); - indices.reserve(num_indices); - for (const int i : mask.index_range()) { - if (mask[i] >= 0) { - indices.append_unchecked(i); - } - } - return IndexMask(indices); -} - /** * Copies the attributes with a domain in `domains` to `result_component`. */ @@ -191,12 +137,87 @@ static void copy_attributes_based_on_mask(const Map<AttributeIDRef, AttributeKin using T = decltype(dummy); VArray_Span<T> span{attribute.varray.typed<T>()}; MutableSpan<T> out_span = result_attribute.as_span<T>(); - copy_data(span, out_span, mask); + copy_data_based_on_mask(span, out_span, mask); }); result_attribute.save(); } } +static void copy_attributes_based_on_map(const Map<AttributeIDRef, AttributeKind> &attributes, + const GeometryComponent &in_component, + GeometryComponent &result_component, + const AttributeDomain domain, + const Span<int> index_map) +{ + for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) { + const AttributeIDRef attribute_id = entry.key; + ReadAttributeLookup attribute = in_component.attribute_try_get_for_read(attribute_id); + if (!attribute) { + continue; + } + + /* Only copy if it is on a domain we want. */ + if (domain != attribute.domain) { + continue; + } + const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); + + OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only( + attribute_id, attribute.domain, data_type); + + if (!result_attribute) { + continue; + } + + attribute_math::convert_to_static_type(data_type, [&](auto dummy) { + using T = decltype(dummy); + VArray_Span<T> span{attribute.varray.typed<T>()}; + MutableSpan<T> out_span = result_attribute.as_span<T>(); + copy_data_based_on_map(span, out_span, index_map); + }); + result_attribute.save(); + } +} + +static void copy_face_corner_attributes(const Map<AttributeIDRef, AttributeKind> &attributes, + const GeometryComponent &in_component, + GeometryComponent &out_component, + const int num_selected_loops, + const Span<int> selected_poly_indices, + const Mesh &mesh_in) +{ + Vector<int64_t> indices; + indices.reserve(num_selected_loops); + for (const int src_poly_index : selected_poly_indices) { + const MPoly &src_poly = mesh_in.mpoly[src_poly_index]; + const int src_loop_start = src_poly.loopstart; + const int tot_loop = src_poly.totloop; + for (const int i : IndexRange(tot_loop)) { + indices.append_unchecked(src_loop_start + i); + } + } + copy_attributes_based_on_mask( + attributes, in_component, out_component, ATTR_DOMAIN_CORNER, IndexMask(indices)); +} + +static void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + Span<int> vertex_map) +{ + BLI_assert(src_mesh.totvert == vertex_map.size()); + for (const int i_src : vertex_map.index_range()) { + const int i_dst = vertex_map[i_src]; + if (i_dst == -1) { + continue; + } + + const MVert &v_src = src_mesh.mvert[i_src]; + MVert &v_dst = dst_mesh.mvert[i_dst]; + + v_dst = v_src; + } +} + static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, Mesh &dst_mesh, Span<int> edge_map) { BLI_assert(src_mesh.totedge == edge_map.size()); @@ -215,6 +236,28 @@ static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, Mesh &dst_mesh, } } +static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + Span<int> vertex_map, + Span<int> edge_map) +{ + BLI_assert(src_mesh.totvert == vertex_map.size()); + BLI_assert(src_mesh.totedge == edge_map.size()); + for (const int i_src : IndexRange(src_mesh.totedge)) { + const int i_dst = edge_map[i_src]; + if (i_dst == -1) { + continue; + } + + const MEdge &e_src = src_mesh.medge[i_src]; + MEdge &e_dst = dst_mesh.medge[i_dst]; + + e_dst = e_src; + e_dst.v1 = vertex_map[e_src.v1]; + e_dst.v2 = vertex_map[e_src.v2]; + } +} + /* Faces and edges changed but vertices are the same. */ static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh, Mesh &dst_mesh, @@ -268,29 +311,56 @@ static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh, } } +static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + Span<int> vertex_map, + Span<int> edge_map, + Span<int> masked_poly_indices, + Span<int> new_loop_starts) +{ + for (const int i_dst : masked_poly_indices.index_range()) { + const int i_src = masked_poly_indices[i_dst]; + + const MPoly &mp_src = src_mesh.mpoly[i_src]; + MPoly &mp_dst = dst_mesh.mpoly[i_dst]; + const int i_ml_src = mp_src.loopstart; + const int i_ml_dst = new_loop_starts[i_dst]; + + const MLoop *ml_src = src_mesh.mloop + i_ml_src; + MLoop *ml_dst = dst_mesh.mloop + i_ml_dst; + + mp_dst = mp_src; + mp_dst.loopstart = i_ml_dst; + for (int i : IndexRange(mp_src.totloop)) { + ml_dst[i].v = vertex_map[ml_src[i].v]; + ml_dst[i].e = edge_map[ml_src[i].e]; + } + } +} + static void spline_copy_builtin_attributes(const Spline &spline, Spline &r_spline, const IndexMask mask) { - copy_data(spline.positions(), r_spline.positions(), mask); - copy_data(spline.radii(), r_spline.radii(), mask); - copy_data(spline.tilts(), r_spline.tilts(), mask); + copy_data_based_on_mask(spline.positions(), r_spline.positions(), mask); + copy_data_based_on_mask(spline.radii(), r_spline.radii(), mask); + copy_data_based_on_mask(spline.tilts(), r_spline.tilts(), mask); switch (spline.type()) { case Spline::Type::Poly: break; case Spline::Type::Bezier: { const BezierSpline &src = static_cast<const BezierSpline &>(spline); BezierSpline &dst = static_cast<BezierSpline &>(r_spline); - copy_data(src.handle_positions_left(), dst.handle_positions_left(), mask); - copy_data(src.handle_positions_right(), dst.handle_positions_right(), mask); - copy_data(src.handle_types_left(), dst.handle_types_left(), mask); - copy_data(src.handle_types_right(), dst.handle_types_right(), mask); + copy_data_based_on_mask(src.handle_positions_left(), dst.handle_positions_left(), mask); + copy_data_based_on_mask(src.handle_positions_right(), dst.handle_positions_right(), mask); + copy_data_based_on_mask(src.handle_types_left(), dst.handle_types_left(), mask); + copy_data_based_on_mask(src.handle_types_right(), dst.handle_types_right(), mask); break; } case Spline::Type::NURBS: { const NURBSpline &src = static_cast<const NURBSpline &>(spline); NURBSpline &dst = static_cast<NURBSpline &>(r_spline); - copy_data(src.weights(), dst.weights(), mask); + copy_data_based_on_mask(src.weights(), dst.weights(), mask); break; } } @@ -316,7 +386,7 @@ static void copy_dynamic_attributes(const CustomDataAttributes &src, attribute_math::convert_to_static_type(new_attribute->type(), [&](auto dummy) { using T = decltype(dummy); - copy_data(src_attribute->typed<T>(), new_attribute->typed<T>(), mask); + copy_data_based_on_mask(src_attribute->typed<T>(), new_attribute->typed<T>(), mask); }); return true; }, @@ -986,6 +1056,23 @@ static void do_mesh_separation(GeometrySet &geometry_set, copy_masked_edges_to_new_mesh(mesh_in, *mesh_out, vertex_map, edge_map); copy_masked_polys_to_new_mesh( mesh_in, *mesh_out, vertex_map, edge_map, selected_poly_indices, new_loop_starts); + + /* Copy attributes. */ + copy_attributes_based_on_map( + attributes, in_component, out_component, ATTR_DOMAIN_POINT, vertex_map); + copy_attributes_based_on_map( + attributes, in_component, out_component, ATTR_DOMAIN_EDGE, edge_map); + copy_attributes_based_on_mask(attributes, + in_component, + out_component, + ATTR_DOMAIN_FACE, + IndexMask(Vector<int64_t>(selected_poly_indices.as_span()))); + copy_face_corner_attributes(attributes, + in_component, + out_component, + num_selected_loops, + selected_poly_indices, + mesh_in); break; } case GEO_NODE_DELETE_GEOMETRY_MODE_EDGE_FACE: { @@ -1041,22 +1128,25 @@ static void do_mesh_separation(GeometrySet &geometry_set, /* Copy the selected parts of the mesh over to the new mesh. */ memcpy(mesh_out->mvert, mesh_in.mvert, mesh_in.totvert * sizeof(MVert)); - copy_attributes(attributes, in_component, out_component, {ATTR_DOMAIN_POINT}); copy_masked_edges_to_new_mesh(mesh_in, *mesh_out, edge_map); copy_masked_polys_to_new_mesh( mesh_in, *mesh_out, edge_map, selected_poly_indices, new_loop_starts); - Vector<int64_t> indices; + + /* Copy attributes. */ + copy_attributes(attributes, in_component, out_component, {ATTR_DOMAIN_POINT}); + copy_attributes_based_on_map( + attributes, in_component, out_component, ATTR_DOMAIN_EDGE, edge_map); copy_attributes_based_on_mask(attributes, in_component, out_component, - ATTR_DOMAIN_EDGE, - index_mask_indices(edge_map, num_selected_edges, indices)); - copy_attributes_based_on_mask( - attributes, - in_component, - out_component, - ATTR_DOMAIN_FACE, - index_mask_indices(selected_poly_indices, num_selected_polys, indices)); + ATTR_DOMAIN_FACE, + IndexMask(Vector<int64_t>(selected_poly_indices.as_span()))); + copy_face_corner_attributes(attributes, + in_component, + out_component, + num_selected_loops, + selected_poly_indices, + mesh_in); break; } case GEO_NODE_DELETE_GEOMETRY_MODE_ONLY_FACE: { @@ -1100,14 +1190,22 @@ static void do_mesh_separation(GeometrySet &geometry_set, /* Copy the selected parts of the mesh over to the new mesh. */ memcpy(mesh_out->mvert, mesh_in.mvert, mesh_in.totvert * sizeof(MVert)); memcpy(mesh_out->medge, mesh_in.medge, mesh_in.totedge * sizeof(MEdge)); + copy_masked_polys_to_new_mesh(mesh_in, *mesh_out, selected_poly_indices, new_loop_starts); + + /* Copy attributes. */ copy_attributes( attributes, in_component, out_component, {ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE}); - copy_masked_polys_to_new_mesh(mesh_in, *mesh_out, selected_poly_indices, new_loop_starts); - Vector<int64_t> indices; - const IndexMask mask = index_mask_indices( - selected_poly_indices, num_selected_polys, indices); - copy_attributes_based_on_mask( - attributes, in_component, out_component, ATTR_DOMAIN_FACE, mask); + copy_attributes_based_on_mask(attributes, + in_component, + out_component, + ATTR_DOMAIN_FACE, + IndexMask(Vector<int64_t>(selected_poly_indices.as_span()))); + copy_face_corner_attributes(attributes, + in_component, + out_component, + num_selected_loops, + selected_poly_indices, + mesh_in); break; } } @@ -1177,17 +1275,55 @@ void separate_geometry(GeometrySet &geometry_set, r_is_error = !some_valid_domain && geometry_set.has_realized_data(); } -static void geo_node_delete_geometry_exec(GeoNodeExecParams params) +} // namespace blender::nodes + +namespace blender::nodes::node_geo_delete_geometry_cc { + +NODE_STORAGE_FUNCS(NodeGeometryDeleteGeometry) + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Geometry>(N_("Geometry")); + b.add_input<decl::Bool>(N_("Selection")) + .default_value(true) + .hide_value() + .supports_field() + .description(N_("The parts of the geometry to be deleted")); + b.add_output<decl::Geometry>(N_("Geometry")); +} + +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + const bNode *node = static_cast<bNode *>(ptr->data); + const NodeGeometryDeleteGeometry &storage = node_storage(*node); + const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain); + + uiItemR(layout, ptr, "domain", 0, "", ICON_NONE); + /* Only show the mode when it is relevant. */ + if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE)) { + uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); + } +} + +static void node_init(bNodeTree *UNUSED(tree), bNode *node) +{ + NodeGeometryDeleteGeometry *data = (NodeGeometryDeleteGeometry *)MEM_callocN( + sizeof(NodeGeometryDeleteGeometry), __func__); + data->domain = ATTR_DOMAIN_POINT; + data->mode = GEO_NODE_DELETE_GEOMETRY_MODE_ALL; + + node->storage = data; +} + +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); - const bNode &node = params.node(); - const NodeGeometryDeleteGeometry &storage = *(const NodeGeometryDeleteGeometry *)node.storage; + const NodeGeometryDeleteGeometry &storage = node_storage(params.node()); const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain); - const GeometryNodeDeleteGeometryMode mode = static_cast<GeometryNodeDeleteGeometryMode>( - storage.mode); + const GeometryNodeDeleteGeometryMode mode = (GeometryNodeDeleteGeometryMode)storage.mode; bool all_is_error = false; geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { @@ -1204,10 +1340,12 @@ static void geo_node_delete_geometry_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_delete_geometry_cc void register_node_type_geo_delete_geometry() { + namespace file_ns = blender::nodes::node_geo_delete_geometry_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_DELETE_GEOMETRY, "Delete Geometry", NODE_CLASS_GEOMETRY, 0); @@ -1217,10 +1355,10 @@ void register_node_type_geo_delete_geometry() node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_delete_geometry_init); + node_type_init(&ntype, file_ns::node_init); - ntype.declare = blender::nodes::geo_node_delete_geometry_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_delete_geometry_exec; - ntype.draw_buttons = blender::nodes::geo_node_delete_geometry_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } 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 b2c76b76590..3537b62c76e 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 @@ -36,11 +36,9 @@ #include "node_geometry_util.hh" -using blender::bke::GeometryInstanceGroup; +namespace blender::nodes::node_geo_distribute_points_on_faces_cc { -namespace blender::nodes { - -static void geo_node_point_distribute_points_on_faces_declare(NodeDeclarationBuilder &b) +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).hide_value().supports_field(); @@ -60,9 +58,7 @@ static void geo_node_point_distribute_points_on_faces_declare(NodeDeclarationBui b.add_output<decl::Vector>(N_("Rotation")).subtype(PROP_EULER).field_source(); } -static void geo_node_point_distribute_points_on_faces_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "distribute_method", 0, "", ICON_NONE); } @@ -403,16 +399,12 @@ static Array<float> calc_full_density_factors_with_selection(const MeshComponent GeometryComponentFieldContext field_context{component, attribute_domain}; const int domain_size = component.attribute_domain_size(attribute_domain); - fn::FieldEvaluator selection_evaluator{field_context, domain_size}; - selection_evaluator.add(selection_field); - selection_evaluator.evaluate(); - const IndexMask selection_mask = selection_evaluator.get_evaluated_as_mask(0); - Array<float> densities(domain_size, 0.0f); - fn::FieldEvaluator density_evaluator{field_context, &selection_mask}; - density_evaluator.add_with_destination(density_field, densities.as_mutable_span()); - density_evaluator.evaluate(); + fn::FieldEvaluator evaluator{field_context, domain_size}; + evaluator.set_selection(selection_field); + evaluator.add_with_destination(density_field, densities.as_mutable_span()); + evaluator.evaluate(); return densities; } @@ -528,7 +520,7 @@ static void point_distribution_calculate(GeometrySet &geometry_set, mesh_component, point_component, bary_coords, looptri_indices, attribute_outputs); } -static void geo_node_point_distribute_points_on_faces_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); @@ -570,10 +562,12 @@ static void geo_node_point_distribute_points_on_faces_exec(GeoNodeExecParams par } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_distribute_points_on_faces_cc void register_node_type_geo_distribute_points_on_faces() { + namespace file_ns = blender::nodes::node_geo_distribute_points_on_faces_cc; + static bNodeType ntype; geo_node_type_base(&ntype, @@ -581,10 +575,10 @@ void register_node_type_geo_distribute_points_on_faces() "Distribute Points on Faces", NODE_CLASS_GEOMETRY, 0); - node_type_update(&ntype, blender::nodes::node_point_distribute_points_on_faces_update); + node_type_update(&ntype, file_ns::node_point_distribute_points_on_faces_update); node_type_size(&ntype, 170, 100, 320); - ntype.declare = blender::nodes::geo_node_point_distribute_points_on_faces_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_point_distribute_points_on_faces_exec; - ntype.draw_buttons = blender::nodes::geo_node_point_distribute_points_on_faces_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc new file mode 100644 index 00000000000..a3bbeca7af3 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc @@ -0,0 +1,847 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "BLI_task.hh" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_attribute_math.hh" +#include "BKE_mesh.h" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_dual_mesh_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Geometry>("Mesh").supported_type(GEO_COMPONENT_TYPE_MESH); + b.add_input<decl::Bool>("Keep Boundaries") + .default_value(false) + .description( + "Keep non-manifold boundaries of the input mesh in place by avoiding the dual " + "transformation there"); + b.add_output<decl::Geometry>("Dual Mesh"); +} + +enum class EdgeType : int8_t { + Loose = 0, /* No polygons connected to it. */ + Boundary = 1, /* An edge connected to exactly one polygon. */ + Normal = 2, /* A normal edge (connected to two polygons). */ + NonManifold = 3, /* An edge connected to more than two polygons. */ +}; + +static EdgeType get_edge_type_with_added_neighbor(EdgeType old_type) +{ + switch (old_type) { + case EdgeType::Loose: + return EdgeType::Boundary; + case EdgeType::Boundary: + return EdgeType::Normal; + case EdgeType::Normal: + case EdgeType::NonManifold: + return EdgeType::NonManifold; + } + BLI_assert_unreachable(); + return EdgeType::Loose; +} + +enum class VertexType : int8_t { + Loose = 0, /* Either no edges connected or only loose edges connected. */ + Normal = 1, /* A normal vertex. */ + Boundary = 2, /* A vertex on a boundary edge. */ + NonManifold = 3, /* A vertex on a non-manifold edge. */ +}; + +static VertexType get_vertex_type_with_added_neighbor(VertexType old_type) +{ + switch (old_type) { + case VertexType::Loose: + return VertexType::Normal; + case VertexType::Normal: + return VertexType::Boundary; + case VertexType::Boundary: + case VertexType::NonManifold: + return VertexType::NonManifold; + } + BLI_assert_unreachable(); + return VertexType::Loose; +} + +/* Copy only where vertex_types is 'normal'. If keep boundaries is selected, also copy from + * boundary vertices. */ +template<typename T> +static void copy_data_based_on_vertex_types(Span<T> data, + MutableSpan<T> r_data, + const Span<VertexType> vertex_types, + const bool keep_boundaries) +{ + if (keep_boundaries) { + int out_i = 0; + for (const int i : data.index_range()) { + if (ELEM(vertex_types[i], VertexType::Normal, VertexType::Boundary)) { + r_data[out_i] = data[i]; + out_i++; + } + } + } + else { + int out_i = 0; + for (const int i : data.index_range()) { + if (vertex_types[i] == VertexType::Normal) { + r_data[out_i] = data[i]; + out_i++; + } + } + } +} + +template<typename T> +static void copy_data_based_on_pairs(Span<T> data, + MutableSpan<T> r_data, + const Span<std::pair<int, int>> new_to_old_map) +{ + for (const std::pair<int, int> &pair : new_to_old_map) { + r_data[pair.first] = data[pair.second]; + } +} + +/* Copy using the map. */ +template<typename T> +static void copy_data_based_on_new_to_old_map(Span<T> data, + MutableSpan<T> r_data, + const Span<int> new_to_old_map) +{ + for (const int i : r_data.index_range()) { + const int old_i = new_to_old_map[i]; + r_data[i] = data[old_i]; + } +} + +/** + * Transfers the attributes from the original mesh to the new mesh using the following logic: + * - If the attribute was on the face domain it is now on the point domain, and this is true + * for all faces, so we can just copy these. + * - If the attribute was on the vertex domain there are three cases: + * - It was a 'bad' vertex so it is not in the dual mesh, and we can just ignore it + * - It was a normal vertex so it has a corresponding face in the dual mesh to which we can + * transfer. + * - It was a boundary vertex so it has a corresponding face, if keep_boundaries is true. + * Otherwise we can just ignore it. + * - If the attribute was on the edge domain we lookup for the new edges which edge it originated + * from using `new_to_old_edges_map`. We have to do it in this reverse order, because there can + * be more edges in the new mesh if keep boundaries is on. + * - We do the same thing for face corners as we do for edges. + * + * Some of the vertices (on the boundary) in the dual mesh don't come from faces, but from edges or + * vertices. For these the `boundary_vertex_to_relevant_face_map` is used, which maps them to the + * closest face. + */ +static void transfer_attributes( + const Map<AttributeIDRef, AttributeKind> &attributes, + const Span<VertexType> vertex_types, + const bool keep_boundaries, + const Span<int> new_to_old_edges_map, + const Span<int> new_to_old_face_corners_map, + const Span<std::pair<int, int>> boundary_vertex_to_relevant_face_map, + const GeometryComponent &src_component, + GeometryComponent &dst_component) +{ + for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) { + const AttributeIDRef attribute_id = entry.key; + ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read(attribute_id); + if (!src_attribute) { + continue; + } + + AttributeDomain out_domain; + if (src_attribute.domain == ATTR_DOMAIN_FACE) { + out_domain = ATTR_DOMAIN_POINT; + } + else if (src_attribute.domain == ATTR_DOMAIN_POINT) { + out_domain = ATTR_DOMAIN_FACE; + } + else { + /* Edges and Face Corners. */ + out_domain = src_attribute.domain; + } + const CustomDataType data_type = bke::cpp_type_to_custom_data_type( + src_attribute.varray.type()); + OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( + attribute_id, out_domain, data_type); + + if (!dst_attribute) { + continue; + } + + attribute_math::convert_to_static_type(data_type, [&](auto dummy) { + using T = decltype(dummy); + VArray_Span<T> span{src_attribute.varray.typed<T>()}; + MutableSpan<T> dst_span = dst_attribute.as_span<T>(); + if (src_attribute.domain == ATTR_DOMAIN_FACE) { + dst_span.take_front(span.size()).copy_from(span); + if (keep_boundaries) { + copy_data_based_on_pairs(span, dst_span, boundary_vertex_to_relevant_face_map); + } + } + else if (src_attribute.domain == ATTR_DOMAIN_POINT) { + copy_data_based_on_vertex_types(span, dst_span, vertex_types, keep_boundaries); + } + else if (src_attribute.domain == ATTR_DOMAIN_EDGE) { + copy_data_based_on_new_to_old_map(span, dst_span, new_to_old_edges_map); + } + else { + copy_data_based_on_new_to_old_map(span, dst_span, new_to_old_face_corners_map); + } + }); + dst_attribute.save(); + } +} + +/** + * Calculates the boundaries of the mesh. Boundary polygons are not computed since we don't need + * them later on. We use the following definitions: + * - An edge is on a boundary if it is connected to only one polygon. + * - A vertex is on a boundary if it is on an edge on a boundary. + */ +static void calc_boundaries(const Mesh &mesh, + MutableSpan<VertexType> r_vertex_types, + MutableSpan<EdgeType> r_edge_types) +{ + BLI_assert(r_vertex_types.size() == mesh.totvert); + BLI_assert(r_edge_types.size() == mesh.totedge); + r_vertex_types.fill(VertexType::Loose); + r_edge_types.fill(EdgeType::Loose); + + /* Add up the number of polys connected to each edge. */ + for (const int i : IndexRange(mesh.totpoly)) { + const MPoly &poly = mesh.mpoly[i]; + for (const MLoop &loop : Span<MLoop>(&mesh.mloop[poly.loopstart], poly.totloop)) { + r_edge_types[loop.e] = get_edge_type_with_added_neighbor(r_edge_types[loop.e]); + } + } + + /* Update vertices. */ + for (const int i : IndexRange(mesh.totedge)) { + const EdgeType edge_type = r_edge_types[i]; + if (edge_type == EdgeType::Loose) { + continue; + } + const MEdge &edge = mesh.medge[i]; + if (edge_type == EdgeType::Boundary) { + r_vertex_types[edge.v1] = get_vertex_type_with_added_neighbor(r_vertex_types[edge.v1]); + r_vertex_types[edge.v2] = get_vertex_type_with_added_neighbor(r_vertex_types[edge.v2]); + } + else if (edge_type >= EdgeType::NonManifold) { + r_vertex_types[edge.v1] = VertexType::NonManifold; + r_vertex_types[edge.v2] = VertexType::NonManifold; + } + } + + /* Normal verts are on a normal edge, and not on boundary edges or non-manifold edges. */ + for (const int i : IndexRange(mesh.totedge)) { + const EdgeType edge_type = r_edge_types[i]; + if (edge_type == EdgeType::Normal) { + const MEdge &edge = mesh.medge[i]; + if (r_vertex_types[edge.v1] == VertexType::Loose) { + r_vertex_types[edge.v1] = VertexType::Normal; + } + if (r_vertex_types[edge.v2] == VertexType::Loose) { + r_vertex_types[edge.v2] = VertexType::Normal; + } + } + } +} + +/** + * Stores the indices of the polygons connected to each vertex. + */ +static void create_vertex_poly_map(const Mesh &mesh, + MutableSpan<Vector<int>> r_vertex_poly_indices) +{ + for (const int i : IndexRange(mesh.totpoly)) { + const MPoly &poly = mesh.mpoly[i]; + for (const MLoop &loop : Span<MLoop>(&mesh.mloop[poly.loopstart], poly.totloop)) { + r_vertex_poly_indices[loop.v].append(i); + } + } +} + +/** + * Sorts the polygons connected to the given vertex based on polygon adjacency. The ordering is + * so such that the normals point in the same way as the original mesh. If the vertex is a + * boundary vertex, the first and last polygon have a boundary edge connected to the vertex. The + * `r_shared_edges` array at index i is set to the index of the shared edge between the i-th and + * `(i+1)-th` sorted polygon. Similarly the `r_sorted_corners` array at index i is set to the + * corner in the i-th sorted polygon. + * + * How the faces are sorted (see diagrams below): + * (For this explanation we'll assume all faces are oriented clockwise) + * (The vertex whose connected polygons we need to sort is "v0") + * + * \code{.unparsed} + * Normal case: Boundary Vertex case: + * v1 ----- v2 ----- v3 | | | + * | f3 | f0 | v2 ---- v4 --------- v3--- + * | | | | / ,-' | + * v8 ----- v0 ----- v4 | f0 / f1 ,-' | + * | f2 | f1 | | / ,-' | + * | | | | / ,-' | + * v7 ----- v6 ----- v5 | / ,-' f2 | + * | /,-' | + * v0 ------------------ v1--- + * \endcode + * + * - First we get the two corners of each face that have an edge which contains v0. A corner is + * simply a vertex followed by an edge. In this case for the face "f0" for example, we'd end up + * with the corners (v: v4, e: v4<->v0) and (v: v0, e: v0<->v2). Note that if the face was + * oriented counter-clockwise we'd end up with the corners (v: v0, e: v0<->v4) and (v: v2, e: + * v0<->v2) instead. + * - Then we need to choose one polygon as our first. If "v0" is not on a boundary we can just + * choose any polygon. If it is on a boundary some more care needs to be taken. Here we need to + * pick a polygon which lies on the boundary (in the diagram either f0 or f2). To choose between + * the two we need the next step. + * - In the normal case we use this polygon to set `shared_edge_i` which indicates the index of the + * shared edge between this polygon and the next one. There are two possible choices: v0<->v4 and + * v2<->v0. To choose we look at the corners. Since the edge v0<->v2 lies on the corner which has + * v0, we set `shared_edge_i` to the other edge (v0<->v4), such that the next face will be "f1" + * which is the next face in clockwise order. + * - In the boundary vertex case, we do something similar, but we are also forced to choose the + * edge which is not on the boundary. If this doesn't line up with orientation of the polygon, we + * know we'll need to choose the other boundary polygon as our first polygon. If the orientations + * don't line up there as well, it means that the mesh normals are not consistent, and we just + * have to force an orientation for ourselves. (Imagine if f0 is oriented counter-clockwise and + * f2 is oriented clockwise for example) + * - Next comes a loop where we look at the other faces and find the one which has the shared + * edge. Then we set the next shared edge to the other edge on the polygon connected to "v0", and + * continue. Because of the way we've chosen the first shared edge the order of the faces will + * have the same orientation as that of the first polygon. + * (In this case we'd have f0 -> f1 -> f2 -> f3 which also goes around clockwise). + * - Every time we determine a shared edge, we can also add a corner to `r_sorted_corners`. This + * will simply be the corner which doesn't contain the shared edge. + * - Finally if we are in the normal case we also need to add the last "shared edge" to close the + * loop. + */ +static void sort_vertex_polys(const Mesh &mesh, + const int vertex_index, + const bool boundary_vertex, + const Span<EdgeType> edge_types, + MutableSpan<int> connected_polygons, + MutableSpan<int> r_shared_edges, + MutableSpan<int> r_sorted_corners) +{ + if (connected_polygons.size() <= 2 && (!boundary_vertex || connected_polygons.size() == 0)) { + return; + } + + /* For each polygon store the two corners whose edge contains the vertex. */ + Array<std::pair<int, int>> poly_vertex_corners(connected_polygons.size()); + for (const int i : connected_polygons.index_range()) { + const MPoly &poly = mesh.mpoly[connected_polygons[i]]; + bool first_edge_done = false; + for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { + const MLoop &loop = mesh.mloop[loop_index]; + if (mesh.medge[loop.e].v1 == vertex_index || mesh.medge[loop.e].v2 == vertex_index) { + if (!first_edge_done) { + poly_vertex_corners[i].first = loop_index; + first_edge_done = true; + } + else { + poly_vertex_corners[i].second = loop_index; + break; + } + } + } + } + + int shared_edge_i = -1; + /* Determine first polygon and orientation. For now the orientation of the whole loop depends + * on the one polygon we chose as first. It's probably not worth it to check every polygon in + * the loop to determine the 'average' orientation. */ + if (boundary_vertex) { + /* Our first polygon needs to be one which has a boundary edge. */ + for (const int i : connected_polygons.index_range()) { + const MLoop &first_loop = mesh.mloop[poly_vertex_corners[i].first]; + const MLoop &second_loop = mesh.mloop[poly_vertex_corners[i].second]; + if (edge_types[first_loop.e] == EdgeType::Boundary && first_loop.v == vertex_index) { + shared_edge_i = second_loop.e; + r_sorted_corners[0] = poly_vertex_corners[i].first; + std::swap(connected_polygons[i], connected_polygons[0]); + std::swap(poly_vertex_corners[i], poly_vertex_corners[0]); + break; + } + if (edge_types[second_loop.e] == EdgeType::Boundary && second_loop.v == vertex_index) { + shared_edge_i = first_loop.e; + r_sorted_corners[0] = poly_vertex_corners[i].second; + std::swap(connected_polygons[i], connected_polygons[0]); + std::swap(poly_vertex_corners[i], poly_vertex_corners[0]); + break; + } + } + if (shared_edge_i == -1) { + /* The rotation is inconsistent between the two polygons on the boundary. Just choose one + * of the polygon's orientation. */ + for (const int i : connected_polygons.index_range()) { + const MLoop &first_loop = mesh.mloop[poly_vertex_corners[i].first]; + const MLoop &second_loop = mesh.mloop[poly_vertex_corners[i].second]; + if (edge_types[first_loop.e] == EdgeType::Boundary) { + shared_edge_i = second_loop.e; + r_sorted_corners[0] = poly_vertex_corners[i].first; + std::swap(connected_polygons[i], connected_polygons[0]); + std::swap(poly_vertex_corners[i], poly_vertex_corners[0]); + break; + } + if (edge_types[second_loop.e] == EdgeType::Boundary) { + shared_edge_i = first_loop.e; + r_sorted_corners[0] = poly_vertex_corners[i].second; + std::swap(connected_polygons[i], connected_polygons[0]); + std::swap(poly_vertex_corners[i], poly_vertex_corners[0]); + break; + } + } + } + } + else { + /* Any polygon can be the first. Just need to check the orientation.*/ + const MLoop &first_loop = mesh.mloop[poly_vertex_corners[0].first]; + const MLoop &second_loop = mesh.mloop[poly_vertex_corners[0].second]; + if (first_loop.v == vertex_index) { + shared_edge_i = second_loop.e; + r_sorted_corners[0] = poly_vertex_corners[0].first; + } + else { + r_sorted_corners[0] = poly_vertex_corners[0].second; + shared_edge_i = first_loop.e; + } + } + BLI_assert(shared_edge_i != -1); + + for (const int i : IndexRange(connected_polygons.size() - 1)) { + r_shared_edges[i] = shared_edge_i; + + /* Look at the other polys to see if it has this shared edge. */ + int j = i + 1; + for (; j < connected_polygons.size(); ++j) { + const MLoop &first_loop = mesh.mloop[poly_vertex_corners[j].first]; + const MLoop &second_loop = mesh.mloop[poly_vertex_corners[j].second]; + if (first_loop.e == shared_edge_i) { + r_sorted_corners[i + 1] = poly_vertex_corners[j].first; + shared_edge_i = second_loop.e; + break; + } + if (second_loop.e == shared_edge_i) { + r_sorted_corners[i + 1] = poly_vertex_corners[j].second; + shared_edge_i = first_loop.e; + break; + } + } + + BLI_assert(j != connected_polygons.size()); + + std::swap(connected_polygons[i + 1], connected_polygons[j]); + std::swap(poly_vertex_corners[i + 1], poly_vertex_corners[j]); + } + + if (!boundary_vertex) { + /* Shared edge between first and last polygon. */ + r_shared_edges.last() = shared_edge_i; + } +} + +/** + * Get the edge on the poly that contains the given vertex and is a boundary edge. + */ +static void boundary_edge_on_poly(const MPoly &poly, + const Mesh &mesh, + const int vertex_index, + const Span<EdgeType> edge_types, + int &r_edge) +{ + for (const MLoop &loop : Span<MLoop>(&mesh.mloop[poly.loopstart], poly.totloop)) { + if (edge_types[loop.e] == EdgeType::Boundary) { + const MEdge &edge = mesh.medge[loop.e]; + if (edge.v1 == vertex_index || edge.v2 == vertex_index) { + r_edge = loop.e; + return; + } + } + } +} + +/** + * Get the two edges on the poly that contain the given vertex and are boundary edges. The + * orientation of the poly is taken into account. + */ +static void boundary_edges_on_poly(const MPoly &poly, + const Mesh &mesh, + const int vertex_index, + const Span<EdgeType> edge_types, + int &r_edge1, + int &r_edge2) +{ + bool edge1_done = false; + /* This is set to true if the order in which we encounter the two edges is inconsistent with the + * orientation of the polygon. */ + bool needs_swap = false; + for (const MLoop &loop : Span<MLoop>(&mesh.mloop[poly.loopstart], poly.totloop)) { + if (edge_types[loop.e] == EdgeType::Boundary) { + const MEdge &edge = mesh.medge[loop.e]; + if (edge.v1 == vertex_index || edge.v2 == vertex_index) { + if (edge1_done) { + if (needs_swap) { + r_edge2 = r_edge1; + r_edge1 = loop.e; + } + else { + r_edge2 = loop.e; + } + return; + } + r_edge1 = loop.e; + edge1_done = true; + if (loop.v == vertex_index) { + needs_swap = true; + } + } + } + } +} + +static void add_edge(const Mesh &mesh, + const int old_edge_i, + const int v1, + const int v2, + Vector<int> &new_to_old_edges_map, + Vector<MEdge> &new_edges, + Vector<int> &loop_edges) +{ + MEdge new_edge = MEdge(mesh.medge[old_edge_i]); + new_edge.v1 = v1; + new_edge.v2 = v2; + const int new_edge_i = new_edges.size(); + new_to_old_edges_map.append(old_edge_i); + new_edges.append(new_edge); + loop_edges.append(new_edge_i); +} + +/** + * Calculate the barycentric dual of a mesh. The dual is only "dual" in terms of connectivity, + * i.e. applying the function twice will give the same vertices, edges, and faces, but not the + * same positions. When the option "Keep Boundaries" is selected the connectivity is no + * longer dual. + * + * For the dual mesh of a manifold input mesh: + * - The vertices are at the centers of the faces of the input mesh. + * - The edges connect the two vertices created from the two faces next to the edge in the input + * mesh. + * - The faces are at the vertices of the input mesh. + * + * Some special cases are needed for boundaries and non-manifold geometry. + */ +static void calc_dual_mesh(GeometrySet &geometry_set, + const MeshComponent &in_component, + const bool keep_boundaries) +{ + const Mesh &mesh_in = *in_component.get_for_read(); + + Map<AttributeIDRef, AttributeKind> attributes; + geometry_set.gather_attributes_for_propagation( + {GEO_COMPONENT_TYPE_MESH}, GEO_COMPONENT_TYPE_MESH, false, attributes); + + Array<VertexType> vertex_types(mesh_in.totvert); + Array<EdgeType> edge_types(mesh_in.totedge); + calc_boundaries(mesh_in, vertex_types, edge_types); + Array<Vector<int>> vertex_poly_indices(mesh_in.totvert); + Array<Array<int>> vertex_shared_edges(mesh_in.totvert); + Array<Array<int>> vertex_corners(mesh_in.totvert); + create_vertex_poly_map(mesh_in, vertex_poly_indices); + threading::parallel_for(vertex_poly_indices.index_range(), 512, [&](IndexRange range) { + for (const int i : range) { + if (vertex_types[i] == VertexType::Loose || vertex_types[i] >= VertexType::NonManifold || + (!keep_boundaries && vertex_types[i] == VertexType::Boundary)) { + /* Bad vertex that we can't work with. */ + continue; + } + MutableSpan<int> loop_indices = vertex_poly_indices[i]; + Array<int> sorted_corners(loop_indices.size()); + if (vertex_types[i] == VertexType::Normal) { + Array<int> shared_edges(loop_indices.size()); + sort_vertex_polys( + mesh_in, i, false, edge_types, loop_indices, shared_edges, sorted_corners); + vertex_shared_edges[i] = shared_edges; + } + else { + Array<int> shared_edges(loop_indices.size() - 1); + sort_vertex_polys( + mesh_in, i, true, edge_types, loop_indices, shared_edges, sorted_corners); + vertex_shared_edges[i] = shared_edges; + } + vertex_corners[i] = sorted_corners; + } + }); + + Vector<float3> vertex_positions(mesh_in.totpoly); + for (const int i : IndexRange(mesh_in.totpoly)) { + const MPoly poly = mesh_in.mpoly[i]; + BKE_mesh_calc_poly_center( + &poly, &mesh_in.mloop[poly.loopstart], mesh_in.mvert, vertex_positions[i]); + } + + Array<int> boundary_edge_midpoint_index; + if (keep_boundaries) { + /* Only initialize when we actually need it. */ + boundary_edge_midpoint_index.reinitialize(mesh_in.totedge); + /* We need to add vertices at the centers of boundary edges. */ + for (const int i : IndexRange(mesh_in.totedge)) { + if (edge_types[i] == EdgeType::Boundary) { + float3 mid; + const MEdge &edge = mesh_in.medge[i]; + mid_v3_v3v3(mid, mesh_in.mvert[edge.v1].co, mesh_in.mvert[edge.v2].co); + boundary_edge_midpoint_index[i] = vertex_positions.size(); + vertex_positions.append(mid); + } + } + } + + Vector<int> loop_lengths; + Vector<int> loops; + Vector<int> loop_edges; + Vector<MEdge> new_edges; + /* These are used to transfer attributes. */ + Vector<int> new_to_old_face_corners_map; + Vector<int> new_to_old_edges_map; + /* Stores the index of the vertex in the dual and the face it should get the attribute from. */ + Vector<std::pair<int, int>> boundary_vertex_to_relevant_face_map; + /* Since each edge in the dual (except the ones created with keep boundaries) comes from + * exactly one edge in the original, we can use this array to keep track of whether it still + * needs to be created or not. If it's not -1 it gives the index in `new_edges` of the dual + * edge. The edges coming from preserving the boundaries only get added once anyway, so we + * don't need a hashmap for that. */ + Array<int> old_to_new_edges_map(mesh_in.totedge); + old_to_new_edges_map.fill(-1); + for (const int i : IndexRange(mesh_in.totvert)) { + if (vertex_types[i] == VertexType::Loose || vertex_types[i] >= VertexType::NonManifold || + (!keep_boundaries && vertex_types[i] == VertexType::Boundary)) { + /* Bad vertex that we can't work with. */ + continue; + } + + Vector<int> loop_indices = vertex_poly_indices[i]; + Span<int> shared_edges = vertex_shared_edges[i]; + Span<int> sorted_corners = vertex_corners[i]; + if (vertex_types[i] == VertexType::Normal) { + if (loop_indices.size() <= 2) { + /* We can't make a polygon from 2 vertices. */ + continue; + } + + /* Add edges in the loop. */ + for (const int i : shared_edges.index_range()) { + const int old_edge_i = shared_edges[i]; + if (old_to_new_edges_map[old_edge_i] == -1) { + /* This edge has not been created yet. */ + MEdge new_edge = MEdge(mesh_in.medge[old_edge_i]); + new_edge.v1 = loop_indices[i]; + new_edge.v2 = loop_indices[(i + 1) % loop_indices.size()]; + new_to_old_edges_map.append(old_edge_i); + old_to_new_edges_map[old_edge_i] = new_edges.size(); + new_edges.append(new_edge); + } + loop_edges.append(old_to_new_edges_map[old_edge_i]); + } + + new_to_old_face_corners_map.extend(sorted_corners); + } + else { + /** + * The code handles boundary vertices like the vertex marked "V" in the diagram below. + * The first thing that happens is ordering the faces f1,f2 and f3 (stored in + * loop_indices), together with their shared edges e3 and e4 (which get stored in + * shared_edges). The ordering could end up being clockwise or counterclockwise, for this + * we'll assume that the ordering f1->f2->f3 is chosen. After that we add the edges in + * between the polygons, in this case the edges f1--f2, and f2--f3. Now we need to merge + * these with the boundary edges e1 and e2. To do this we create an edge from f3 to the + * midpoint of e2 (computed in a previous step), from this midpoint to V, from V to the + * midpoint of e1 and from the midpoint of e1 to f1. + * + * \code{.unparsed} + * | | | | | | + * v2 ---- v3 --------- v4--- v2 ---- v3 -------- v4--- + * | f3 / ,-' | | / ,-'| + * | / f2 ,-' | | / ,-' | + * e2 | /e3 ,-' e4 | ====> M1-f3-/--f2-.,-' | + * | / ,-' | ====> | / ,-'\ | + * | / ,-' f1 | | / ,-' f1 | + * | /,-' | | /,-' | | + * V-------------------- v5--- V------------M2----- v5--- + * \endcode + */ + + /* Add the edges in between the polys. */ + for (const int i : shared_edges.index_range()) { + const int old_edge_i = shared_edges[i]; + if (old_to_new_edges_map[old_edge_i] == -1) { + /* This edge has not been created yet. */ + MEdge new_edge = MEdge(mesh_in.medge[old_edge_i]); + new_edge.v1 = loop_indices[i]; + new_edge.v2 = loop_indices[i + 1]; + new_to_old_edges_map.append(old_edge_i); + old_to_new_edges_map[old_edge_i] = new_edges.size(); + new_edges.append(new_edge); + } + loop_edges.append(old_to_new_edges_map[old_edge_i]); + } + + new_to_old_face_corners_map.extend(sorted_corners); + + /* Add the vertex and the midpoints of the two boundary edges to the loop. */ + + /* Get the boundary edges. */ + int edge1; + int edge2; + if (loop_indices.size() >= 2) { + /* The first boundary edge is at the end of the chain of polygons. */ + boundary_edge_on_poly(mesh_in.mpoly[loop_indices.last()], mesh_in, i, edge_types, edge1); + boundary_edge_on_poly(mesh_in.mpoly[loop_indices.first()], mesh_in, i, edge_types, edge2); + } + else { + /* If there is only one polygon both edges are in that polygon. */ + boundary_edges_on_poly( + mesh_in.mpoly[loop_indices[0]], mesh_in, i, edge_types, edge1, edge2); + } + + const int last_face_center = loop_indices.last(); + loop_indices.append(boundary_edge_midpoint_index[edge1]); + new_to_old_face_corners_map.append(sorted_corners.last()); + const int first_midpoint = loop_indices.last(); + if (old_to_new_edges_map[edge1] == -1) { + add_edge(mesh_in, + edge1, + last_face_center, + first_midpoint, + new_to_old_edges_map, + new_edges, + loop_edges); + old_to_new_edges_map[edge1] = new_edges.size() - 1; + boundary_vertex_to_relevant_face_map.append(std::pair(first_midpoint, last_face_center)); + } + else { + loop_edges.append(old_to_new_edges_map[edge1]); + } + loop_indices.append(vertex_positions.size()); + /* This is sort of arbitrary, but interpolating would be a lot harder to do. */ + new_to_old_face_corners_map.append(sorted_corners.first()); + boundary_vertex_to_relevant_face_map.append( + std::pair(loop_indices.last(), last_face_center)); + vertex_positions.append(mesh_in.mvert[i].co); + const int boundary_vertex = loop_indices.last(); + add_edge(mesh_in, + edge1, + first_midpoint, + boundary_vertex, + new_to_old_edges_map, + new_edges, + loop_edges); + + loop_indices.append(boundary_edge_midpoint_index[edge2]); + new_to_old_face_corners_map.append(sorted_corners.first()); + const int second_midpoint = loop_indices.last(); + add_edge(mesh_in, + edge2, + boundary_vertex, + second_midpoint, + new_to_old_edges_map, + new_edges, + loop_edges); + + if (old_to_new_edges_map[edge2] == -1) { + const int first_face_center = loop_indices.first(); + add_edge(mesh_in, + edge2, + second_midpoint, + first_face_center, + new_to_old_edges_map, + new_edges, + loop_edges); + old_to_new_edges_map[edge2] = new_edges.size() - 1; + boundary_vertex_to_relevant_face_map.append(std::pair(second_midpoint, first_face_center)); + } + else { + loop_edges.append(old_to_new_edges_map[edge2]); + } + } + + loop_lengths.append(loop_indices.size()); + for (const int j : loop_indices) { + loops.append(j); + } + } + Mesh *mesh_out = BKE_mesh_new_nomain( + vertex_positions.size(), new_edges.size(), 0, loops.size(), loop_lengths.size()); + MeshComponent out_component; + out_component.replace(mesh_out, GeometryOwnershipType::Editable); + transfer_attributes(attributes, + vertex_types, + keep_boundaries, + new_to_old_edges_map, + new_to_old_face_corners_map, + boundary_vertex_to_relevant_face_map, + in_component, + out_component); + + int loop_start = 0; + for (const int i : IndexRange(mesh_out->totpoly)) { + mesh_out->mpoly[i].loopstart = loop_start; + mesh_out->mpoly[i].totloop = loop_lengths[i]; + loop_start += loop_lengths[i]; + } + for (const int i : IndexRange(mesh_out->totloop)) { + mesh_out->mloop[i].v = loops[i]; + mesh_out->mloop[i].e = loop_edges[i]; + } + for (const int i : IndexRange(mesh_out->totvert)) { + copy_v3_v3(mesh_out->mvert[i].co, vertex_positions[i]); + } + memcpy(mesh_out->medge, new_edges.data(), sizeof(MEdge) * new_edges.size()); + BKE_mesh_normals_tag_dirty(mesh_out); + geometry_set.replace_mesh(mesh_out); +} + +static void node_geo_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); + const bool keep_boundaries = params.extract_input<bool>("Keep Boundaries"); + geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + if (geometry_set.has_mesh()) { + const MeshComponent &component = *geometry_set.get_component_for_read<MeshComponent>(); + calc_dual_mesh(geometry_set, component, keep_boundaries); + } + }); + params.set_output("Dual Mesh", std::move(geometry_set)); +} + +} // namespace blender::nodes::node_geo_dual_mesh_cc + +void register_node_type_geo_dual_mesh() +{ + namespace file_ns = blender::nodes::node_geo_dual_mesh_cc; + + static bNodeType ntype; + geo_node_type_base(&ntype, GEO_NODE_DUAL_MESH, "Dual Mesh", NODE_CLASS_GEOMETRY, 0); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc index ca6254be182..d23a18ba37b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc @@ -22,9 +22,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_edge_split_cc { -static void geo_node_edge_split_declare(NodeDeclarationBuilder &b) +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).hide_value().supports_field(); @@ -57,7 +57,7 @@ static Mesh *mesh_edge_split(const Mesh &mesh, const IndexMask selection) return result; } -static void geo_node_edge_split_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); @@ -82,14 +82,16 @@ static void geo_node_edge_split_exec(GeoNodeExecParams params) params.set_output("Mesh", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_edge_split_cc void register_node_type_geo_edge_split() { + namespace file_ns = blender::nodes::node_geo_edge_split_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SPLIT_EDGES, "Split Edges", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_edge_split_exec; - ntype.declare = blender::nodes::geo_node_edge_split_declare; + 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_geometry_to_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc new file mode 100644 index 00000000000..7faf104737f --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc @@ -0,0 +1,55 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_geometry_to_instance_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Geometry>(N_("Geometry")).multi_input(); + b.add_output<decl::Geometry>(N_("Instances")); +} + +static void node_geo_exec(GeoNodeExecParams params) +{ + Vector<GeometrySet> geometries = params.extract_multi_input<GeometrySet>("Geometry"); + GeometrySet instances_geometry; + InstancesComponent &instances_component = + instances_geometry.get_component_for_write<InstancesComponent>(); + for (GeometrySet &geometry : geometries) { + geometry.ensure_owns_direct_data(); + const int handle = instances_component.add_reference(std::move(geometry)); + instances_component.add_instance(handle, float4x4::identity()); + } + params.set_output("Instances", std::move(instances_geometry)); +} + +} // namespace blender::nodes::node_geo_geometry_to_instance_cc + +void register_node_type_geo_geometry_to_instance() +{ + namespace file_ns = blender::nodes::node_geo_geometry_to_instance_cc; + + static bNodeType ntype; + + geo_node_type_base( + &ntype, GEO_NODE_GEOMETRY_TO_INSTANCE, "Geometry to Instance", NODE_CLASS_GEOMETRY, 0); + node_type_size(&ntype, 160, 100, 300); + 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_image_texture.cc b/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc index 7bbe0716f78..0003f15854d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc @@ -32,9 +32,11 @@ #include "UI_interface.h" #include "UI_resources.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_image_texture_cc { -static void geo_node_image_texture_declare(NodeDeclarationBuilder &b) +NODE_STORAGE_FUNCS(NodeGeometryImageTexture) + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Image>(N_("Image")).hide_label(); b.add_input<decl::Vector>(N_("Vector")) @@ -45,13 +47,13 @@ static void geo_node_image_texture_declare(NodeDeclarationBuilder &b) b.add_output<decl::Float>(N_("Alpha")).no_muted_links().dependent_field(); } -static void geo_node_image_texture_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "interpolation", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); uiItemR(layout, ptr, "extension", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); } -static void geo_node_image_texture_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryImageTexture *tex = (NodeGeometryImageTexture *)MEM_callocN( sizeof(NodeGeometryImageTexture), __func__); @@ -370,20 +372,15 @@ class ImageFieldsFunction : public fn::MultiFunction { } }; -static void geo_node_image_texture_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { - auto return_default = [&]() { - params.set_output("Color", ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f)); - params.set_output("Alpha", 1.0f); - }; - Image *image = params.get_input<Image *>("Image"); if (image == nullptr) { - return return_default(); + params.set_default_remaining_outputs(); + return; } - const bNode &node = params.node(); - NodeGeometryImageTexture *data = (NodeGeometryImageTexture *)node.storage; + const NodeGeometryImageTexture &storage = node_storage(params.node()); ImageUser image_user; BKE_imageuser_default(&image_user); @@ -395,10 +392,11 @@ static void geo_node_image_texture_exec(GeoNodeExecParams params) std::unique_ptr<ImageFieldsFunction> image_fn; try { image_fn = std::make_unique<ImageFieldsFunction>( - data->interpolation, data->extension, *image, image_user); + storage.interpolation, storage.extension, *image, image_user); } catch (const std::runtime_error &) { - return return_default(); + params.set_default_remaining_outputs(); + return; } Field<float3> vector_field = params.extract_input<Field<float3>>("Vector"); @@ -410,20 +408,22 @@ static void geo_node_image_texture_exec(GeoNodeExecParams params) params.set_output("Alpha", Field<float>(image_op, 1)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_image_texture_cc -void register_node_type_geo_image_texture(void) +void register_node_type_geo_image_texture() { + namespace file_ns = blender::nodes::node_geo_image_texture_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_IMAGE_TEXTURE, "Image Texture", NODE_CLASS_TEXTURE, 0); - ntype.declare = blender::nodes::geo_node_image_texture_declare; - ntype.draw_buttons = blender::nodes::geo_node_image_texture_layout; - node_type_init(&ntype, blender::nodes::geo_node_image_texture_init); + ntype.declare = file_ns::node_declare; + ntype.draw_buttons = file_ns::node_layout; + node_type_init(&ntype, file_ns::node_init); node_type_storage( &ntype, "NodeGeometryImageTexture", node_free_standard_storage, node_copy_standard_storage); node_type_size_preset(&ntype, NODE_SIZE_LARGE); - ntype.geometry_node_execute = blender::nodes::geo_node_image_texture_exec; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc index b8df545d073..dae8fda2099 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc @@ -16,15 +16,15 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_curve_handles_cc { -static void geo_node_input_curve_handles_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Vector>(N_("Left")).field_source(); b.add_output<decl::Vector>(N_("Right")).field_source(); } -static void geo_node_input_curve_handles_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<float3> left_field = AttributeFieldInput::Create<float3>("handle_left"); Field<float3> right_field = AttributeFieldInput::Create<float3>("handle_right"); @@ -32,15 +32,17 @@ static void geo_node_input_curve_handles_exec(GeoNodeExecParams params) params.set_output("Right", std::move(right_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_curve_handles_cc void register_node_type_geo_input_curve_handles() { + namespace file_ns = blender::nodes::node_geo_input_curve_handles_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_INPUT_CURVE_HANDLES, "Curve Handle Positions", NODE_CLASS_INPUT, 0); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); - ntype.geometry_node_execute = blender::nodes::geo_node_input_curve_handles_exec; - ntype.declare = blender::nodes::geo_node_input_curve_handles_declare; + 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_curve_tilt.cc b/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc index f32db3842db..5ba85b6f34e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc @@ -16,27 +16,29 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_curve_tilt_cc { -static void geo_node_input_curve_tilt_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Float>(N_("Tilt")).field_source(); } -static void geo_node_input_curve_tilt_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<float> tilt_field = AttributeFieldInput::Create<float>("tilt"); params.set_output("Tilt", std::move(tilt_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_curve_tilt_cc void register_node_type_geo_input_curve_tilt() { + namespace file_ns = blender::nodes::node_geo_input_curve_tilt_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_CURVE_TILT, "Curve Tilt", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_curve_tilt_exec; - ntype.declare = blender::nodes::geo_node_input_curve_tilt_declare; + 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_id.cc b/source/blender/nodes/geometry/nodes/node_geo_input_id.cc index 37d5bac0325..d2e103a093a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_id.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_id.cc @@ -16,27 +16,29 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_id_cc { -static void geo_node_input_id_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Int>(N_("ID")).field_source(); } -static void geo_node_input_id_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<int> position_field{std::make_shared<bke::IDAttributeFieldInput>()}; params.set_output("ID", std::move(position_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_id_cc void register_node_type_geo_input_id() { + namespace file_ns = blender::nodes::node_geo_input_id_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_ID, "ID", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_id_exec; - ntype.declare = blender::nodes::geo_node_input_id_declare; + 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_index.cc b/source/blender/nodes/geometry/nodes/node_geo_input_index.cc index 6200ac5e7a8..74cddfc6a4a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_index.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_index.cc @@ -16,27 +16,29 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_index_cc { -static void geo_node_input_index_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Int>(N_("Index")).field_source(); } -static void geo_node_input_index_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<int> index_field{std::make_shared<fn::IndexFieldInput>()}; params.set_output("Index", std::move(index_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_index_cc void register_node_type_geo_input_index() { + namespace file_ns = blender::nodes::node_geo_input_index_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_INDEX, "Index", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_index_exec; - ntype.declare = blender::nodes::geo_node_input_index_declare; + 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 fc41188dee5..1b6e3c8fc68 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_material.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_material.cc @@ -19,33 +19,35 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_material_cc { -static void geo_node_input_material_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Material>(N_("Material")); } -static void geo_node_input_material_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "material", 0, "", ICON_NONE); } -static void geo_node_input_material_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Material *material = (Material *)params.node().id; params.set_output("Material", material); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_material_cc void register_node_type_geo_input_material() { + namespace file_ns = blender::nodes::node_geo_input_material_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_MATERIAL, "Material", NODE_CLASS_INPUT, 0); - ntype.draw_buttons = blender::nodes::geo_node_input_material_layout; - ntype.declare = blender::nodes::geo_node_input_material_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_input_material_exec; + ntype.draw_buttons = file_ns::node_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc b/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc index 5d5d9e40032..4df218eb669 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc @@ -16,27 +16,29 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_material_index_cc { -static void geo_node_input_material_index_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Int>(N_("Material Index")).field_source(); } -static void geo_node_input_material_index_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<int> material_index_field = AttributeFieldInput::Create<int>("material_index"); params.set_output("Material Index", std::move(material_index_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_material_index_cc void register_node_type_geo_input_material_index() { + namespace file_ns = blender::nodes::node_geo_input_material_index_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_MATERIAL_INDEX, "Material Index", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_material_index_exec; - ntype.declare = blender::nodes::geo_node_input_material_index_declare; + 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_mesh_edge_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc new file mode 100644 index 00000000000..ede87252312 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc @@ -0,0 +1,93 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_mesh.h" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_input_mesh_edge_neighbors_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_output<decl::Int>(N_("Face Count")) + .field_source() + .description(N_("Number of faces that contain the edge")); +} + +class EdgeNeighborCountFieldInput final : public GeometryFieldInput { + public: + EdgeNeighborCountFieldInput() + : GeometryFieldInput(CPPType::get<int>(), "Edge Neighbor Count Field") + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask UNUSED(mask)) const final + { + if (component.type() == GEO_COMPONENT_TYPE_MESH) { + const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); + const Mesh *mesh = mesh_component.get_for_read(); + if (mesh == nullptr) { + return {}; + } + + Array<int> face_count(mesh->totedge, 0); + for (const int i : IndexRange(mesh->totloop)) { + face_count[mesh->mloop[i].e]++; + } + + return mesh_component.attribute_try_adapt_domain<int>( + VArray<int>::ForContainer(std::move(face_count)), ATTR_DOMAIN_EDGE, domain); + } + return {}; + } + + uint64_t hash() const override + { + /* Some random constant hash. */ + return 985671075; + } + + bool is_equal_to(const fn::FieldNode &other) const override + { + return dynamic_cast<const EdgeNeighborCountFieldInput *>(&other) != nullptr; + } +}; + +static void node_geo_exec(GeoNodeExecParams params) +{ + Field<int> neighbor_count_field{std::make_shared<EdgeNeighborCountFieldInput>()}; + params.set_output("Face Count", std::move(neighbor_count_field)); +} + +} // namespace blender::nodes::node_geo_input_mesh_edge_neighbors_cc + +void register_node_type_geo_input_mesh_edge_neighbors() +{ + namespace file_ns = blender::nodes::node_geo_input_mesh_edge_neighbors_cc; + + static bNodeType ntype; + geo_node_type_base( + &ntype, GEO_NODE_INPUT_MESH_EDGE_NEIGHBORS, "Edge Neighbors", NODE_CLASS_INPUT, 0); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc new file mode 100644 index 00000000000..473bef63e92 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc @@ -0,0 +1,188 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_mesh.h" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_input_mesh_edge_vertices_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_output<decl::Int>(N_("Vertex Index 1")) + .field_source() + .description(N_("The index of the first vertex in the edge")); + b.add_output<decl::Int>(N_("Vertex Index 2")) + .field_source() + .description(N_("The index of the second vertex in the edge")); + b.add_output<decl::Vector>(N_("Position 1")) + .field_source() + .description(N_("The position of the first vertex in the edge")); + b.add_output<decl::Vector>(N_("Position 2")) + .field_source() + .description(N_("The position of the second vertex in the edge")); +} + +enum VertexNumber { VERTEX_ONE, VERTEX_TWO }; + +static VArray<int> construct_edge_vertices_gvarray(const MeshComponent &component, + const VertexNumber vertex, + const AttributeDomain domain) +{ + const Mesh *mesh = component.get_for_read(); + if (mesh == nullptr) { + return {}; + } + if (domain == ATTR_DOMAIN_EDGE) { + + if (vertex == VERTEX_ONE) { + return VArray<int>::ForFunc(mesh->totpoly, + [mesh](const int i) -> int { return mesh->medge[i].v1; }); + } + return VArray<int>::ForFunc(mesh->totpoly, + [mesh](const int i) -> int { return mesh->medge[i].v2; }); + } + return {}; +} + +class EdgeVerticesFieldInput final : public GeometryFieldInput { + private: + VertexNumber vertex_; + + public: + EdgeVerticesFieldInput(VertexNumber vertex) + : GeometryFieldInput(CPPType::get<int>(), "Edge Vertices Field"), vertex_(vertex) + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask UNUSED(mask)) const final + { + if (component.type() == GEO_COMPONENT_TYPE_MESH) { + const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); + return construct_edge_vertices_gvarray(mesh_component, vertex_, domain); + } + return {}; + } + + uint64_t hash() const override + { + return vertex_ == VERTEX_ONE ? 23847562893465 : 92384598734567; + } + + bool is_equal_to(const fn::FieldNode &other) const override + { + if (const EdgeVerticesFieldInput *other_field = dynamic_cast<const EdgeVerticesFieldInput *>( + &other)) { + return vertex_ == other_field->vertex_; + } + return false; + } +}; + +static VArray<float3> construct_edge_positions_gvarray(const MeshComponent &component, + const VertexNumber vertex, + const AttributeDomain domain) +{ + const Mesh *mesh = component.get_for_read(); + if (mesh == nullptr) { + return {}; + } + + if (vertex == VERTEX_ONE) { + return component.attribute_try_adapt_domain<float3>( + VArray<float3>::ForFunc( + mesh->totedge, + [mesh](const int i) { return float3(mesh->mvert[mesh->medge[i].v1].co); }), + ATTR_DOMAIN_EDGE, + domain); + } + return component.attribute_try_adapt_domain<float3>( + VArray<float3>::ForFunc( + mesh->totedge, + [mesh](const int i) { return float3(mesh->mvert[mesh->medge[i].v2].co); }), + ATTR_DOMAIN_EDGE, + domain); +} + +class EdgePositionFieldInput final : public GeometryFieldInput { + private: + VertexNumber vertex_; + + public: + EdgePositionFieldInput(VertexNumber vertex) + : GeometryFieldInput(CPPType::get<float3>(), "Edge Position Field"), vertex_(vertex) + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask UNUSED(mask)) const final + { + if (component.type() == GEO_COMPONENT_TYPE_MESH) { + const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); + return construct_edge_positions_gvarray(mesh_component, vertex_, domain); + } + return {}; + } + + uint64_t hash() const override + { + return vertex_ == VERTEX_ONE ? 987456978362 : 374587679866; + } + + bool is_equal_to(const fn::FieldNode &other) const override + { + if (const EdgePositionFieldInput *other_field = dynamic_cast<const EdgePositionFieldInput *>( + &other)) { + return vertex_ == other_field->vertex_; + } + return false; + } +}; + +static void node_geo_exec(GeoNodeExecParams params) +{ + Field<int> vertex_field_1{std::make_shared<EdgeVerticesFieldInput>(VERTEX_ONE)}; + Field<int> vertex_field_2{std::make_shared<EdgeVerticesFieldInput>(VERTEX_TWO)}; + Field<float3> position_field_1{std::make_shared<EdgePositionFieldInput>(VERTEX_ONE)}; + Field<float3> position_field_2{std::make_shared<EdgePositionFieldInput>(VERTEX_TWO)}; + + params.set_output("Vertex Index 1", std::move(vertex_field_1)); + params.set_output("Vertex Index 2", std::move(vertex_field_2)); + params.set_output("Position 1", std::move(position_field_1)); + params.set_output("Position 2", std::move(position_field_2)); +} + +} // namespace blender::nodes::node_geo_input_mesh_edge_vertices_cc + +void register_node_type_geo_input_mesh_edge_vertices() +{ + namespace file_ns = blender::nodes::node_geo_input_mesh_edge_vertices_cc; + + static bNodeType ntype; + geo_node_type_base( + &ntype, GEO_NODE_INPUT_MESH_EDGE_VERTICES, "Edge Vertices", NODE_CLASS_INPUT, 0); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc new file mode 100644 index 00000000000..538b9e9682d --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc @@ -0,0 +1,96 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_mesh.h" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_input_mesh_face_area_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_output<decl::Float>(N_("Area")) + .field_source() + .description(N_("The surface area of each of the mesh's faces")); +} + +static VArray<float> construct_face_area_gvarray(const MeshComponent &component, + const AttributeDomain domain) +{ + const Mesh *mesh = component.get_for_read(); + if (mesh == nullptr) { + return {}; + } + + auto area_fn = [mesh](const int i) -> float { + const MPoly *mp = &mesh->mpoly[i]; + return BKE_mesh_calc_poly_area(mp, &mesh->mloop[mp->loopstart], mesh->mvert); + }; + + return component.attribute_try_adapt_domain<float>( + VArray<float>::ForFunc(mesh->totpoly, area_fn), ATTR_DOMAIN_FACE, domain); +} + +class FaceAreaFieldInput final : public GeometryFieldInput { + public: + FaceAreaFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Face Area Field") + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask UNUSED(mask)) const final + { + if (component.type() == GEO_COMPONENT_TYPE_MESH) { + const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); + return construct_face_area_gvarray(mesh_component, domain); + } + return {}; + } + + uint64_t hash() const override + { + /* Some random constant hash. */ + return 1346334523; + } + + bool is_equal_to(const fn::FieldNode &other) const override + { + return dynamic_cast<const FaceAreaFieldInput *>(&other) != nullptr; + } +}; + +static void node_geo_exec(GeoNodeExecParams params) +{ + params.set_output("Area", Field<float>(std::make_shared<FaceAreaFieldInput>())); +} + +} // namespace blender::nodes::node_geo_input_mesh_face_area_cc + +void register_node_type_geo_input_mesh_face_area() +{ + namespace file_ns = blender::nodes::node_geo_input_mesh_face_area_cc; + + static bNodeType ntype; + geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_FACE_AREA, "Face Area", NODE_CLASS_INPUT, 0); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc new file mode 100644 index 00000000000..80bb25dc7ca --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc @@ -0,0 +1,158 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_mesh.h" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_input_mesh_face_neighbors_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_output<decl::Int>(N_("Vertex Count")) + .field_source() + .description(N_("Number of edges or points in the face")); + b.add_output<decl::Int>(N_("Face Count")) + .field_source() + .description(N_("Number of faces which share an edge with the face")); +} + +static VArray<int> construct_neighbor_count_gvarray(const MeshComponent &component, + const AttributeDomain domain) +{ + const Mesh *mesh = component.get_for_read(); + if (mesh == nullptr) { + return {}; + } + + Array<int> edge_count(mesh->totedge, 0); + for (const int i : IndexRange(mesh->totloop)) { + edge_count[mesh->mloop[i].e]++; + } + + Array<int> poly_count(mesh->totpoly, 0); + for (const int poly_num : IndexRange(mesh->totpoly)) { + MPoly &poly = mesh->mpoly[poly_num]; + for (const int loop_num : IndexRange(poly.loopstart, poly.totloop)) { + poly_count[poly_num] += edge_count[mesh->mloop[loop_num].e] - 1; + } + } + + return component.attribute_try_adapt_domain<int>( + VArray<int>::ForContainer(std::move(poly_count)), ATTR_DOMAIN_FACE, domain); +} + +class FaceNeighborCountFieldInput final : public GeometryFieldInput { + public: + FaceNeighborCountFieldInput() + : GeometryFieldInput(CPPType::get<int>(), "Face Neighbor Count Field") + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask UNUSED(mask)) const final + { + if (component.type() == GEO_COMPONENT_TYPE_MESH) { + const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); + return construct_neighbor_count_gvarray(mesh_component, domain); + } + return {}; + } + + uint64_t hash() const override + { + /* Some random constant hash. */ + return 823543774; + } + + bool is_equal_to(const fn::FieldNode &other) const override + { + return dynamic_cast<const FaceNeighborCountFieldInput *>(&other) != nullptr; + } +}; + +static VArray<int> construct_vertex_count_gvarray(const MeshComponent &component, + const AttributeDomain domain) +{ + const Mesh *mesh = component.get_for_read(); + if (mesh == nullptr) { + return {}; + } + + return component.attribute_try_adapt_domain<int>( + VArray<int>::ForFunc(mesh->totpoly, + [mesh](const int i) -> float { return mesh->mpoly[i].totloop; }), + ATTR_DOMAIN_FACE, + domain); +} + +class FaceVertexCountFieldInput final : public GeometryFieldInput { + public: + FaceVertexCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Vertex Count Field") + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask UNUSED(mask)) const final + { + if (component.type() == GEO_COMPONENT_TYPE_MESH) { + const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); + return construct_vertex_count_gvarray(mesh_component, domain); + } + return {}; + } + + uint64_t hash() const override + { + /* Some random constant hash. */ + return 236235463634; + } + + bool is_equal_to(const fn::FieldNode &other) const override + { + return dynamic_cast<const FaceVertexCountFieldInput *>(&other) != nullptr; + } +}; + +static void node_geo_exec(GeoNodeExecParams params) +{ + Field<int> vertex_count_field{std::make_shared<FaceVertexCountFieldInput>()}; + Field<int> neighbor_count_field{std::make_shared<FaceNeighborCountFieldInput>()}; + params.set_output("Vertex Count", std::move(vertex_count_field)); + params.set_output("Face Count", std::move(neighbor_count_field)); +} + +} // namespace blender::nodes::node_geo_input_mesh_face_neighbors_cc + +void register_node_type_geo_input_mesh_face_neighbors() +{ + namespace file_ns = blender::nodes::node_geo_input_mesh_face_neighbors_cc; + + static bNodeType ntype; + geo_node_type_base( + &ntype, GEO_NODE_INPUT_MESH_FACE_NEIGHBORS, "Face Neighbors", NODE_CLASS_INPUT, 0); + node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc new file mode 100644 index 00000000000..3c713ef6ca9 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc @@ -0,0 +1,101 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_mesh.h" + +#include "BLI_disjoint_set.hh" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_input_mesh_island_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_output<decl::Int>(N_("Index")) + .field_source() + .description(N_("Island indices are based on the order of the lowest-numbered vertex " + "contained in each island")); +} + +class IslandFieldInput final : public GeometryFieldInput { + public: + IslandFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Island Index") + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask UNUSED(mask)) const final + { + if (component.type() != GEO_COMPONENT_TYPE_MESH) { + return {}; + } + const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); + const Mesh *mesh = mesh_component.get_for_read(); + if (mesh == nullptr) { + return {}; + } + + DisjointSet islands(mesh->totvert); + for (const int i : IndexRange(mesh->totedge)) { + islands.join(mesh->medge[i].v1, mesh->medge[i].v2); + } + + Array<int> output(mesh->totvert); + VectorSet<int> ordered_roots; + for (const int i : IndexRange(mesh->totvert)) { + const int64_t root = islands.find_root(i); + output[i] = ordered_roots.index_of_or_add(root); + } + + return mesh_component.attribute_try_adapt_domain<int>( + VArray<int>::ForContainer(std::move(output)), ATTR_DOMAIN_POINT, domain); + } + + uint64_t hash() const override + { + /* Some random constant hash. */ + return 635467354; + } + + bool is_equal_to(const fn::FieldNode &other) const override + { + return dynamic_cast<const IslandFieldInput *>(&other) != nullptr; + } +}; + +static void node_geo_exec(GeoNodeExecParams params) +{ + Field<int> island_field{std::make_shared<IslandFieldInput>()}; + params.set_output("Index", std::move(island_field)); +} + +} // namespace blender::nodes::node_geo_input_mesh_island_cc + +void register_node_type_geo_input_mesh_island() +{ + namespace file_ns = blender::nodes::node_geo_input_mesh_island_cc; + + static bNodeType ntype; + geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_ISLAND, "Mesh Island", NODE_CLASS_INPUT, 0); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc new file mode 100644 index 00000000000..05140c92205 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc @@ -0,0 +1,155 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_mesh.h" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_input_mesh_vertex_neighbors_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_output<decl::Int>(N_("Vertex Count")) + .field_source() + .description(N_("Vertex count and edge count are equal")); + b.add_output<decl::Int>(N_("Face Count")) + .field_source() + .description(N_("Number of faces that contain the vertex")); +} + +static VArray<int> construct_vertex_count_gvarray(const MeshComponent &component, + const AttributeDomain domain) +{ + const Mesh *mesh = component.get_for_read(); + if (mesh == nullptr) { + return {}; + } + + if (domain == ATTR_DOMAIN_POINT) { + Array<int> vertices(mesh->totvert, 0); + for (const int i : IndexRange(mesh->totedge)) { + vertices[mesh->medge[i].v1]++; + vertices[mesh->medge[i].v2]++; + } + return VArray<int>::ForContainer(std::move(vertices)); + } + return {}; +} + +class VertexCountFieldInput final : public GeometryFieldInput { + public: + VertexCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Vertex Count Field") + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask UNUSED(mask)) const final + { + if (component.type() == GEO_COMPONENT_TYPE_MESH) { + const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); + return construct_vertex_count_gvarray(mesh_component, domain); + } + return {}; + } + + uint64_t hash() const override + { + /* Some random constant hash. */ + return 23574528465; + } + + bool is_equal_to(const fn::FieldNode &other) const override + { + return dynamic_cast<const VertexCountFieldInput *>(&other) != nullptr; + } +}; + +static VArray<int> construct_face_count_gvarray(const MeshComponent &component, + const AttributeDomain domain) +{ + const Mesh *mesh = component.get_for_read(); + if (mesh == nullptr) { + return {}; + } + + if (domain == ATTR_DOMAIN_POINT) { + Array<int> vertices(mesh->totvert, 0); + for (const int i : IndexRange(mesh->totloop)) { + int vertex = mesh->mloop[i].v; + vertices[vertex]++; + } + return VArray<int>::ForContainer(std::move(vertices)); + } + return {}; +} + +class VertexFaceCountFieldInput final : public GeometryFieldInput { + public: + VertexFaceCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Vertex Face Count Field") + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask UNUSED(mask)) const final + { + if (component.type() == GEO_COMPONENT_TYPE_MESH) { + const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); + return construct_face_count_gvarray(mesh_component, domain); + } + return {}; + } + + uint64_t hash() const override + { + /* Some random constant hash. */ + return 3462374322; + } + + bool is_equal_to(const fn::FieldNode &other) const override + { + return dynamic_cast<const VertexFaceCountFieldInput *>(&other) != nullptr; + } +}; + +static void node_geo_exec(GeoNodeExecParams params) +{ + Field<int> vertex_field{std::make_shared<VertexCountFieldInput>()}; + Field<int> face_field{std::make_shared<VertexFaceCountFieldInput>()}; + + params.set_output("Vertex Count", std::move(vertex_field)); + params.set_output("Face Count", std::move(face_field)); +} + +} // namespace blender::nodes::node_geo_input_mesh_vertex_neighbors_cc + +void register_node_type_geo_input_mesh_vertex_neighbors() +{ + namespace file_ns = blender::nodes::node_geo_input_mesh_vertex_neighbors_cc; + + static bNodeType ntype; + geo_node_type_base( + &ntype, GEO_NODE_INPUT_MESH_VERTEX_NEIGHBORS, "Vertex Neighbors", NODE_CLASS_INPUT, 0); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc index 6c95ad73bf7..1cc508d9d9d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc @@ -24,9 +24,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_normal_cc { -static void geo_node_input_normal_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Vector>(N_("Normal")).field_source(); } @@ -93,8 +93,7 @@ static VArray<float3> mesh_vertex_normals(const Mesh &mesh, static VArray<float3> construct_mesh_normals_gvarray(const MeshComponent &mesh_component, const Mesh &mesh, const IndexMask mask, - const AttributeDomain domain, - ResourceScope &UNUSED(scope)) + const AttributeDomain domain) { Span<MVert> verts{mesh.mvert, mesh.totvert}; Span<MEdge> edges{mesh.medge, mesh.totedge}; @@ -199,8 +198,7 @@ static Array<float3> curve_normal_point_domain(const CurveEval &curve) } static VArray<float3> construct_curve_normal_gvarray(const CurveComponent &component, - const AttributeDomain domain, - ResourceScope &UNUSED(scope)) + const AttributeDomain domain) { const CurveEval *curve = component.get_for_read(); if (curve == nullptr) { @@ -231,36 +229,29 @@ static VArray<float3> construct_curve_normal_gvarray(const CurveComponent &compo return nullptr; } -class NormalFieldInput final : public fn::FieldInput { +class NormalFieldInput final : public GeometryFieldInput { public: - NormalFieldInput() : fn::FieldInput(CPPType::get<float3>(), "Normal node") + NormalFieldInput() : GeometryFieldInput(CPPType::get<float3>(), "Normal node") { category_ = Category::Generated; } - GVArray get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &scope) const final + GVArray get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask mask) const final { - if (const GeometryComponentFieldContext *geometry_context = - dynamic_cast<const GeometryComponentFieldContext *>(&context)) { - - const GeometryComponent &component = geometry_context->geometry_component(); - const AttributeDomain domain = geometry_context->domain(); - - if (component.type() == GEO_COMPONENT_TYPE_MESH) { - const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); - const Mesh *mesh = mesh_component.get_for_read(); - if (mesh == nullptr) { - return {}; - } - - return construct_mesh_normals_gvarray(mesh_component, *mesh, mask, domain, scope); - } - if (component.type() == GEO_COMPONENT_TYPE_CURVE) { - const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); - return construct_curve_normal_gvarray(curve_component, domain, scope); + if (component.type() == GEO_COMPONENT_TYPE_MESH) { + const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); + const Mesh *mesh = mesh_component.get_for_read(); + if (mesh == nullptr) { + return {}; } + + return construct_mesh_normals_gvarray(mesh_component, *mesh, mask, domain); + } + if (component.type() == GEO_COMPONENT_TYPE_CURVE) { + const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); + return construct_curve_normal_gvarray(curve_component, domain); } return {}; } @@ -277,20 +268,22 @@ class NormalFieldInput final : public fn::FieldInput { } }; -static void geo_node_input_normal_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<float3> normal_field{std::make_shared<NormalFieldInput>()}; params.set_output("Normal", std::move(normal_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_normal_cc void register_node_type_geo_input_normal() { + namespace file_ns = blender::nodes::node_geo_input_normal_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_NORMAL, "Normal", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_normal_exec; - ntype.declare = blender::nodes::geo_node_input_normal_declare; + 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_position.cc b/source/blender/nodes/geometry/nodes/node_geo_input_position.cc index a8477d4bc4f..8322831a871 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_position.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_position.cc @@ -16,27 +16,29 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_position_cc { -static void geo_node_input_position_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Vector>(N_("Position")).field_source(); } -static void geo_node_input_position_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<float3> position_field{AttributeFieldInput::Create<float3>("position")}; params.set_output("Position", std::move(position_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_position_cc void register_node_type_geo_input_position() { + namespace file_ns = blender::nodes::node_geo_input_position_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_POSITION, "Position", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_position_exec; - ntype.declare = blender::nodes::geo_node_input_position_declare; + 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_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc index 6d2c4c38cbe..26fb74f5a5b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc @@ -16,27 +16,29 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_radius_cc { -static void geo_node_input_radius_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Float>(N_("Radius")).default_value(1.0f).min(0.0f).field_source(); } -static void geo_node_input_radius_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<float> radius_field = AttributeFieldInput::Create<float>("radius"); params.set_output("Radius", std::move(radius_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_radius_cc void register_node_type_geo_input_radius() { + namespace file_ns = blender::nodes::node_geo_input_radius_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_RADIUS, "Radius", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_radius_exec; - ntype.declare = blender::nodes::geo_node_input_radius_declare; + 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_scene_time.cc b/source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc new file mode 100644 index 00000000000..cfc1a81f7b9 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc @@ -0,0 +1,50 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "BKE_scene.h" + +#include "DEG_depsgraph_query.h" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_input_scene_time_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_output<decl::Float>(N_("Seconds")); + b.add_output<decl::Float>(N_("Frame")); +} + +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); + params.set_output("Seconds", float(scene_ctime / frame_rate)); + params.set_output("Frame", scene_ctime); +} + +} // namespace blender::nodes::node_geo_input_scene_time_cc + +void register_node_type_geo_input_scene_time() +{ + static bNodeType ntype; + namespace file_ns = blender::nodes::node_geo_input_scene_time_cc; + geo_node_type_base(&ntype, GEO_NODE_INPUT_SCENE_TIME, "Scene Time", NODE_CLASS_INPUT, 0); + ntype.geometry_node_execute = file_ns::node_exec; + ntype.declare = file_ns::node_declare; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc index dcd14b1c054..3efe8577e51 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc @@ -16,27 +16,29 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_shade_smooth_cc { -static void geo_node_input_shade_smooth_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Bool>(N_("Smooth")).field_source(); } -static void geo_node_input_shade_smooth_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<bool> shade_smooth_field = AttributeFieldInput::Create<bool>("shade_smooth"); params.set_output("Smooth", std::move(shade_smooth_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_shade_smooth_cc void register_node_type_geo_input_shade_smooth() { + namespace file_ns = blender::nodes::node_geo_input_shade_smooth_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_SHADE_SMOOTH, "Is Shade Smooth", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_shade_smooth_exec; - ntype.declare = blender::nodes::geo_node_input_shade_smooth_declare; + 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_spline_cyclic.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc index a8ee6dd8b12..5f833445a76 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc @@ -16,28 +16,30 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_spline_cyclic_cc { -static void geo_node_input_spline_cyclic_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Bool>(N_("Cyclic")).field_source(); } -static void geo_node_input_spline_cyclic_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<bool> cyclic_field = AttributeFieldInput::Create<bool>("cyclic"); params.set_output("Cyclic", std::move(cyclic_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_spline_cyclic_cc void register_node_type_geo_input_spline_cyclic() { + namespace file_ns = blender::nodes::node_geo_input_spline_cyclic_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_INPUT_SPLINE_CYCLIC, "Is Spline Cyclic", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_spline_cyclic_exec; - ntype.declare = blender::nodes::geo_node_input_spline_cyclic_declare; + 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_spline_length.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc index a976e0b193f..810d6e2fddd 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc @@ -18,16 +18,20 @@ #include "BKE_spline.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_spline_length_cc { -static void geo_node_input_spline_length_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Float>(N_("Length")).field_source(); + b.add_output<decl::Int>(N_("Point Count")).field_source(); } +/* -------------------------------------------------------------------- + * Spline Length + */ + static VArray<float> construct_spline_length_gvarray(const CurveComponent &component, - const AttributeDomain domain, - ResourceScope &UNUSED(scope)) + const AttributeDomain domain) { const CurveEval *curve = component.get_for_read(); if (curve == nullptr) { @@ -46,29 +50,23 @@ static VArray<float> construct_spline_length_gvarray(const CurveComponent &compo std::move(length), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT); } - return nullptr; + return {}; } -class SplineLengthFieldInput final : public fn::FieldInput { +class SplineLengthFieldInput final : public GeometryFieldInput { public: - SplineLengthFieldInput() : fn::FieldInput(CPPType::get<float>(), "Spline Length node") + SplineLengthFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Spline Length node") { category_ = Category::Generated; } - GVArray get_varray_for_context(const fn::FieldContext &context, - IndexMask UNUSED(mask), - ResourceScope &scope) const final + GVArray get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask UNUSED(mask)) const final { - if (const GeometryComponentFieldContext *geometry_context = - dynamic_cast<const GeometryComponentFieldContext *>(&context)) { - - const GeometryComponent &component = geometry_context->geometry_component(); - const AttributeDomain domain = geometry_context->domain(); - if (component.type() == GEO_COMPONENT_TYPE_CURVE) { - const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); - return construct_spline_length_gvarray(curve_component, domain, scope); - } + if (component.type() == GEO_COMPONENT_TYPE_CURVE) { + const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); + return construct_spline_length_gvarray(curve_component, domain); } return {}; } @@ -85,20 +83,81 @@ class SplineLengthFieldInput final : public fn::FieldInput { } }; -static void geo_node_input_spline_length_exec(GeoNodeExecParams params) +/* -------------------------------------------------------------------- + * Spline Count + */ + +static VArray<int> construct_spline_count_gvarray(const CurveComponent &component, + const AttributeDomain domain) +{ + const CurveEval *curve = component.get_for_read(); + if (curve == nullptr) { + return {}; + } + + Span<SplinePtr> splines = curve->splines(); + auto count_fn = [splines](int i) { return splines[i]->size(); }; + + if (domain == ATTR_DOMAIN_CURVE) { + return VArray<int>::ForFunc(splines.size(), count_fn); + } + if (domain == ATTR_DOMAIN_POINT) { + VArray<int> count = VArray<int>::ForFunc(splines.size(), count_fn); + return component.attribute_try_adapt_domain<int>( + std::move(count), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT); + } + + return {}; +} + +class SplineCountFieldInput final : public GeometryFieldInput { + public: + SplineCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Spline Point Count") + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask UNUSED(mask)) const final + { + if (component.type() == GEO_COMPONENT_TYPE_CURVE) { + const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); + return construct_spline_count_gvarray(curve_component, domain); + } + return {}; + } + + uint64_t hash() const override + { + /* Some random constant hash. */ + return 456364322625; + } + + bool is_equal_to(const fn::FieldNode &other) const override + { + return dynamic_cast<const SplineCountFieldInput *>(&other) != nullptr; + } +}; + +static void node_geo_exec(GeoNodeExecParams params) { - Field<float> length_field{std::make_shared<SplineLengthFieldInput>()}; - params.set_output("Length", std::move(length_field)); + Field<float> spline_length_field{std::make_shared<SplineLengthFieldInput>()}; + Field<int> spline_count_field{std::make_shared<SplineCountFieldInput>()}; + + params.set_output("Length", std::move(spline_length_field)); + params.set_output("Point Count", std::move(spline_count_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_spline_length_cc void register_node_type_geo_input_spline_length() { - static bNodeType ntype; + namespace file_ns = blender::nodes::node_geo_input_spline_length_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_SPLINE_LENGTH, "Spline Length", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_spline_length_exec; - ntype.declare = blender::nodes::geo_node_input_spline_length_declare; + 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_spline_resolution.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc index 75fb8a13d38..77b6e27e6a2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc @@ -16,28 +16,30 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_spline_resolution_cc { -static void geo_node_input_spline_resolution_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Int>(N_("Resolution")).field_source(); } -static void geo_node_input_spline_resolution_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<int> resolution_field = AttributeFieldInput::Create<int>("resolution"); params.set_output("Resolution", std::move(resolution_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_spline_resolution_cc void register_node_type_geo_input_spline_resolution() { + namespace file_ns = blender::nodes::node_geo_input_spline_resolution_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_INPUT_SPLINE_RESOLUTION, "Spline Resolution", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_spline_resolution_exec; - ntype.declare = blender::nodes::geo_node_input_spline_resolution_declare; + 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_tangent.cc b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc index 49885f29d44..86f882df3cd 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc @@ -20,9 +20,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_tangent_cc { -static void geo_node_input_tangent_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Vector>(N_("Tangent")).field_source(); } @@ -85,8 +85,7 @@ static Array<float3> curve_tangent_point_domain(const CurveEval &curve) } static VArray<float3> construct_curve_tangent_gvarray(const CurveComponent &component, - const AttributeDomain domain, - ResourceScope &UNUSED(scope)) + const AttributeDomain domain) { const CurveEval *curve = component.get_for_read(); if (curve == nullptr) { @@ -118,27 +117,20 @@ static VArray<float3> construct_curve_tangent_gvarray(const CurveComponent &comp return nullptr; } -class TangentFieldInput final : public fn::FieldInput { +class TangentFieldInput final : public GeometryFieldInput { public: - TangentFieldInput() : fn::FieldInput(CPPType::get<float3>(), "Tangent node") + TangentFieldInput() : GeometryFieldInput(CPPType::get<float3>(), "Tangent node") { category_ = Category::Generated; } - GVArray get_varray_for_context(const fn::FieldContext &context, - IndexMask UNUSED(mask), - ResourceScope &scope) const final + GVArray get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask UNUSED(mask)) const final { - if (const GeometryComponentFieldContext *geometry_context = - dynamic_cast<const GeometryComponentFieldContext *>(&context)) { - - const GeometryComponent &component = geometry_context->geometry_component(); - const AttributeDomain domain = geometry_context->domain(); - - if (component.type() == GEO_COMPONENT_TYPE_CURVE) { - const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); - return construct_curve_tangent_gvarray(curve_component, domain, scope); - } + if (component.type() == GEO_COMPONENT_TYPE_CURVE) { + const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); + return construct_curve_tangent_gvarray(curve_component, domain); } return {}; } @@ -155,20 +147,22 @@ class TangentFieldInput final : public fn::FieldInput { } }; -static void geo_node_input_tangent_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<float3> tangent_field{std::make_shared<TangentFieldInput>()}; params.set_output("Tangent", std::move(tangent_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_tangent_cc void register_node_type_geo_input_tangent() { + namespace file_ns = blender::nodes::node_geo_input_tangent_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_TANGENT, "Curve Tangent", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_tangent_exec; - ntype.declare = blender::nodes::geo_node_input_tangent_declare; + 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_instance_on_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc index 2a68030aba7..486f90760f5 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 @@ -22,11 +22,13 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "BKE_attribute_math.hh" + #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_instance_on_points_cc { -static void geo_node_instance_on_points_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Points")).description(N_("Points to instance on")); b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value(); @@ -53,20 +55,34 @@ static void geo_node_instance_on_points_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Instances")); } -static void add_instances_from_component(InstancesComponent &dst_component, - const GeometryComponent &src_component, - const GeometrySet &instance, - const GeoNodeExecParams ¶ms) +static void add_instances_from_component( + InstancesComponent &dst_component, + const GeometryComponent &src_component, + const GeometrySet &instance, + const GeoNodeExecParams ¶ms, + const Map<AttributeIDRef, AttributeKind> &attributes_to_propagate) { const AttributeDomain domain = ATTR_DOMAIN_POINT; const int domain_size = src_component.attribute_domain_size(domain); + VArray<bool> pick_instance; + VArray<int> indices; + VArray<float3> rotations; + VArray<float3> scales; + GeometryComponentFieldContext field_context{src_component, domain}; const Field<bool> selection_field = params.get_input<Field<bool>>("Selection"); - fn::FieldEvaluator selection_evaluator{field_context, domain_size}; - selection_evaluator.add(selection_field); - selection_evaluator.evaluate(); - const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0); + fn::FieldEvaluator evaluator{field_context, domain_size}; + evaluator.set_selection(selection_field); + /* The evaluator could use the component's stable IDs as a destination directly, but only the + * selected indices should be copied. */ + evaluator.add(params.get_input<Field<bool>>("Pick Instance"), &pick_instance); + evaluator.add(params.get_input<Field<int>>("Instance Index"), &indices); + evaluator.add(params.get_input<Field<float3>>("Rotation"), &rotations); + evaluator.add(params.get_input<Field<float3>>("Scale"), &scales); + evaluator.evaluate(); + + const IndexMask selection = evaluator.get_evaluated_selection_as_mask(); /* The initial size of the component might be non-zero when this function is called for multiple * component types. */ @@ -79,19 +95,6 @@ static void add_instances_from_component(InstancesComponent &dst_component, MutableSpan<float4x4> dst_transforms = dst_component.instance_transforms().slice(start_len, select_len); - FieldEvaluator field_evaluator{field_context, domain_size}; - VArray<bool> pick_instance; - VArray<int> indices; - VArray<float3> rotations; - VArray<float3> scales; - /* The evaluator could use the component's stable IDs as a destination directly, but only the - * selected indices should be copied. */ - field_evaluator.add(params.get_input<Field<bool>>("Pick Instance"), &pick_instance); - field_evaluator.add(params.get_input<Field<int>>("Instance Index"), &indices); - field_evaluator.add(params.get_input<Field<float3>>("Rotation"), &rotations); - field_evaluator.add(params.get_input<Field<float3>>("Scale"), &scales); - field_evaluator.evaluate(); - VArray<float3> positions = src_component.attribute_get_for_read<float3>( "position", domain, {0, 0, 0}); @@ -154,17 +157,6 @@ static void add_instances_from_component(InstancesComponent &dst_component, } }); - VArray<int> ids = src_component - .attribute_try_get_for_read("id", ATTR_DOMAIN_POINT, CD_PROP_INT32) - .typed<int>(); - if (ids) { - VArray_Span<int> ids_span{ids}; - MutableSpan<int> dst_ids = dst_component.instance_ids_ensure(); - for (const int64_t i : selection.index_range()) { - dst_ids[i] = ids_span[selection[i]]; - } - } - if (pick_instance.is_single()) { if (pick_instance.get_internal_single()) { if (instance.has_realized_data()) { @@ -174,9 +166,40 @@ static void add_instances_from_component(InstancesComponent &dst_component, } } } + + bke::CustomDataAttributes &instance_attributes = dst_component.attributes(); + for (const auto item : attributes_to_propagate.items()) { + const AttributeIDRef &attribute_id = item.key; + const AttributeKind attribute_kind = item.value; + + const GVArray src_attribute = src_component.attribute_get_for_read( + attribute_id, ATTR_DOMAIN_POINT, attribute_kind.data_type); + BLI_assert(src_attribute); + std::optional<GMutableSpan> dst_attribute_opt = instance_attributes.get_for_write( + attribute_id); + if (!dst_attribute_opt) { + if (!instance_attributes.create(attribute_id, attribute_kind.data_type)) { + continue; + } + dst_attribute_opt = instance_attributes.get_for_write(attribute_id); + } + BLI_assert(dst_attribute_opt); + const GMutableSpan dst_attribute = dst_attribute_opt->slice(start_len, select_len); + threading::parallel_for(selection.index_range(), 1024, [&](IndexRange selection_range) { + attribute_math::convert_to_static_type(attribute_kind.data_type, [&](auto dummy) { + using T = decltype(dummy); + VArray<T> src = src_attribute.typed<T>(); + MutableSpan<T> dst = dst_attribute.typed<T>(); + for (const int range_i : selection_range) { + const int i = selection[range_i]; + dst[range_i] = src[i]; + } + }); + }); + } } -static void geo_node_instance_on_points_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Points"); GeometrySet instance = params.get_input<GeometrySet>("Instance"); @@ -185,23 +208,36 @@ static void geo_node_instance_on_points_exec(GeoNodeExecParams params) geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>(); + Map<AttributeIDRef, AttributeKind> attributes_to_propagate; + geometry_set.gather_attributes_for_propagation( + {GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}, + GEO_COMPONENT_TYPE_INSTANCES, + false, + attributes_to_propagate); + attributes_to_propagate.remove("position"); + if (geometry_set.has<MeshComponent>()) { - add_instances_from_component( - instances, *geometry_set.get_component_for_read<MeshComponent>(), instance, params); - geometry_set.remove(GEO_COMPONENT_TYPE_MESH); + add_instances_from_component(instances, + *geometry_set.get_component_for_read<MeshComponent>(), + instance, + params, + attributes_to_propagate); } if (geometry_set.has<PointCloudComponent>()) { add_instances_from_component(instances, *geometry_set.get_component_for_read<PointCloudComponent>(), instance, - params); - geometry_set.remove(GEO_COMPONENT_TYPE_POINT_CLOUD); + params, + attributes_to_propagate); } if (geometry_set.has<CurveComponent>()) { - add_instances_from_component( - instances, *geometry_set.get_component_for_read<CurveComponent>(), instance, params); - geometry_set.remove(GEO_COMPONENT_TYPE_CURVE); + add_instances_from_component(instances, + *geometry_set.get_component_for_read<CurveComponent>(), + instance, + params, + attributes_to_propagate); } + geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES}); }); /* Unused references may have been added above. Remove those now so that other nodes don't @@ -214,15 +250,17 @@ static void geo_node_instance_on_points_exec(GeoNodeExecParams params) params.set_output("Instances", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_instance_on_points_cc void register_node_type_geo_instance_on_points() { + namespace file_ns = blender::nodes::node_geo_instance_on_points_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_INSTANCE_ON_POINTS, "Instance on Points", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_instance_on_points_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_instance_on_points_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc index c3955426e69..9942e388ba5 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 @@ -14,14 +14,16 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "BKE_pointcloud.h" #include "DNA_pointcloud_types.h" +#include "BKE_attribute_math.hh" +#include "BKE_pointcloud.h" + #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_instances_to_points_cc { -static void geo_node_instances_to_points_declare(NodeDeclarationBuilder &b) +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(); @@ -51,14 +53,15 @@ static void convert_instances_to_points(GeometrySet &geometry_set, { const InstancesComponent &instances = *geometry_set.get_component_for_read<InstancesComponent>(); - const AttributeDomain attribute_domain = ATTR_DOMAIN_POINT; - GeometryComponentFieldContext field_context{instances, attribute_domain}; - const int domain_size = instances.attribute_domain_size(attribute_domain); + GeometryComponentFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE}; + const int domain_size = instances.attribute_domain_size(ATTR_DOMAIN_INSTANCE); - fn::FieldEvaluator selection_evaluator{field_context, domain_size}; - selection_evaluator.add(std::move(selection_field)); - selection_evaluator.evaluate(); - const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0); + fn::FieldEvaluator evaluator{field_context, domain_size}; + evaluator.set_selection(std::move(selection_field)); + evaluator.add(std::move(position_field)); + evaluator.add(std::move(radius_field)); + evaluator.evaluate(); + const IndexMask selection = evaluator.get_evaluated_selection_as_mask(); if (selection.is_empty()) { return; } @@ -68,27 +71,40 @@ static void convert_instances_to_points(GeometrySet &geometry_set, PointCloudComponent &points = geometry_set.get_component_for_write<PointCloudComponent>(); - fn::FieldEvaluator evaluator{field_context, &selection}; - evaluator.add(std::move(position_field)); - evaluator.add(std::move(radius_field)); - evaluator.evaluate(); const VArray<float3> &positions = evaluator.get_evaluated<float3>(0); copy_attribute_to_points(positions, selection, {(float3 *)pointcloud->co, pointcloud->totpoint}); const VArray<float> &radii = evaluator.get_evaluated<float>(1); copy_attribute_to_points(radii, selection, {pointcloud->radius, pointcloud->totpoint}); - if (!instances.instance_ids().is_empty()) { - OutputAttribute_Typed<int> id_attribute = points.attribute_try_get_for_output<int>( - "id", ATTR_DOMAIN_POINT, CD_PROP_INT32); - MutableSpan<int> ids = id_attribute.as_span(); - for (const int i : selection.index_range()) { - ids[i] = instances.instance_ids()[selection[i]]; - } - id_attribute.save(); + Map<AttributeIDRef, AttributeKind> attributes_to_propagate; + geometry_set.gather_attributes_for_propagation({GEO_COMPONENT_TYPE_INSTANCES}, + GEO_COMPONENT_TYPE_POINT_CLOUD, + false, + attributes_to_propagate); + /* These two attributes are added by the implicit inputs above. */ + attributes_to_propagate.remove("position"); + attributes_to_propagate.remove("radius"); + + for (const auto item : attributes_to_propagate.items()) { + const AttributeIDRef &attribute_id = item.key; + const AttributeKind attribute_kind = item.value; + + const GVArray src = instances.attribute_get_for_read( + attribute_id, ATTR_DOMAIN_INSTANCE, attribute_kind.data_type); + BLI_assert(src); + OutputAttribute dst = points.attribute_try_get_for_output_only( + attribute_id, ATTR_DOMAIN_POINT, attribute_kind.data_type); + BLI_assert(dst); + + attribute_math::convert_to_static_type(attribute_kind.data_type, [&](auto dummy) { + using T = decltype(dummy); + copy_attribute_to_points(src.typed<T>(), selection, dst.as_span().typed<T>()); + }); + dst.save(); } } -static void geo_node_instances_to_points_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances"); @@ -101,19 +117,21 @@ static void geo_node_instances_to_points_exec(GeoNodeExecParams params) params.set_output("Points", std::move(geometry_set)); } else { - params.set_output("Points", GeometrySet()); + params.set_default_remaining_outputs(); } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_instances_to_points_cc void register_node_type_geo_instances_to_points() { + namespace file_ns = blender::nodes::node_geo_instances_to_points_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_INSTANCES_TO_POINTS, "Instances to Points", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_instances_to_points_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_instances_to_points_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc b/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc index 8e0e98f7bd5..5925d440317 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc @@ -18,14 +18,14 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_is_viewport_cc { -static void geo_node_is_viewport_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Bool>(N_("Is Viewport")); } -static void geo_node_is_viewport_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const Depsgraph *depsgraph = params.depsgraph(); const eEvaluationMode mode = DEG_get_mode(depsgraph); @@ -34,14 +34,16 @@ static void geo_node_is_viewport_exec(GeoNodeExecParams params) params.set_output("Is Viewport", is_viewport); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_is_viewport_cc void register_node_type_geo_is_viewport() { + namespace file_ns = blender::nodes::node_geo_is_viewport_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_IS_VIEWPORT, "Is Viewport", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_is_viewport_exec; - ntype.declare = blender::nodes::geo_node_is_viewport_declare; + 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_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc index fcdf7c2da01..bf7a9f49829 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc @@ -19,127 +19,23 @@ #include "BKE_mesh_runtime.h" #include "BKE_pointcloud.h" #include "BKE_spline.hh" +#include "BKE_type_conversions.hh" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "NOD_type_conversions.hh" +#include "GEO_realize_instances.hh" #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_join_geometry_cc { -static void geo_node_join_geometry_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")).multi_input(); b.add_output<decl::Geometry>(N_("Geometry")); } -static Mesh *join_mesh_topology_and_builtin_attributes(Span<const MeshComponent *> src_components) -{ - int totverts = 0; - int totloops = 0; - int totedges = 0; - int totpolys = 0; - - int64_t cd_dirty_vert = 0; - int64_t cd_dirty_poly = 0; - int64_t cd_dirty_edge = 0; - int64_t cd_dirty_loop = 0; - - VectorSet<Material *> materials; - - for (const MeshComponent *mesh_component : src_components) { - const Mesh *mesh = mesh_component->get_for_read(); - totverts += mesh->totvert; - totloops += mesh->totloop; - totedges += mesh->totedge; - totpolys += mesh->totpoly; - cd_dirty_vert |= mesh->runtime.cd_dirty_vert; - cd_dirty_poly |= mesh->runtime.cd_dirty_poly; - cd_dirty_edge |= mesh->runtime.cd_dirty_edge; - cd_dirty_loop |= mesh->runtime.cd_dirty_loop; - - for (const int slot_index : IndexRange(mesh->totcol)) { - Material *material = mesh->mat[slot_index]; - materials.add(material); - } - } - - const Mesh *first_input_mesh = src_components[0]->get_for_read(); - Mesh *new_mesh = BKE_mesh_new_nomain(totverts, totedges, 0, totloops, totpolys); - BKE_mesh_copy_parameters_for_eval(new_mesh, first_input_mesh); - - for (const int i : IndexRange(materials.size())) { - Material *material = materials[i]; - BKE_id_material_eval_assign(&new_mesh->id, i + 1, material); - } - - new_mesh->runtime.cd_dirty_vert = cd_dirty_vert; - new_mesh->runtime.cd_dirty_poly = cd_dirty_poly; - new_mesh->runtime.cd_dirty_edge = cd_dirty_edge; - new_mesh->runtime.cd_dirty_loop = cd_dirty_loop; - - int vert_offset = 0; - int loop_offset = 0; - int edge_offset = 0; - int poly_offset = 0; - for (const MeshComponent *mesh_component : src_components) { - const Mesh *mesh = mesh_component->get_for_read(); - if (mesh == nullptr) { - continue; - } - - Array<int> material_index_map(mesh->totcol); - for (const int i : IndexRange(mesh->totcol)) { - Material *material = mesh->mat[i]; - const int new_material_index = materials.index_of(material); - material_index_map[i] = new_material_index; - } - - for (const int i : IndexRange(mesh->totvert)) { - const MVert &old_vert = mesh->mvert[i]; - MVert &new_vert = new_mesh->mvert[vert_offset + i]; - new_vert = old_vert; - } - - for (const int i : IndexRange(mesh->totedge)) { - const MEdge &old_edge = mesh->medge[i]; - MEdge &new_edge = new_mesh->medge[edge_offset + i]; - new_edge = old_edge; - new_edge.v1 += vert_offset; - new_edge.v2 += vert_offset; - } - for (const int i : IndexRange(mesh->totloop)) { - const MLoop &old_loop = mesh->mloop[i]; - MLoop &new_loop = new_mesh->mloop[loop_offset + i]; - new_loop = old_loop; - new_loop.v += vert_offset; - new_loop.e += edge_offset; - } - for (const int i : IndexRange(mesh->totpoly)) { - const MPoly &old_poly = mesh->mpoly[i]; - MPoly &new_poly = new_mesh->mpoly[poly_offset + i]; - new_poly = old_poly; - new_poly.loopstart += loop_offset; - if (old_poly.mat_nr >= 0 && old_poly.mat_nr < mesh->totcol) { - new_poly.mat_nr = material_index_map[new_poly.mat_nr]; - } - else { - /* The material index was invalid before. */ - new_poly.mat_nr = 0; - } - } - - vert_offset += mesh->totvert; - loop_offset += mesh->totloop; - edge_offset += mesh->totedge; - poly_offset += mesh->totpoly; - } - - return new_mesh; -} - template<typename Component> static Array<const GeometryComponent *> to_base_components(Span<const Component *> components) { @@ -223,33 +119,6 @@ static void join_attributes(Span<const GeometryComponent *> src_components, } } -static void join_components(Span<const MeshComponent *> src_components, GeometrySet &result) -{ - Mesh *new_mesh = join_mesh_topology_and_builtin_attributes(src_components); - - MeshComponent &dst_component = result.get_component_for_write<MeshComponent>(); - dst_component.replace(new_mesh); - - /* Don't copy attributes that are stored directly in the mesh data structs. */ - join_attributes(to_base_components(src_components), - dst_component, - {"position", "material_index", "normal", "shade_smooth", "crease"}); -} - -static void join_components(Span<const PointCloudComponent *> src_components, GeometrySet &result) -{ - int totpoints = 0; - for (const PointCloudComponent *pointcloud_component : src_components) { - totpoints += pointcloud_component->attribute_domain_size(ATTR_DOMAIN_POINT); - } - - PointCloudComponent &dst_component = result.get_component_for_write<PointCloudComponent>(); - PointCloud *pointcloud = BKE_pointcloud_new_nomain(totpoints); - dst_component.replace(pointcloud); - - join_attributes(to_base_components(src_components), dst_component); -} - static void join_components(Span<const InstancesComponent *> src_components, GeometrySet &result) { InstancesComponent &dst_component = result.get_component_for_write<InstancesComponent>(); @@ -288,192 +157,6 @@ static void join_components(Span<const VolumeComponent *> src_components, Geomet UNUSED_VARS(src_components, dst_component); } -/** - * \note This takes advantage of the fact that creating attributes on joined curves never - * changes a point attribute into a spline attribute; it is always the other way around. - */ -static void ensure_control_point_attribute(const AttributeIDRef &attribute_id, - const CustomDataType data_type, - Span<CurveComponent *> src_components, - CurveEval &result) -{ - MutableSpan<SplinePtr> splines = result.splines(); - const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type); - - /* In order to fill point attributes with spline domain attribute values where necessary, keep - * track of the curve each spline came from while iterating over the splines in the result. */ - int src_component_index = 0; - int spline_index_in_component = 0; - const CurveEval *current_curve = src_components[src_component_index]->get_for_read(); - - for (SplinePtr &spline : splines) { - std::optional<GSpan> attribute = spline->attributes.get_for_read(attribute_id); - - if (attribute) { - if (attribute->type() != type) { - /* In this case, the attribute exists, but it has the wrong type. So create a buffer - * for the converted values, do the conversion, and then replace the attribute. */ - void *converted_buffer = MEM_mallocN_aligned( - spline->size() * type.size(), type.alignment(), __func__); - - const DataTypeConversions &conversions = blender::nodes::get_implicit_type_conversions(); - conversions.try_convert(GVArray::ForSpan(*attribute), type).materialize(converted_buffer); - - spline->attributes.remove(attribute_id); - spline->attributes.create_by_move(attribute_id, data_type, converted_buffer); - } - } - else { - spline->attributes.create(attribute_id, data_type); - - if (current_curve->attributes.get_for_read(attribute_id)) { - /* In this case the attribute did not exist, but there is a spline domain attribute - * we can retrieve a value from, as a spline to point domain conversion. So fill the - * new attribute with the value for this spline. */ - GVArray current_curve_attribute = current_curve->attributes.get_for_read( - attribute_id, data_type, nullptr); - - BLI_assert(spline->attributes.get_for_read(attribute_id)); - std::optional<GMutableSpan> new_attribute = spline->attributes.get_for_write(attribute_id); - - BUFFER_FOR_CPP_TYPE_VALUE(type, buffer); - current_curve_attribute.get(spline_index_in_component, buffer); - type.fill_assign_n(buffer, new_attribute->data(), new_attribute->size()); - } - } - - /* Move to the next spline and maybe the next input component. */ - spline_index_in_component++; - if (spline != splines.last() && spline_index_in_component >= current_curve->splines().size()) { - src_component_index++; - spline_index_in_component = 0; - - current_curve = src_components[src_component_index]->get_for_read(); - } - } -} - -/** - * Curve point domain attributes must be in the same order on every spline. The order might have - * been different on separate instances, so ensure that all splines have the same order. Note that - * because #Map is used, the order is not necessarily consistent every time, but it is the same for - * every spline, and that's what matters. - */ -static void sort_curve_point_attributes(const Map<AttributeIDRef, AttributeMetaData> &info, - MutableSpan<SplinePtr> splines) -{ - Vector<AttributeIDRef> new_order; - for (Map<AttributeIDRef, AttributeMetaData>::Item item : info.items()) { - if (item.value.domain == ATTR_DOMAIN_POINT) { - /* Only sort attributes stored on splines. */ - new_order.append(item.key); - } - } - for (SplinePtr &spline : splines) { - spline->attributes.reorder(new_order); - } -} - -/** - * Fill data for an attribute on the new curve based on all source curves. - */ -static void ensure_spline_attribute(const AttributeIDRef &attribute_id, - const CustomDataType data_type, - Span<CurveComponent *> src_components, - CurveEval &result) -{ - const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type); - - result.attributes.create(attribute_id, data_type); - GMutableSpan result_attribute = *result.attributes.get_for_write(attribute_id); - - int offset = 0; - for (const CurveComponent *component : src_components) { - const CurveEval &curve = *component->get_for_read(); - const int size = curve.splines().size(); - if (size == 0) { - continue; - } - GVArray read_attribute = curve.attributes.get_for_read(attribute_id, data_type, nullptr); - GVArray_GSpan src_span{read_attribute}; - - const void *src_buffer = src_span.data(); - type.copy_assign_n(src_buffer, result_attribute[offset], size); - - offset += size; - } -} - -/** - * Special handling for copying spline attributes. This is necessary because we move the splines - * out of the source components instead of copying them, meaning we can no longer access point - * domain attributes on the source components. - * - * \warning Splines have been moved out of the source components at this point, so it - * is important to only read curve-level data (spline domain attributes) from them. - */ -static void join_curve_attributes(const Map<AttributeIDRef, AttributeMetaData> &info, - Span<CurveComponent *> src_components, - CurveEval &result) -{ - for (const Map<AttributeIDRef, AttributeMetaData>::Item item : info.items()) { - const AttributeIDRef attribute_id = item.key; - const AttributeMetaData meta_data = item.value; - - if (meta_data.domain == ATTR_DOMAIN_CURVE) { - ensure_spline_attribute(attribute_id, meta_data.data_type, src_components, result); - } - else { - ensure_control_point_attribute(attribute_id, meta_data.data_type, src_components, result); - } - } - - sort_curve_point_attributes(info, result.splines()); -} - -static void join_curve_components(MutableSpan<GeometrySet> src_geometry_sets, GeometrySet &result) -{ - Vector<CurveComponent *> src_components; - for (GeometrySet &geometry_set : src_geometry_sets) { - if (geometry_set.has_curve()) { - /* Retrieving with write access seems counterintuitive, but it can allow avoiding a copy - * in the case where the input spline has no other users, because the splines can be - * moved from the source curve rather than copied from a read-only source. Retrieving - * the curve for write will make a copy only when it has a user elsewhere. */ - CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>(); - src_components.append(&component); - } - } - - if (src_components.size() == 0) { - return; - } - if (src_components.size() == 1) { - result.add(*src_components[0]); - return; - } - - /* Retrieve attribute info before moving the splines out of the input components. */ - const Map<AttributeIDRef, AttributeMetaData> info = get_final_attribute_info( - {(const GeometryComponent **)src_components.data(), src_components.size()}, - {"position", "radius", "tilt", "handle_left", "handle_right", "cyclic", "resolution"}); - - CurveComponent &dst_component = result.get_component_for_write<CurveComponent>(); - CurveEval *dst_curve = new CurveEval(); - for (CurveComponent *component : src_components) { - CurveEval *src_curve = component->get_for_write(); - for (SplinePtr &spline : src_curve->splines()) { - dst_curve->add_spline(std::move(spline)); - } - } - dst_curve->attributes.reallocate(dst_curve->splines().size()); - - join_curve_attributes(info, src_components, *dst_curve); - dst_curve->assert_valid_point_attributes(); - - dst_component.replace(dst_curve); -} - template<typename Component> static void join_component_type(Span<GeometrySet> src_geometry_sets, GeometrySet &result) { @@ -492,10 +175,32 @@ static void join_component_type(Span<GeometrySet> src_geometry_sets, GeometrySet result.add(*components[0]); return; } - join_components(components, result); + + GeometrySet instances_geometry_set; + InstancesComponent &instances = + instances_geometry_set.get_component_for_write<InstancesComponent>(); + + if constexpr (std::is_same_v<Component, InstancesComponent> || + std::is_same_v<Component, VolumeComponent>) { + join_components(components, result); + } + else { + for (const Component *component : components) { + GeometrySet tmp_geo; + tmp_geo.add(*component); + const int handle = instances.add_reference(InstanceReference{tmp_geo}); + instances.add_instance(handle, float4x4::identity()); + } + + geometry::RealizeInstancesOptions options; + options.keep_original_ids = true; + options.realize_instance_attributes = false; + GeometrySet joined_components = geometry::realize_instances(instances_geometry_set, options); + result.add(joined_components.get_component_for_write<Component>()); + } } -static void geo_node_join_geometry_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Vector<GeometrySet> geometry_sets = params.extract_multi_input<GeometrySet>("Geometry"); @@ -504,18 +209,20 @@ static void geo_node_join_geometry_exec(GeoNodeExecParams params) join_component_type<PointCloudComponent>(geometry_sets, geometry_set_result); join_component_type<InstancesComponent>(geometry_sets, geometry_set_result); join_component_type<VolumeComponent>(geometry_sets, geometry_set_result); - join_curve_components(geometry_sets, geometry_set_result); + join_component_type<CurveComponent>(geometry_sets, geometry_set_result); params.set_output("Geometry", std::move(geometry_set_result)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_join_geometry_cc void register_node_type_geo_join_geometry() { + namespace file_ns = blender::nodes::node_geo_join_geometry_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_JOIN_GEOMETRY, "Join Geometry", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_join_geometry_exec; - ntype.declare = blender::nodes::geo_node_join_geometry_declare; + 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_material_replace.cc b/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc index e4a62bd5267..5a334126350 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc @@ -24,9 +24,9 @@ #include "BKE_material.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_material_replace_cc { -static void geo_node_material_replace_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_MESH); b.add_input<decl::Material>(N_("Old")); @@ -34,7 +34,7 @@ static void geo_node_material_replace_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_material_replace_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Material *old_material = params.extract_input<Material *>("Old"); Material *new_material = params.extract_input<Material *>("New"); @@ -55,15 +55,17 @@ static void geo_node_material_replace_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_material_replace_cc void register_node_type_geo_material_replace() { + namespace file_ns = blender::nodes::node_geo_material_replace_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_REPLACE_MATERIAL, "Replace Material", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_material_replace_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_material_replace_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc index 12ffa21762e..2aad68e7c25 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc @@ -26,9 +26,9 @@ #include "BKE_material.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_material_selection_cc { -static void geo_node_material_selection_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Material>(N_("Material")).hide_label(true); b.add_output<decl::Bool>(N_("Selection")).field_source(); @@ -54,45 +54,40 @@ static void select_mesh_by_material(const Mesh &mesh, }); } -class MaterialSelectionFieldInput final : public fn::FieldInput { +class MaterialSelectionFieldInput final : public GeometryFieldInput { Material *material_; public: MaterialSelectionFieldInput(Material *material) - : fn::FieldInput(CPPType::get<bool>(), "Material Selection node"), material_(material) + : GeometryFieldInput(CPPType::get<bool>(), "Material Selection node"), material_(material) { category_ = Category::Generated; } - GVArray get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &UNUSED(scope)) const final + GVArray get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask mask) const final { - if (const GeometryComponentFieldContext *geometry_context = - dynamic_cast<const GeometryComponentFieldContext *>(&context)) { - const GeometryComponent &component = geometry_context->geometry_component(); - const AttributeDomain domain = geometry_context->domain(); - if (component.type() != GEO_COMPONENT_TYPE_MESH) { - return {}; - } - const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); - const Mesh *mesh = mesh_component.get_for_read(); - if (mesh == nullptr) { - return {}; - } - - if (domain == ATTR_DOMAIN_FACE) { - Array<bool> selection(mask.min_array_size()); - select_mesh_by_material(*mesh, material_, mask, selection); - return VArray<bool>::ForContainer(std::move(selection)); - } - - Array<bool> selection(mesh->totpoly); - select_mesh_by_material(*mesh, material_, IndexMask(mesh->totpoly), selection); - return mesh_component.attribute_try_adapt_domain<bool>( - VArray<bool>::ForContainer(std::move(selection)), ATTR_DOMAIN_FACE, domain); + if (component.type() != GEO_COMPONENT_TYPE_MESH) { + return {}; + } + const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); + const Mesh *mesh = mesh_component.get_for_read(); + if (mesh == nullptr) { + return {}; + } + + if (domain == ATTR_DOMAIN_FACE) { + Array<bool> selection(mask.min_array_size()); + select_mesh_by_material(*mesh, material_, mask, selection); + return VArray<bool>::ForContainer(std::move(selection)); } + Array<bool> selection(mesh->totpoly); + select_mesh_by_material(*mesh, material_, IndexMask(mesh->totpoly), selection); + return mesh_component.attribute_try_adapt_domain<bool>( + VArray<bool>::ForContainer(std::move(selection)), ATTR_DOMAIN_FACE, domain); + return nullptr; } @@ -111,22 +106,24 @@ class MaterialSelectionFieldInput final : public fn::FieldInput { } }; -static void geo_node_material_selection_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Material *material = params.extract_input<Material *>("Material"); Field<bool> material_field{std::make_shared<MaterialSelectionFieldInput>(material)}; params.set_output("Selection", std::move(material_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_material_selection_cc void register_node_type_geo_material_selection() { + namespace file_ns = blender::nodes::node_geo_material_selection_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_MATERIAL_SELECTION, "Material Selection", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_material_selection_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_material_selection_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc index f1f95be107a..7a1cb8a62a3 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 @@ -25,9 +25,11 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_mesh_primitive_circle_cc { -static void geo_node_mesh_primitive_circle_declare(NodeDeclarationBuilder &b) +NODE_STORAGE_FUNCS(NodeGeometryMeshCircle) + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Int>(N_("Vertices")) .default_value(32) @@ -41,16 +43,14 @@ static void geo_node_mesh_primitive_circle_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Mesh")); } -static void geo_node_mesh_primitive_circle_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE); } -static void geo_node_mesh_primitive_circle_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryMeshCircle *node_storage = (NodeGeometryMeshCircle *)MEM_callocN( sizeof(NodeGeometryMeshCircle), __func__); @@ -199,42 +199,41 @@ static Mesh *create_circle_mesh(const float radius, return mesh; } -static void geo_node_mesh_primitive_circle_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { - const bNode &node = params.node(); - const NodeGeometryMeshCircle &storage = *(const NodeGeometryMeshCircle *)node.storage; - - const GeometryNodeMeshCircleFillType fill_type = (const GeometryNodeMeshCircleFillType) - storage.fill_type; + const NodeGeometryMeshCircle &storage = node_storage(params.node()); + const GeometryNodeMeshCircleFillType fill = (GeometryNodeMeshCircleFillType)storage.fill_type; const float radius = params.extract_input<float>("Radius"); const int verts_num = params.extract_input<int>("Vertices"); if (verts_num < 3) { params.error_message_add(NodeWarningType::Info, TIP_("Vertices must be at least 3")); - params.set_output("Mesh", GeometrySet()); + params.set_default_remaining_outputs(); return; } - Mesh *mesh = create_circle_mesh(radius, verts_num, fill_type); + Mesh *mesh = create_circle_mesh(radius, verts_num, fill); BLI_assert(BKE_mesh_is_valid(mesh)); params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_primitive_circle_cc void register_node_type_geo_mesh_primitive_circle() { + namespace file_ns = blender::nodes::node_geo_mesh_primitive_circle_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_MESH_PRIMITIVE_CIRCLE, "Mesh Circle", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_mesh_primitive_circle_init); + node_type_init(&ntype, file_ns::node_init); node_type_storage( &ntype, "NodeGeometryMeshCircle", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_circle_exec; - ntype.draw_buttons = blender::nodes::geo_node_mesh_primitive_circle_layout; - ntype.declare = blender::nodes::geo_node_mesh_primitive_circle_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } 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 fc93f6e72b5..70b093798f8 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 @@ -29,75 +29,6 @@ namespace blender::nodes { -static void geo_node_mesh_primitive_cone_declare(NodeDeclarationBuilder &b) -{ - b.add_input<decl::Int>(N_("Vertices")) - .default_value(32) - .min(3) - .max(512) - .description(N_("Number of points on the circle at the top and bottom")); - b.add_input<decl::Int>(N_("Side Segments")) - .default_value(1) - .min(1) - .max(512) - .description(N_("The number of edges running vertically along the side of the cone")); - b.add_input<decl::Int>(N_("Fill Segments")) - .default_value(1) - .min(1) - .max(512) - .description(N_("Number of concentric rings used to fill the round face")); - b.add_input<decl::Float>(N_("Radius Top")) - .min(0.0f) - .subtype(PROP_DISTANCE) - .description(N_("Radius of the top circle of the cone")); - b.add_input<decl::Float>(N_("Radius Bottom")) - .default_value(1.0f) - .min(0.0f) - .subtype(PROP_DISTANCE) - .description(N_("Radius of the bottom circle of the cone")); - b.add_input<decl::Float>(N_("Depth")) - .default_value(2.0f) - .min(0.0f) - .subtype(PROP_DISTANCE) - .description(N_("Height of the generated cone")); - b.add_output<decl::Geometry>(N_("Mesh")); - b.add_output<decl::Bool>(N_("Top")).field_source(); - b.add_output<decl::Bool>(N_("Bottom")).field_source(); - b.add_output<decl::Bool>(N_("Side")).field_source(); -} - -static void geo_node_mesh_primitive_cone_init(bNodeTree *UNUSED(ntree), bNode *node) -{ - NodeGeometryMeshCone *node_storage = (NodeGeometryMeshCone *)MEM_callocN( - sizeof(NodeGeometryMeshCone), __func__); - - node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NGON; - - node->storage = node_storage; -} - -static void geo_node_mesh_primitive_cone_update(bNodeTree *ntree, bNode *node) -{ - bNodeSocket *vertices_socket = (bNodeSocket *)node->inputs.first; - bNodeSocket *rings_socket = vertices_socket->next; - bNodeSocket *fill_subdiv_socket = rings_socket->next; - - const NodeGeometryMeshCone &storage = *(const NodeGeometryMeshCone *)node->storage; - const GeometryNodeMeshCircleFillType fill_type = - static_cast<const GeometryNodeMeshCircleFillType>(storage.fill_type); - const bool has_fill = fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE; - nodeSetSocketAvailability(ntree, fill_subdiv_socket, has_fill); -} - -static void geo_node_mesh_primitive_cone_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) -{ - uiLayoutSetPropSep(layout, true); - uiLayoutSetPropDecorate(layout, false); - uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE); -} - struct ConeConfig { float radius_top; float radius_bottom; @@ -794,37 +725,103 @@ Mesh *create_cylinder_or_cone_mesh(const float radius_top, return mesh; } -static void geo_node_mesh_primitive_cone_exec(GeoNodeExecParams params) +} // namespace blender::nodes + +namespace blender::nodes::node_geo_mesh_primitive_cone_cc { + +NODE_STORAGE_FUNCS(NodeGeometryMeshCone) + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Int>(N_("Vertices")) + .default_value(32) + .min(3) + .max(512) + .description(N_("Number of points on the circle at the top and bottom")); + b.add_input<decl::Int>(N_("Side Segments")) + .default_value(1) + .min(1) + .max(512) + .description(N_("The number of edges running vertically along the side of the cone")); + b.add_input<decl::Int>(N_("Fill Segments")) + .default_value(1) + .min(1) + .max(512) + .description(N_("Number of concentric rings used to fill the round face")); + b.add_input<decl::Float>(N_("Radius Top")) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("Radius of the top circle of the cone")); + b.add_input<decl::Float>(N_("Radius Bottom")) + .default_value(1.0f) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("Radius of the bottom circle of the cone")); + b.add_input<decl::Float>(N_("Depth")) + .default_value(2.0f) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("Height of the generated cone")); + b.add_output<decl::Geometry>(N_("Mesh")); + b.add_output<decl::Bool>(N_("Top")).field_source(); + b.add_output<decl::Bool>(N_("Bottom")).field_source(); + b.add_output<decl::Bool>(N_("Side")).field_source(); +} + +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { - const bNode &node = params.node(); - const NodeGeometryMeshCone &storage = *(const NodeGeometryMeshCone *)node.storage; - const GeometryNodeMeshCircleFillType fill_type = (const GeometryNodeMeshCircleFillType) - storage.fill_type; - - auto return_default = [&]() { - params.set_output("Top", fn::make_constant_field<bool>(false)); - params.set_output("Bottom", fn::make_constant_field<bool>(false)); - params.set_output("Side", fn::make_constant_field<bool>(false)); - params.set_output("Mesh", GeometrySet()); - }; + NodeGeometryMeshCone *node_storage = (NodeGeometryMeshCone *)MEM_callocN( + sizeof(NodeGeometryMeshCone), __func__); + + node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NGON; + + node->storage = node_storage; +} + +static void node_update(bNodeTree *ntree, bNode *node) +{ + bNodeSocket *vertices_socket = (bNodeSocket *)node->inputs.first; + bNodeSocket *rings_socket = vertices_socket->next; + bNodeSocket *fill_subdiv_socket = rings_socket->next; + + const NodeGeometryMeshCone &storage = node_storage(*node); + const GeometryNodeMeshCircleFillType fill = (GeometryNodeMeshCircleFillType)storage.fill_type; + const bool has_fill = fill != GEO_NODE_MESH_CIRCLE_FILL_NONE; + nodeSetSocketAvailability(ntree, fill_subdiv_socket, has_fill); +} + +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); + uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE); +} + +static void node_geo_exec(GeoNodeExecParams params) +{ + const NodeGeometryMeshCone &storage = node_storage(params.node()); + const GeometryNodeMeshCircleFillType fill = (GeometryNodeMeshCircleFillType)storage.fill_type; const int circle_segments = params.extract_input<int>("Vertices"); if (circle_segments < 3) { params.error_message_add(NodeWarningType::Info, TIP_("Vertices must be at least 3")); - return return_default(); + params.set_default_remaining_outputs(); + return; } const int side_segments = params.extract_input<int>("Side Segments"); if (side_segments < 1) { params.error_message_add(NodeWarningType::Info, TIP_("Side Segments must be at least 1")); - return return_default(); + params.set_default_remaining_outputs(); + return; } - const bool no_fill = fill_type == GEO_NODE_MESH_CIRCLE_FILL_NONE; + const bool no_fill = fill == GEO_NODE_MESH_CIRCLE_FILL_NONE; const int fill_segments = no_fill ? 1 : params.extract_input<int>("Fill Segments"); if (fill_segments < 1) { params.error_message_add(NodeWarningType::Info, TIP_("Fill Segments must be at least 1")); - return return_default(); + params.set_default_remaining_outputs(); + return; } const float radius_top = params.extract_input<float>("Radius Top"); @@ -848,7 +845,7 @@ static void geo_node_mesh_primitive_cone_exec(GeoNodeExecParams params) circle_segments, side_segments, fill_segments, - fill_type, + fill, attribute_outputs); /* Transform the mesh so that the base of the cone is at the origin. */ @@ -874,19 +871,21 @@ static void geo_node_mesh_primitive_cone_exec(GeoNodeExecParams params) params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_primitive_cone_cc void register_node_type_geo_mesh_primitive_cone() { + namespace file_ns = blender::nodes::node_geo_mesh_primitive_cone_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CONE, "Cone", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_mesh_primitive_cone_init); - node_type_update(&ntype, blender::nodes::geo_node_mesh_primitive_cone_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeGeometryMeshCone", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_cone_exec; - ntype.draw_buttons = blender::nodes::geo_node_mesh_primitive_cone_layout; - ntype.declare = blender::nodes::geo_node_mesh_primitive_cone_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc index b5903f7b71e..2542542c919 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc @@ -24,31 +24,6 @@ namespace blender::nodes { -static void geo_node_mesh_primitive_cube_declare(NodeDeclarationBuilder &b) -{ - b.add_input<decl::Vector>(N_("Size")) - .default_value(float3(1)) - .min(0.0f) - .subtype(PROP_TRANSLATION) - .description(N_("Side length along each axis")); - b.add_input<decl::Int>(N_("Vertices X")) - .default_value(2) - .min(2) - .max(1000) - .description(N_("Number of vertices for the X side of the shape")); - b.add_input<decl::Int>(N_("Vertices Y")) - .default_value(2) - .min(2) - .max(1000) - .description(N_("Number of vertices for the Y side of the shape")); - b.add_input<decl::Int>(N_("Vertices Z")) - .default_value(2) - .min(2) - .max(1000) - .description(N_("Number of vertices for the Z side of the shape")); - b.add_output<decl::Geometry>(N_("Mesh")); -} - struct CuboidConfig { float3 size; int verts_x; @@ -102,23 +77,37 @@ static void calculate_vertices(const CuboidConfig &config, MutableSpan<MVert> ve int vert_index = 0; - /* Though looping over all possible coordinates inside the cube only to skip them may be slow, - * the alternative is similar complexity to below in the poly index calculation. If this loop - * becomes a problem in the future it could be optimized, though only after proper performance - * testing. */ for (const int z : IndexRange(config.verts_z)) { - for (const int y : IndexRange(config.verts_y)) { - for (const int x : IndexRange(config.verts_x)) { - /* Only plot vertices on the surface of the cuboid. */ - if (ELEM(z, 0, config.edges_z) || ELEM(x, 0, config.edges_x) || - ELEM(y, 0, config.edges_y)) { - + if (ELEM(z, 0, config.edges_z)) { + /* Fill bottom and top. */ + const float z_pos = z_bottom + z_delta * z; + for (const int y : IndexRange(config.verts_y)) { + const float y_pos = y_front + y_delta * y; + for (const int x : IndexRange(config.verts_x)) { const float x_pos = x_left + x_delta * x; + copy_v3_v3(verts[vert_index++].co, float3(x_pos, y_pos, z_pos)); + } + } + } + else { + for (const int y : IndexRange(config.verts_y)) { + if (ELEM(y, 0, config.edges_y)) { + /* Fill y-sides. */ const float y_pos = y_front + y_delta * y; const float z_pos = z_bottom + z_delta * z; - copy_v3_v3(verts[vert_index].co, float3(x_pos, y_pos, z_pos)); - - vert_index++; + for (const int x : IndexRange(config.verts_x)) { + const float x_pos = x_left + x_delta * x; + copy_v3_v3(verts[vert_index++].co, float3(x_pos, y_pos, z_pos)); + } + } + else { + /* Fill x-sides. */ + const float x_pos = x_left; + const float y_pos = y_front + y_delta * y; + const float z_pos = z_bottom + z_delta * z; + copy_v3_v3(verts[vert_index++].co, float3(x_pos, y_pos, z_pos)); + const float x_pos2 = x_left + x_delta * config.edges_x; + copy_v3_v3(verts[vert_index++].co, float3(x_pos2, y_pos, z_pos)); } } } @@ -439,6 +428,35 @@ Mesh *create_cuboid_mesh(const float3 size, return mesh; } +} // namespace blender::nodes + +namespace blender::nodes::node_geo_mesh_primitive_cube_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Vector>(N_("Size")) + .default_value(float3(1)) + .min(0.0f) + .subtype(PROP_TRANSLATION) + .description(N_("Side length along each axis")); + b.add_input<decl::Int>(N_("Vertices X")) + .default_value(2) + .min(2) + .max(1000) + .description(N_("Number of vertices for the X side of the shape")); + b.add_input<decl::Int>(N_("Vertices Y")) + .default_value(2) + .min(2) + .max(1000) + .description(N_("Number of vertices for the Y side of the shape")); + b.add_input<decl::Int>(N_("Vertices Z")) + .default_value(2) + .min(2) + .max(1000) + .description(N_("Number of vertices for the Z side of the shape")); + b.add_output<decl::Geometry>(N_("Mesh")); +} + static Mesh *create_cube_mesh(const float3 size, const int verts_x, const int verts_y, @@ -484,7 +502,7 @@ static Mesh *create_cube_mesh(const float3 size, return create_cuboid_mesh(size, verts_x, verts_y, verts_z); } -static void geo_node_mesh_primitive_cube_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const float3 size = params.extract_input<float3>("Size"); const int verts_x = params.extract_input<int>("Vertices X"); @@ -492,7 +510,7 @@ static void geo_node_mesh_primitive_cube_exec(GeoNodeExecParams params) const int verts_z = params.extract_input<int>("Vertices Z"); if (verts_x < 1 || verts_y < 1 || verts_z < 1) { params.error_message_add(NodeWarningType::Info, TIP_("Vertices must be at least 1")); - params.set_output("Mesh", GeometrySet()); + params.set_default_remaining_outputs(); return; } @@ -501,14 +519,16 @@ static void geo_node_mesh_primitive_cube_exec(GeoNodeExecParams params) params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_primitive_cube_cc void register_node_type_geo_mesh_primitive_cube() { + namespace file_ns = blender::nodes::node_geo_mesh_primitive_cube_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CUBE, "Cube", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_mesh_primitive_cube_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_cube_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc index a2ac46190b3..b8d2ed3be92 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 @@ -25,9 +25,11 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_mesh_primitive_cylinder_cc { -static void geo_node_mesh_primitive_cylinder_declare(NodeDeclarationBuilder &b) +NODE_STORAGE_FUNCS(NodeGeometryMeshCylinder) + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Int>(N_("Vertices")) .default_value(32) @@ -60,16 +62,14 @@ static void geo_node_mesh_primitive_cylinder_declare(NodeDeclarationBuilder &b) b.add_output<decl::Bool>(N_("Bottom")).field_source(); } -static void geo_node_mesh_primitive_cylinder_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE); } -static void geo_node_mesh_primitive_cylinder_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryMeshCylinder *node_storage = (NodeGeometryMeshCylinder *)MEM_callocN( sizeof(NodeGeometryMeshCylinder), __func__); @@ -79,53 +79,45 @@ static void geo_node_mesh_primitive_cylinder_init(bNodeTree *UNUSED(ntree), bNod node->storage = node_storage; } -static void geo_node_mesh_primitive_cylinder_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { bNodeSocket *vertices_socket = (bNodeSocket *)node->inputs.first; bNodeSocket *rings_socket = vertices_socket->next; bNodeSocket *fill_subdiv_socket = rings_socket->next; - const NodeGeometryMeshCone &storage = *(const NodeGeometryMeshCone *)node->storage; - const GeometryNodeMeshCircleFillType fill_type = - static_cast<const GeometryNodeMeshCircleFillType>(storage.fill_type); - const bool has_fill = fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE; + const NodeGeometryMeshCylinder &storage = node_storage(*node); + const GeometryNodeMeshCircleFillType fill = (GeometryNodeMeshCircleFillType)storage.fill_type; + const bool has_fill = fill != GEO_NODE_MESH_CIRCLE_FILL_NONE; nodeSetSocketAvailability(ntree, fill_subdiv_socket, has_fill); } -static void geo_node_mesh_primitive_cylinder_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { - const bNode &node = params.node(); - const NodeGeometryMeshCylinder &storage = *(const NodeGeometryMeshCylinder *)node.storage; - - const GeometryNodeMeshCircleFillType fill_type = (const GeometryNodeMeshCircleFillType) - storage.fill_type; - - auto return_default = [&]() { - params.set_output("Top", fn::make_constant_field<bool>(false)); - params.set_output("Bottom", fn::make_constant_field<bool>(false)); - params.set_output("Side", fn::make_constant_field<bool>(false)); - params.set_output("Mesh", GeometrySet()); - }; + const NodeGeometryMeshCylinder &storage = node_storage(params.node()); + const GeometryNodeMeshCircleFillType fill = (GeometryNodeMeshCircleFillType)storage.fill_type; const float radius = params.extract_input<float>("Radius"); const float depth = params.extract_input<float>("Depth"); const int circle_segments = params.extract_input<int>("Vertices"); if (circle_segments < 3) { params.error_message_add(NodeWarningType::Info, TIP_("Vertices must be at least 3")); - return return_default(); + params.set_default_remaining_outputs(); + return; } const int side_segments = params.extract_input<int>("Side Segments"); if (side_segments < 1) { params.error_message_add(NodeWarningType::Info, TIP_("Side Segments must be at least 1")); - return return_default(); + params.set_default_remaining_outputs(); + return; } - const bool no_fill = fill_type == GEO_NODE_MESH_CIRCLE_FILL_NONE; + const bool no_fill = fill == GEO_NODE_MESH_CIRCLE_FILL_NONE; const int fill_segments = no_fill ? 1 : params.extract_input<int>("Fill Segments"); if (fill_segments < 1) { params.error_message_add(NodeWarningType::Info, TIP_("Fill Segments must be at least 1")); - return return_default(); + params.set_default_remaining_outputs(); + return; } ConeAttributeOutputs attribute_outputs; @@ -146,7 +138,7 @@ static void geo_node_mesh_primitive_cylinder_exec(GeoNodeExecParams params) circle_segments, side_segments, fill_segments, - fill_type, + fill, attribute_outputs); if (attribute_outputs.top_id) { @@ -169,18 +161,20 @@ static void geo_node_mesh_primitive_cylinder_exec(GeoNodeExecParams params) params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_primitive_cylinder_cc void register_node_type_geo_mesh_primitive_cylinder() { + namespace file_ns = blender::nodes::node_geo_mesh_primitive_cylinder_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CYLINDER, "Cylinder", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_mesh_primitive_cylinder_init); - node_type_update(&ntype, blender::nodes::geo_node_mesh_primitive_cylinder_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeGeometryMeshCylinder", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_mesh_primitive_cylinder_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_cylinder_exec; - ntype.draw_buttons = blender::nodes::geo_node_mesh_primitive_cylinder_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc index 73c679e18f8..77634a03af6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc @@ -27,31 +27,6 @@ namespace blender::nodes { -static void geo_node_mesh_primitive_grid_declare(NodeDeclarationBuilder &b) -{ - b.add_input<decl::Float>(N_("Size X")) - .default_value(1.0f) - .min(0.0f) - .subtype(PROP_DISTANCE) - .description(N_("Side length of the plane in the X direction")); - b.add_input<decl::Float>(N_("Size Y")) - .default_value(1.0f) - .min(0.0f) - .subtype(PROP_DISTANCE) - .description(N_("Side length of the plane in the Y direction")); - b.add_input<decl::Int>(N_("Vertices X")) - .default_value(3) - .min(2) - .max(1000) - .description(N_("Number of vertices in the X direction")); - b.add_input<decl::Int>(N_("Vertices Y")) - .default_value(3) - .min(2) - .max(1000) - .description(N_("Number of vertices in the Y direction")); - b.add_output<decl::Geometry>(N_("Mesh")); -} - static void calculate_uvs( Mesh *mesh, Span<MVert> verts, Span<MLoop> loops, const float size_x, const float size_y) { @@ -169,14 +144,43 @@ Mesh *create_grid_mesh(const int verts_x, return mesh; } -static void geo_node_mesh_primitive_grid_exec(GeoNodeExecParams params) +} // namespace blender::nodes + +namespace blender::nodes::node_geo_mesh_primitive_grid_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Float>(N_("Size X")) + .default_value(1.0f) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("Side length of the plane in the X direction")); + b.add_input<decl::Float>(N_("Size Y")) + .default_value(1.0f) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("Side length of the plane in the Y direction")); + b.add_input<decl::Int>(N_("Vertices X")) + .default_value(3) + .min(2) + .max(1000) + .description(N_("Number of vertices in the X direction")); + b.add_input<decl::Int>(N_("Vertices Y")) + .default_value(3) + .min(2) + .max(1000) + .description(N_("Number of vertices in the Y direction")); + b.add_output<decl::Geometry>(N_("Mesh")); +} + +static void node_geo_exec(GeoNodeExecParams params) { const float size_x = params.extract_input<float>("Size X"); const float size_y = params.extract_input<float>("Size Y"); const int verts_x = params.extract_input<int>("Vertices X"); const int verts_y = params.extract_input<int>("Vertices Y"); if (verts_x < 1 || verts_y < 1) { - params.set_output("Mesh", GeometrySet()); + params.set_default_remaining_outputs(); return; } @@ -187,14 +191,16 @@ static void geo_node_mesh_primitive_grid_exec(GeoNodeExecParams params) params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_primitive_grid_cc void register_node_type_geo_mesh_primitive_grid() { + namespace file_ns = blender::nodes::node_geo_mesh_primitive_grid_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_GRID, "Grid", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_mesh_primitive_grid_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_grid_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc index e4bf5e31dbf..5f483a95063 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 @@ -24,9 +24,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_mesh_primitive_ico_sphere_cc { -static void geo_node_mesh_primitive_ico_sphere_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Float>(N_("Radius")) .default_value(1.0f) @@ -69,7 +69,7 @@ static Mesh *create_ico_sphere_mesh(const int subdivisions, const float radius) return mesh; } -static void geo_node_mesh_primitive_ico_sphere_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const int subdivisions = std::min(params.extract_input<int>("Subdivisions"), 10); const float radius = params.extract_input<float>("Radius"); @@ -78,15 +78,17 @@ static void geo_node_mesh_primitive_ico_sphere_exec(GeoNodeExecParams params) params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_primitive_ico_sphere_cc void register_node_type_geo_mesh_primitive_ico_sphere() { + namespace file_ns = blender::nodes::node_geo_mesh_primitive_ico_sphere_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, "Ico Sphere", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_mesh_primitive_ico_sphere_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_ico_sphere_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc index 1a92be1c05d..9a87c040bdf 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 @@ -23,11 +23,15 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "NOD_socket_search_link.hh" + #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_mesh_primitive_line_cc { + +NODE_STORAGE_FUNCS(NodeGeometryMeshLine) -static void geo_node_mesh_primitive_line_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Int>(N_("Count")) .default_value(10) @@ -51,9 +55,7 @@ static void geo_node_mesh_primitive_line_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Mesh")); } -static void geo_node_mesh_primitive_line_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -63,7 +65,7 @@ static void geo_node_mesh_primitive_line_layout(uiLayout *layout, } } -static void geo_node_mesh_primitive_line_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryMeshLine *node_storage = (NodeGeometryMeshLine *)MEM_callocN( sizeof(NodeGeometryMeshLine), __func__); @@ -74,16 +76,16 @@ static void geo_node_mesh_primitive_line_init(bNodeTree *UNUSED(ntree), bNode *n node->storage = node_storage; } -static void geo_node_mesh_primitive_line_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { bNodeSocket *count_socket = (bNodeSocket *)node->inputs.first; bNodeSocket *resolution_socket = count_socket->next; bNodeSocket *start_socket = resolution_socket->next; bNodeSocket *end_and_offset_socket = start_socket->next; - const NodeGeometryMeshLine &storage = *(const NodeGeometryMeshLine *)node->storage; - const GeometryNodeMeshLineMode mode = (const GeometryNodeMeshLineMode)storage.mode; - const GeometryNodeMeshLineCountMode count_mode = (const GeometryNodeMeshLineCountMode) + const NodeGeometryMeshLine &storage = node_storage(*node); + const GeometryNodeMeshLineMode mode = (GeometryNodeMeshLineMode)storage.mode; + const GeometryNodeMeshLineCountMode count_mode = (GeometryNodeMeshLineCountMode) storage.count_mode; node_sock_label(end_and_offset_socket, @@ -100,44 +102,48 @@ static void geo_node_mesh_primitive_line_update(bNodeTree *ntree, bNode *node) count_mode == GEO_NODE_MESH_LINE_COUNT_TOTAL); } -static void fill_edge_data(MutableSpan<MEdge> edges) +static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) { - for (const int i : edges.index_range()) { - edges[i].v1 = i; - edges[i].v2 = i + 1; - edges[i].flag |= ME_LOOSEEDGE; + const NodeDeclaration &declaration = *params.node_type().fixed_declaration; + if (params.in_out() == SOCK_OUT) { + search_link_ops_for_declarations(params, declaration.outputs()); + return; } -} - -Mesh *create_line_mesh(const float3 start, const float3 delta, const int count) -{ - if (count < 1) { - return nullptr; - } - - Mesh *mesh = BKE_mesh_new_nomain(count, count - 1, 0, 0, 0); - BKE_id_material_eval_ensure_default_slot(&mesh->id); - MutableSpan<MVert> verts{mesh->mvert, mesh->totvert}; - MutableSpan<MEdge> edges{mesh->medge, mesh->totedge}; - - short normal[3]; - normal_float_to_short_v3(normal, delta.normalized()); - - for (const int i : verts.index_range()) { - copy_v3_v3(verts[i].co, start + delta * i); - copy_v3_v3_short(verts[i].no, normal); + else if (params.node_tree().typeinfo->validate_link( + static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_FLOAT)) { + params.add_item(IFACE_("Count"), [](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("GeometryNodeMeshLine"); + node_storage(node).mode = GEO_NODE_MESH_LINE_MODE_OFFSET; + params.connect_available_socket(node, "Count"); + }); + params.add_item(IFACE_("Resolution"), [](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("GeometryNodeMeshLine"); + node_storage(node).mode = GEO_NODE_MESH_LINE_MODE_OFFSET; + node_storage(node).count_mode = GEO_NODE_MESH_LINE_COUNT_RESOLUTION; + params.connect_available_socket(node, "Resolution"); + }); + params.add_item(IFACE_("Start Location"), [](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("GeometryNodeMeshLine"); + params.connect_available_socket(node, "Start Location"); + }); + params.add_item(IFACE_("Offset"), [](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("GeometryNodeMeshLine"); + params.connect_available_socket(node, "Offset"); + }); + /* The last socket is reused in end points mode. */ + params.add_item(IFACE_("End Location"), [](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("GeometryNodeMeshLine"); + node_storage(node).mode = GEO_NODE_MESH_LINE_MODE_END_POINTS; + params.connect_available_socket(node, "Offset"); + }); } - - fill_edge_data(edges); - - return mesh; } -static void geo_node_mesh_primitive_line_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { - const NodeGeometryMeshLine &storage = *(const NodeGeometryMeshLine *)params.node().storage; - const GeometryNodeMeshLineMode mode = (const GeometryNodeMeshLineMode)storage.mode; - const GeometryNodeMeshLineCountMode count_mode = (const GeometryNodeMeshLineCountMode) + const NodeGeometryMeshLine &storage = node_storage(params.node()); + const GeometryNodeMeshLineMode mode = (GeometryNodeMeshLineMode)storage.mode; + const GeometryNodeMeshLineCountMode count_mode = (GeometryNodeMeshLineCountMode) storage.count_mode; Mesh *mesh = nullptr; @@ -174,19 +180,59 @@ static void geo_node_mesh_primitive_line_exec(GeoNodeExecParams params) params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); } +} // namespace blender::nodes::node_geo_mesh_primitive_line_cc + +namespace blender::nodes { + +static void fill_edge_data(MutableSpan<MEdge> edges) +{ + for (const int i : edges.index_range()) { + edges[i].v1 = i; + edges[i].v2 = i + 1; + edges[i].flag |= ME_LOOSEEDGE; + } +} + +Mesh *create_line_mesh(const float3 start, const float3 delta, const int count) +{ + if (count < 1) { + return nullptr; + } + + Mesh *mesh = BKE_mesh_new_nomain(count, count - 1, 0, 0, 0); + BKE_id_material_eval_ensure_default_slot(&mesh->id); + MutableSpan<MVert> verts{mesh->mvert, mesh->totvert}; + MutableSpan<MEdge> edges{mesh->medge, mesh->totedge}; + + short normal[3]; + normal_float_to_short_v3(normal, delta.normalized()); + + for (const int i : verts.index_range()) { + copy_v3_v3(verts[i].co, start + delta * i); + copy_v3_v3_short(verts[i].no, normal); + } + + fill_edge_data(edges); + + return mesh; +} + } // namespace blender::nodes void register_node_type_geo_mesh_primitive_line() { + namespace file_ns = blender::nodes::node_geo_mesh_primitive_line_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_LINE, "Mesh Line", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_mesh_primitive_line_declare; - node_type_init(&ntype, blender::nodes::geo_node_mesh_primitive_line_init); - node_type_update(&ntype, blender::nodes::geo_node_mesh_primitive_line_update); + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeGeometryMeshLine", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_line_exec; - ntype.draw_buttons = blender::nodes::geo_node_mesh_primitive_line_layout; + 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_mesh_primitive_uv_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc index 3197a94c27b..ce2e0923a30 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 @@ -25,9 +25,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_mesh_primitive_uv_sphere_cc { -static void geo_node_mesh_primitive_uv_shpere_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Int>(N_("Segments")) .default_value(32) @@ -292,7 +292,7 @@ static Mesh *create_uv_sphere_mesh(const float radius, const int segments, const return mesh; } -static void geo_node_mesh_primitive_uv_sphere_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const int segments_num = params.extract_input<int>("Segments"); const int rings_num = params.extract_input<int>("Rings"); @@ -303,7 +303,7 @@ static void geo_node_mesh_primitive_uv_sphere_exec(GeoNodeExecParams params) if (rings_num < 3) { params.error_message_add(NodeWarningType::Info, TIP_("Rings must be at least 3")); } - params.set_output("Mesh", GeometrySet()); + params.set_default_remaining_outputs(); return; } @@ -313,15 +313,17 @@ static void geo_node_mesh_primitive_uv_sphere_exec(GeoNodeExecParams params) params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_primitive_uv_sphere_cc void register_node_type_geo_mesh_primitive_uv_sphere() { + namespace file_ns = blender::nodes::node_geo_mesh_primitive_uv_sphere_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, "UV Sphere", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_mesh_primitive_uv_shpere_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_uv_sphere_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc index d99c0c851a8..1ec9808044f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc @@ -23,9 +23,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_mesh_subdivide_cc { -static void geo_node_mesh_subdivide_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH); b.add_input<decl::Int>(N_("Level")).default_value(1).min(0).max(6); @@ -72,14 +72,14 @@ static void geometry_set_mesh_subdivide(GeometrySet &geometry_set, const int lev BKE_subdiv_free(subdiv); } -static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); #ifndef WITH_OPENSUBDIV params.error_message_add(NodeWarningType::Error, TIP_("Disabled, Blender was compiled without OpenSubdiv")); - params.set_output("Mesh", std::move(geometry_set)); + params.set_default_remaining_outputs(); return; #endif @@ -97,14 +97,16 @@ static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params) params.set_output("Mesh", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_subdivide_cc void register_node_type_geo_mesh_subdivide() { + namespace file_ns = blender::nodes::node_geo_mesh_subdivide_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE_MESH, "Subdivide Mesh", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_mesh_subdivide_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_subdivide_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc index 11865c635b8..90f0af75788 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc @@ -18,16 +18,16 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_mesh_to_curve_cc { -static void geo_node_legacy_mesh_to_curve_declare(NodeDeclarationBuilder &b) +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).hide_value().supports_field(); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); @@ -56,14 +56,16 @@ static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params) params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_to_curve_cc void register_node_type_geo_mesh_to_curve() { + namespace file_ns = blender::nodes::node_geo_mesh_to_curve_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_MESH_TO_CURVE, "Mesh to Curve", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_legacy_mesh_to_curve_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_legacy_mesh_to_curve_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc index a37e3e34777..77314341fec 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 @@ -26,9 +26,11 @@ using blender::Array; -namespace blender::nodes { +namespace blender::nodes::node_geo_mesh_to_points_cc { -static void geo_node_mesh_to_points_declare(NodeDeclarationBuilder &b) +NODE_STORAGE_FUNCS(NodeGeometryMeshToPoints) + +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(); @@ -41,12 +43,12 @@ static void geo_node_mesh_to_points_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Points")); } -static void geo_node_mesh_to_points_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); } -static void geo_node_mesh_to_points_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryMeshToPoints *data = (NodeGeometryMeshToPoints *)MEM_callocN( sizeof(NodeGeometryMeshToPoints), __func__); @@ -81,10 +83,15 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set, geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES}); return; } - fn::FieldEvaluator selection_evaluator{field_context, domain_size}; - selection_evaluator.add(selection_field); - selection_evaluator.evaluate(); - const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0); + fn::FieldEvaluator evaluator{field_context, domain_size}; + evaluator.set_selection(selection_field); + /* Evaluating directly into the point cloud doesn't work because we are not using the full + * "min_array_size" array but compressing the selected elements into the final array with no + * gaps. */ + evaluator.add(position_field); + evaluator.add(radius_field); + evaluator.evaluate(); + const IndexMask selection = evaluator.get_evaluated_selection_as_mask(); PointCloud *pointcloud = BKE_pointcloud_new_nomain(selection.size()); uninitialized_fill_n(pointcloud->radius, pointcloud->totpoint, 0.05f); @@ -92,13 +99,6 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set, PointCloudComponent &point_component = geometry_set.get_component_for_write<PointCloudComponent>(); - /* Evaluating directly into the point cloud doesn't work because we are not using the full - * "min_array_size" array but compressing the selected elements into the final array with no - * gaps. */ - fn::FieldEvaluator evaluator{field_context, &selection}; - evaluator.add(position_field); - evaluator.add(radius_field); - evaluator.evaluate(); copy_attribute_to_points(evaluator.get_evaluated<float3>(0), selection, {(float3 *)pointcloud->co, pointcloud->totpoint}); @@ -129,7 +129,7 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set, geometry_set.keep_only({GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_INSTANCES}); } -static void geo_node_mesh_to_points_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); Field<float3> position = params.extract_input<Field<float3>>("Position"); @@ -144,8 +144,7 @@ static void geo_node_mesh_to_points_exec(GeoNodeExecParams params) FieldOperation(max_zero_fn, {std::move(radius)})); Field<float> positive_radius(std::move(max_zero_op), 0); - const NodeGeometryMeshToPoints &storage = - *(const NodeGeometryMeshToPoints *)params.node().storage; + const NodeGeometryMeshToPoints &storage = node_storage(params.node()); const GeometryNodeMeshToPointsMode mode = (GeometryNodeMeshToPointsMode)storage.mode; geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { @@ -172,17 +171,19 @@ static void geo_node_mesh_to_points_exec(GeoNodeExecParams params) params.set_output("Points", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_to_points_cc void register_node_type_geo_mesh_to_points() { + namespace file_ns = blender::nodes::node_geo_mesh_to_points_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_MESH_TO_POINTS, "Mesh to Points", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_mesh_to_points_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_to_points_exec; - node_type_init(&ntype, blender::nodes::geo_node_mesh_to_points_init); - ntype.draw_buttons = blender::nodes::geo_node_mesh_to_points_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); + ntype.draw_buttons = file_ns::node_layout; node_type_storage( &ntype, "NodeGeometryMeshToPoints", node_free_standard_storage, node_copy_standard_storage); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc index bb8e5f7e29b..38c3b9cbcd9 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc @@ -21,9 +21,11 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_object_info_cc { -static void geo_node_object_info_declare(NodeDeclarationBuilder &b) +NODE_STORAGE_FUNCS(NodeGeometryObjectInfo) + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Object>(N_("Object")).hide_label(); b.add_input<decl::Bool>(N_("As Instance")) @@ -35,31 +37,22 @@ static void geo_node_object_info_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_object_info_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "transform_space", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_object_info_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { - const bNode &bnode = params.node(); - NodeGeometryObjectInfo *node_storage = (NodeGeometryObjectInfo *)bnode.storage; - const bool transform_space_relative = (node_storage->transform_space == + const NodeGeometryObjectInfo &storage = node_storage(params.node()); + const bool transform_space_relative = (storage.transform_space == GEO_NODE_TRANSFORM_SPACE_RELATIVE); - auto default_transform = [&]() { - params.set_output("Location", float3(0)); - params.set_output("Rotation", float3(0)); - params.set_output("Scale", float3(0)); - }; - auto default_geometry = [&]() { params.set_output("Geometry", GeometrySet()); }; - Object *object = params.get_input<Object *>("Object"); const Object *self_object = params.self_object(); if (object == nullptr) { - default_transform(); - default_geometry(); + params.set_default_remaining_outputs(); return; } @@ -81,7 +74,7 @@ static void geo_node_object_info_exec(GeoNodeExecParams params) if (object == self_object) { params.error_message_add(NodeWarningType::Error, TIP_("Geometry cannot be retrieved from the modifier object")); - default_geometry(); + params.set_default_remaining_outputs(); return; } @@ -107,7 +100,7 @@ static void geo_node_object_info_exec(GeoNodeExecParams params) } } -static void geo_node_object_info_node_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryObjectInfo *data = (NodeGeometryObjectInfo *)MEM_callocN( sizeof(NodeGeometryObjectInfo), __func__); @@ -115,18 +108,20 @@ static void geo_node_object_info_node_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_object_info_cc void register_node_type_geo_object_info() { + namespace file_ns = blender::nodes::node_geo_object_info_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_OBJECT_INFO, "Object Info", NODE_CLASS_INPUT, 0); - node_type_init(&ntype, blender::nodes::geo_node_object_info_node_init); + node_type_init(&ntype, file_ns::node_node_init); node_type_storage( &ntype, "NodeGeometryObjectInfo", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_object_info_exec; - ntype.draw_buttons = blender::nodes::geo_node_object_info_layout; - ntype.declare = blender::nodes::geo_node_object_info_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc index 5a6a3b25a45..5510773eabd 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc @@ -21,11 +21,11 @@ #include "node_geometry_util.hh" -using blender::Array; +namespace blender::nodes::node_geo_points_to_vertices_cc { -namespace blender::nodes { +using blender::Array; -static void geo_node_points_to_vertices_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Points")).supported_type(GEO_COMPONENT_TYPE_POINT_CLOUD); b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value(); @@ -92,7 +92,7 @@ static void geometry_set_points_to_vertices(GeometrySet &geometry_set, geometry_set.keep_only({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_INSTANCES}); } -static void geo_node_points_to_vertices_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Points"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -104,15 +104,17 @@ static void geo_node_points_to_vertices_exec(GeoNodeExecParams params) params.set_output("Mesh", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_points_to_vertices_cc void register_node_type_geo_points_to_vertices() { + namespace file_ns = blender::nodes::node_geo_points_to_vertices_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_POINTS_TO_VERTICES, "Points to Vertices", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_points_to_vertices_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_points_to_vertices_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc index 31c16cb95e0..744cce6d445 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 @@ -28,14 +28,27 @@ #include "UI_interface.h" #include "UI_resources.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_points_to_volume_cc { -static void geo_node_points_to_volume_declare(NodeDeclarationBuilder &b) +NODE_STORAGE_FUNCS(NodeGeometryPointsToVolume) + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Points")); b.add_input<decl::Float>(N_("Density")).default_value(1.0f).min(0.0f); - b.add_input<decl::Float>(N_("Voxel Size")).default_value(0.3f).min(0.01f).subtype(PROP_DISTANCE); - b.add_input<decl::Float>(N_("Voxel Amount")).default_value(64.0f).min(0.0f); + b.add_input<decl::Float>(N_("Voxel Size")) + .default_value(0.3f) + .min(0.01f) + .subtype(PROP_DISTANCE) + .make_available([](bNode &node) { + node_storage(node).resolution_mode = GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE; + }); + b.add_input<decl::Float>(N_("Voxel Amount")) + .default_value(64.0f) + .min(0.0f) + .make_available([](bNode &node) { + node_storage(node).resolution_mode = GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT; + }); b.add_input<decl::Float>(N_("Radius")) .default_value(0.5f) .min(0.0f) @@ -44,16 +57,14 @@ static void geo_node_points_to_volume_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Volume")); } -static void geo_node_points_to_volume_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); uiItemR(layout, ptr, "resolution_mode", 0, IFACE_("Resolution"), ICON_NONE); } -static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)MEM_callocN( sizeof(NodeGeometryPointsToVolume), __func__); @@ -61,18 +72,18 @@ static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node node->storage = data; } -static void geo_node_points_to_volume_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { - NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)node->storage; + const NodeGeometryPointsToVolume &storage = 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 == + storage.resolution_mode == GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT); nodeSetSocketAvailability(ntree, voxel_size_socket, - data->resolution_mode == + storage.resolution_mode == GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE); } @@ -136,8 +147,7 @@ static float compute_voxel_size(const GeoNodeExecParams ¶ms, Span<float3> positions, const float radius) { - const NodeGeometryPointsToVolume &storage = - *(const NodeGeometryPointsToVolume *)params.node().storage; + const NodeGeometryPointsToVolume &storage = node_storage(params.node()); if (storage.resolution_mode == GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE) { return params.get_input<float>("Voxel Size"); @@ -236,7 +246,7 @@ static void initialize_volume_component_from_points(GeoNodeExecParams ¶ms, } #endif -static void geo_node_points_to_volume_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Points"); @@ -248,14 +258,16 @@ static void geo_node_points_to_volume_exec(GeoNodeExecParams params) #else params.error_message_add(NodeWarningType::Error, TIP_("Disabled, Blender was compiled without OpenVDB")); - params.set_output("Volume", GeometrySet()); + params.set_default_remaining_outputs(); #endif } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_points_to_volume_cc void register_node_type_geo_points_to_volume() { + namespace file_ns = blender::nodes::node_geo_points_to_volume_cc; + static bNodeType ntype; geo_node_type_base( @@ -265,10 +277,10 @@ void register_node_type_geo_points_to_volume() node_free_standard_storage, node_copy_standard_storage); node_type_size(&ntype, 170, 120, 700); - node_type_init(&ntype, blender::nodes::geo_node_points_to_volume_init); - node_type_update(&ntype, blender::nodes::geo_node_points_to_volume_update); - ntype.declare = blender::nodes::geo_node_points_to_volume_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_points_to_volume_exec; - ntype.draw_buttons = blender::nodes::geo_node_points_to_volume_layout; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_proximity.cc b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc index c05476b982b..aa3383e68be 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_proximity.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc @@ -27,9 +27,11 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_proximity_cc { -static void geo_node_proximity_declare(NodeDeclarationBuilder &b) +NODE_STORAGE_FUNCS(NodeGeometryProximity) + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Target")) .only_realized_data() @@ -39,7 +41,7 @@ static void geo_node_proximity_declare(NodeDeclarationBuilder &b) b.add_output<decl::Float>(N_("Distance")).dependent_field(); } -static void geo_node_proximity_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "target_element", 0, "", ICON_NONE); } @@ -206,21 +208,17 @@ class ProximityFunction : public fn::MultiFunction { } }; -static void geo_node_proximity_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set_target = params.extract_input<GeometrySet>("Target"); geometry_set_target.ensure_owns_direct_data(); - auto return_default = [&]() { - params.set_output("Position", fn::make_constant_field<float3>({0.0f, 0.0f, 0.0f})); - params.set_output("Distance", fn::make_constant_field<float>(0.0f)); - }; - if (!geometry_set_target.has_mesh() && !geometry_set_target.has_pointcloud()) { - return return_default(); + params.set_default_remaining_outputs(); + return; } - const NodeGeometryProximity &storage = *(const NodeGeometryProximity *)params.node().storage; + const NodeGeometryProximity &storage = node_storage(params.node()); Field<float3> position_field = params.extract_input<Field<float3>>("Source Position"); auto proximity_fn = std::make_unique<ProximityFunction>( @@ -233,18 +231,20 @@ static void geo_node_proximity_exec(GeoNodeExecParams params) params.set_output("Distance", Field<float>(proximity_op, 1)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_proximity_cc void register_node_type_geo_proximity() { + namespace file_ns = blender::nodes::node_geo_proximity_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_PROXIMITY, "Geometry Proximity", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_proximity_init); + node_type_init(&ntype, file_ns::geo_proximity_init); node_type_storage( &ntype, "NodeGeometryProximity", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_proximity_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_proximity_exec; - ntype.draw_buttons = blender::nodes::geo_node_proximity_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc index d422bf5a00a..d255fe482f6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc @@ -23,13 +23,17 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "NOD_socket_search_link.hh" + #include "node_geometry_util.hh" +namespace blender::nodes::node_geo_raycast_cc { + using namespace blender::bke::mesh_surface_sample; -namespace blender::nodes { +NODE_STORAGE_FUNCS(NodeGeometryRaycast) -static void geo_node_raycast_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Target Geometry")) .only_realized_data() @@ -63,13 +67,13 @@ static void geo_node_raycast_declare(NodeDeclarationBuilder &b) b.add_output<decl::Int>(N_("Attribute"), "Attribute_004").dependent_field({1, 2, 3, 4, 5, 6}); } -static void geo_node_raycast_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); uiItemR(layout, ptr, "mapping", 0, "", ICON_NONE); } -static void geo_node_raycast_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryRaycast *data = (NodeGeometryRaycast *)MEM_callocN(sizeof(NodeGeometryRaycast), __func__); @@ -78,10 +82,10 @@ static void geo_node_raycast_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_raycast_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { - const NodeGeometryRaycast &data = *(const NodeGeometryRaycast *)node->storage; - const CustomDataType data_type = static_cast<CustomDataType>(data.data_type); + const NodeGeometryRaycast &storage = node_storage(*node); + const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); bNodeSocket *socket_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 1); bNodeSocket *socket_float = socket_vector->next; @@ -108,6 +112,25 @@ static void geo_node_raycast_update(bNodeTree *ntree, bNode *node) nodeSetSocketAvailability(ntree, out_socket_int32, data_type == CD_PROP_INT32); } +static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) +{ + const NodeDeclaration &declaration = *params.node_type().fixed_declaration; + search_link_ops_for_declarations(params, declaration.inputs().take_front(1)); + search_link_ops_for_declarations(params, declaration.inputs().take_back(3)); + search_link_ops_for_declarations(params, declaration.outputs().take_front(4)); + + const std::optional<CustomDataType> 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 ¶ms) { + bNode &node = params.add_node("GeometryNodeRaycast"); + node_storage(node).data_type = *type; + params.update_and_connect_available_socket(node, "Attribute"); + }); + } +} + static eAttributeMapMode get_map_mode(GeometryNodeRaycastMapMode map_mode) { switch (map_mode) { @@ -205,10 +228,10 @@ class RaycastFunction : public fn::MultiFunction { std::unique_ptr<FieldEvaluator> target_evaluator_; const GVArray *target_data_ = nullptr; - /* Always evaluate the target domain data on the point domain. Eventually this could be - * exposed as an option or determined automatically from the field inputs in order to avoid - * losing information if the target field is on a different domain. */ - const AttributeDomain domain_ = ATTR_DOMAIN_POINT; + /* Always evaluate the target domain data on the face corner domain because it contains the most + * information. Eventually this could be exposed as an option or determined automatically from + * the field inputs for better performance. */ + const AttributeDomain domain_ = ATTR_DOMAIN_CORNER; fn::MFSignature signature_; @@ -375,35 +398,27 @@ static void output_attribute_field(GeoNodeExecParams ¶ms, GField field) } } -static void geo_node_raycast_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet target = params.extract_input<GeometrySet>("Target Geometry"); - const NodeGeometryRaycast &data = *(const NodeGeometryRaycast *)params.node().storage; - const GeometryNodeRaycastMapMode mapping = static_cast<GeometryNodeRaycastMapMode>(data.mapping); - const CustomDataType data_type = static_cast<CustomDataType>(data.data_type); - - auto return_default = [&]() { - params.set_output("Is Hit", fn::make_constant_field<bool>(false)); - params.set_output("Hit Position", fn::make_constant_field<float3>({0.0f, 0.0f, 0.0f})); - params.set_output("Hit Normal", fn::make_constant_field<float3>({0.0f, 0.0f, 0.0f})); - params.set_output("Hit Distance", fn::make_constant_field<float>(0.0f)); - attribute_math::convert_to_static_type(data_type, [&](auto dummy) { - using T = decltype(dummy); - output_attribute_field(params, fn::make_constant_field<T>(T())); - }); - }; + const NodeGeometryRaycast &storage = node_storage(params.node()); + const GeometryNodeRaycastMapMode mapping = (GeometryNodeRaycastMapMode)storage.mapping; + const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); if (target.is_empty()) { - return return_default(); + params.set_default_remaining_outputs(); + return; } if (!target.has_mesh()) { - return return_default(); + params.set_default_remaining_outputs(); + return; } if (target.get_mesh_for_read()->totpoly == 0) { params.error_message_add(NodeWarningType::Error, TIP_("The target mesh must have faces")); - return return_default(); + params.set_default_remaining_outputs(); + return; } GField field = get_input_attribute_field(params, data_type); @@ -426,20 +441,23 @@ static void geo_node_raycast_exec(GeoNodeExecParams params) } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_raycast_cc void register_node_type_geo_raycast() { + namespace file_ns = blender::nodes::node_geo_raycast_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY, 0); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); - node_type_init(&ntype, blender::nodes::geo_node_raycast_init); - node_type_update(&ntype, blender::nodes::geo_node_raycast_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeGeometryRaycast", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_raycast_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_raycast_exec; - ntype.draw_buttons = blender::nodes::geo_node_raycast_layout; + 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_realize_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc index 6c51c1f738f..fad35389823 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc @@ -16,33 +16,48 @@ #include "node_geometry_util.hh" +#include "GEO_realize_instances.hh" + #include "UI_interface.h" #include "UI_resources.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_realize_instances_cc { -static void geo_node_realize_instances_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_realize_instances_exec(GeoNodeExecParams params) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "legacy_behavior", 0, nullptr, ICON_NONE); +} + +static void node_geo_exec(GeoNodeExecParams params) { + const bool legacy_behavior = params.node().custom1 & GEO_NODE_REALIZE_INSTANCES_LEGACY_BEHAVIOR; + GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - geometry_set = bke::geometry_set_realize_instances(geometry_set); + geometry::RealizeInstancesOptions options; + options.keep_original_ids = legacy_behavior; + options.realize_instance_attributes = !legacy_behavior; + geometry_set = geometry::realize_instances(geometry_set, options); params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_realize_instances_cc void register_node_type_geo_realize_instances() { + namespace file_ns = blender::nodes::node_geo_realize_instances_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_REALIZE_INSTANCES, "Realize Instances", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_realize_instances_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_realize_instances_exec; + ntype.declare = file_ns::node_declare; + ntype.draw_buttons_ex = file_ns::node_layout; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc index c53eaa2ded9..335484c62b0 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc @@ -18,9 +18,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_rotate_instances_cc { -static void geo_node_rotate_instances_declare(NodeDeclarationBuilder &b) +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(); @@ -35,19 +35,17 @@ static void rotate_instances(GeoNodeExecParams ¶ms, InstancesComponent &inst GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE}; const int domain_size = instances_component.instances_amount(); - fn::FieldEvaluator selection_evaluator{field_context, domain_size}; - selection_evaluator.add(params.extract_input<Field<bool>>("Selection")); - selection_evaluator.evaluate(); - const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0); + fn::FieldEvaluator evaluator{field_context, domain_size}; + evaluator.set_selection(params.extract_input<Field<bool>>("Selection")); + evaluator.add(params.extract_input<Field<float3>>("Rotation")); + evaluator.add(params.extract_input<Field<float3>>("Pivot Point")); + evaluator.add(params.extract_input<Field<bool>>("Local Space")); + evaluator.evaluate(); - fn::FieldEvaluator transforms_evaluator{field_context, &selection}; - transforms_evaluator.add(params.extract_input<Field<float3>>("Rotation")); - transforms_evaluator.add(params.extract_input<Field<float3>>("Pivot Point")); - transforms_evaluator.add(params.extract_input<Field<bool>>("Local Space")); - transforms_evaluator.evaluate(); - const VArray<float3> &rotations = transforms_evaluator.get_evaluated<float3>(0); - const VArray<float3> &pivots = transforms_evaluator.get_evaluated<float3>(1); - const VArray<bool> &local_spaces = transforms_evaluator.get_evaluated<bool>(2); + const IndexMask selection = evaluator.get_evaluated_selection_as_mask(); + const VArray<float3> &rotations = evaluator.get_evaluated<float3>(0); + const VArray<float3> &pivots = evaluator.get_evaluated<float3>(1); + const VArray<bool> &local_spaces = evaluator.get_evaluated<bool>(2); MutableSpan<float4x4> instance_transforms = instances_component.instance_transforms(); @@ -96,7 +94,7 @@ static void rotate_instances(GeoNodeExecParams ¶ms, InstancesComponent &inst }); } -static void geo_node_rotate_instances_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances"); if (geometry_set.has_instances()) { @@ -106,15 +104,17 @@ static void geo_node_rotate_instances_exec(GeoNodeExecParams params) params.set_output("Instances", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_rotate_instances_cc void register_node_type_geo_rotate_instances() { + namespace file_ns = blender::nodes::node_geo_rotate_instances_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_ROTATE_INSTANCES, "Rotate Instances", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_rotate_instances_exec; - ntype.declare = blender::nodes::geo_node_rotate_instances_declare; + 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_scale_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc index fa2501515a9..1779ac8bff7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc @@ -18,9 +18,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_scale_instances_cc { -static void geo_node_scale_instances_declare(NodeDeclarationBuilder &b) +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(); @@ -37,19 +37,17 @@ static void scale_instances(GeoNodeExecParams ¶ms, InstancesComponent &insta { GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE}; - fn::FieldEvaluator selection_evaluator{field_context, instances_component.instances_amount()}; - selection_evaluator.add(params.extract_input<Field<bool>>("Selection")); - selection_evaluator.evaluate(); - const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0); + fn::FieldEvaluator evaluator{field_context, instances_component.instances_amount()}; + evaluator.set_selection(params.extract_input<Field<bool>>("Selection")); + evaluator.add(params.extract_input<Field<float3>>("Scale")); + evaluator.add(params.extract_input<Field<float3>>("Center")); + evaluator.add(params.extract_input<Field<bool>>("Local Space")); + evaluator.evaluate(); - fn::FieldEvaluator transforms_evaluator{field_context, &selection}; - transforms_evaluator.add(params.extract_input<Field<float3>>("Scale")); - transforms_evaluator.add(params.extract_input<Field<float3>>("Center")); - transforms_evaluator.add(params.extract_input<Field<bool>>("Local Space")); - transforms_evaluator.evaluate(); - const VArray<float3> &scales = transforms_evaluator.get_evaluated<float3>(0); - const VArray<float3> &pivots = transforms_evaluator.get_evaluated<float3>(1); - const VArray<bool> &local_spaces = transforms_evaluator.get_evaluated<bool>(2); + const IndexMask selection = evaluator.get_evaluated_selection_as_mask(); + const VArray<float3> &scales = evaluator.get_evaluated<float3>(0); + const VArray<float3> &pivots = evaluator.get_evaluated<float3>(1); + const VArray<bool> &local_spaces = evaluator.get_evaluated<bool>(2); MutableSpan<float4x4> instance_transforms = instances_component.instance_transforms(); @@ -75,7 +73,7 @@ static void scale_instances(GeoNodeExecParams ¶ms, InstancesComponent &insta }); } -static void geo_node_scale_instances_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances"); if (geometry_set.has_instances()) { @@ -85,14 +83,16 @@ static void geo_node_scale_instances_exec(GeoNodeExecParams params) params.set_output("Instances", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_scale_instances_cc void register_node_type_geo_scale_instances() { + namespace file_ns = blender::nodes::node_geo_scale_instances_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SCALE_INSTANCES, "Scale Instances", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_scale_instances_exec; - ntype.declare = blender::nodes::geo_node_scale_instances_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc index a16fb712b13..e4adfe6587d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_separate_components_cc { -static void geo_node_join_geometry_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_output<decl::Geometry>(N_("Mesh")); @@ -28,7 +28,7 @@ static void geo_node_join_geometry_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Instances")); } -static void geo_node_separate_components_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -61,15 +61,17 @@ static void geo_node_separate_components_exec(GeoNodeExecParams params) params.set_output("Instances", instances); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_separate_components_cc void register_node_type_geo_separate_components() { + namespace file_ns = blender::nodes::node_geo_separate_components_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_SEPARATE_COMPONENTS, "Separate Components", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_join_geometry_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_separate_components_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc index 28e214c0ccc..7f1cc1be421 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc @@ -19,9 +19,11 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_separate_geometry_cc { -static void geo_node_separate_geometry_declare(NodeDeclarationBuilder &b) +NODE_STORAGE_FUNCS(NodeGeometrySeparateGeometry) + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Bool>(N_("Selection")) @@ -35,14 +37,12 @@ static void geo_node_separate_geometry_declare(NodeDeclarationBuilder &b) .description(N_("The parts of the geometry not in the selection")); } -static void geo_node_separate_geometry_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "domain", 0, "", ICON_NONE); } -static void geo_node_separate_geometry_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometrySeparateGeometry *data = (NodeGeometrySeparateGeometry *)MEM_callocN( sizeof(NodeGeometrySeparateGeometry), __func__); @@ -51,14 +51,13 @@ static void geo_node_separate_geometry_init(bNodeTree *UNUSED(tree), bNode *node node->storage = data; } -static void geo_node_separate_geometry_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); - const bNode &node = params.node(); - const NodeGeometryDeleteGeometry &storage = *(const NodeGeometryDeleteGeometry *)node.storage; + const NodeGeometrySeparateGeometry &storage = node_storage(params.node()); const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain); bool all_is_error = false; @@ -95,10 +94,12 @@ static void geo_node_separate_geometry_exec(GeoNodeExecParams params) } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_separate_geometry_cc void register_node_type_geo_separate_geometry() { + namespace file_ns = blender::nodes::node_geo_separate_geometry_cc; + static bNodeType ntype; geo_node_type_base( @@ -109,10 +110,10 @@ void register_node_type_geo_separate_geometry() node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_separate_geometry_init); + node_type_init(&ntype, file_ns::node_init); - ntype.declare = blender::nodes::geo_node_separate_geometry_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_separate_geometry_exec; - ntype.draw_buttons = blender::nodes::geo_node_separate_geometry_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } 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 30b445da58c..f98b4116526 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 @@ -21,9 +21,11 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_curve_handles_cc { -static void geo_node_set_curve_handles_declare(NodeDeclarationBuilder &b) +NODE_STORAGE_FUNCS(NodeGeometrySetCurveHandlePositions) + +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(); @@ -32,14 +34,12 @@ static void geo_node_set_curve_handles_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_set_curve_handles_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_set_curve_handles_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometrySetCurveHandlePositions *data = (NodeGeometrySetCurveHandlePositions *)MEM_callocN( sizeof(NodeGeometrySetCurveHandlePositions), __func__); @@ -60,10 +60,12 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode, return; } - fn::FieldEvaluator selection_evaluator{field_context, domain_size}; - selection_evaluator.add(selection_field); - selection_evaluator.evaluate(); - const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0); + fn::FieldEvaluator evaluator{field_context, domain_size}; + evaluator.set_selection(selection_field); + evaluator.add(position_field); + evaluator.add(offset_field); + evaluator.evaluate(); + const IndexMask selection = evaluator.get_evaluated_selection_as_mask(); CurveComponent *curve_component = static_cast<CurveComponent *>(&component); CurveEval *curve = curve_component->get_for_write(); @@ -77,7 +79,7 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode, if (spline->type() == Spline::Type::Bezier) { BezierSpline &bezier = static_cast<BezierSpline &>(*spline); for (int i : bezier.positions().index_range()) { - if (selection[current_mask] == current_point) { + if (current_mask < selection.size() && selection[current_mask] == current_point) { if (mode & GEO_NODE_CURVE_HANDLE_LEFT) { if (bezier.handle_types_left()[i] == BezierSpline::HandleType::Vector) { bezier.ensure_auto_handles(); @@ -105,7 +107,7 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode, } else { for (int UNUSED(i) : spline->positions().index_range()) { - if (selection[current_mask] == current_point) { + if (current_mask < selection.size() && selection[current_mask] == current_point) { current_mask++; } current_point++; @@ -113,13 +115,8 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode, } } - fn::FieldEvaluator position_evaluator{field_context, &selection}; - position_evaluator.add(position_field); - position_evaluator.add(offset_field); - position_evaluator.evaluate(); - - const VArray<float3> &positions_input = position_evaluator.get_evaluated<float3>(0); - const VArray<float3> &offsets_input = position_evaluator.get_evaluated<float3>(1); + const VArray<float3> &positions_input = evaluator.get_evaluated<float3>(0); + const VArray<float3> &offsets_input = evaluator.get_evaluated<float3>(1); OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output<float3>( side, ATTR_DOMAIN_POINT, {0, 0, 0}); @@ -132,11 +129,10 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode, positions.save(); } -static void geo_node_set_curve_handles_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { - const NodeGeometrySetCurveHandlePositions *node_storage = - (NodeGeometrySetCurveHandlePositions *)params.node().storage; - const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)node_storage->mode; + const NodeGeometrySetCurveHandlePositions &storage = node_storage(params.node()); + const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)storage.mode; GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -162,22 +158,24 @@ static void geo_node_set_curve_handles_exec(GeoNodeExecParams params) params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_curve_handles_cc void register_node_type_geo_set_curve_handles() { + namespace file_ns = blender::nodes::node_geo_set_curve_handles_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_SET_CURVE_HANDLES, "Set Handle Positions", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_curve_handles_exec; - ntype.declare = blender::nodes::geo_node_set_curve_handles_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; ntype.minwidth = 100.0f; - node_type_init(&ntype, blender::nodes::geo_node_set_curve_handles_init); + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometrySetCurveHandlePositions", node_free_standard_storage, node_copy_standard_storage); - ntype.draw_buttons = blender::nodes::geo_node_set_curve_handles_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc index e47ce7dea30..7d99f42c487 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_curve_radius_cc { -static void geo_node_set_curve_radius_declare(NodeDeclarationBuilder &b) +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(); @@ -40,20 +40,18 @@ static void set_radius_in_component(GeometryComponent &component, return; } - fn::FieldEvaluator selection_evaluator{field_context, domain_size}; - selection_evaluator.add(selection_field); - selection_evaluator.evaluate(); - const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0); - OutputAttribute_Typed<float> radii = component.attribute_try_get_for_output_only<float>( "radius", ATTR_DOMAIN_POINT); - fn::FieldEvaluator radii_evaluator{field_context, &selection}; - radii_evaluator.add_with_destination(radius_field, radii.varray()); - radii_evaluator.evaluate(); + + fn::FieldEvaluator evaluator{field_context, domain_size}; + evaluator.set_selection(selection_field); + evaluator.add_with_destination(radius_field, radii.varray()); + evaluator.evaluate(); + radii.save(); } -static void geo_node_set_curve_radius_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -69,15 +67,17 @@ static void geo_node_set_curve_radius_exec(GeoNodeExecParams params) params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_curve_radius_cc void register_node_type_geo_set_curve_radius() { + namespace file_ns = blender::nodes::node_geo_set_curve_radius_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_SET_CURVE_RADIUS, "Set Curve Radius", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_curve_radius_exec; - ntype.declare = blender::nodes::geo_node_set_curve_radius_declare; + 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_set_curve_tilt.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc index a861c35f738..447310e1ad7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_curve_tilt_cc { -static void geo_node_set_curve_tilt_declare(NodeDeclarationBuilder &b) +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(); @@ -36,20 +36,18 @@ static void set_tilt_in_component(GeometryComponent &component, return; } - fn::FieldEvaluator selection_evaluator{field_context, domain_size}; - selection_evaluator.add(selection_field); - selection_evaluator.evaluate(); - const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0); - OutputAttribute_Typed<float> tilts = component.attribute_try_get_for_output_only<float>( "tilt", ATTR_DOMAIN_POINT); - fn::FieldEvaluator tilt_evaluator{field_context, &selection}; - tilt_evaluator.add_with_destination(tilt_field, tilts.varray()); - tilt_evaluator.evaluate(); + + fn::FieldEvaluator evaluator{field_context, domain_size}; + evaluator.set_selection(selection_field); + evaluator.add_with_destination(tilt_field, tilts.varray()); + evaluator.evaluate(); + tilts.save(); } -static void geo_node_set_curve_tilt_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -65,14 +63,16 @@ static void geo_node_set_curve_tilt_exec(GeoNodeExecParams params) params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_curve_tilt_cc void register_node_type_geo_set_curve_tilt() { + namespace file_ns = blender::nodes::node_geo_set_curve_tilt_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SET_CURVE_TILT, "Set Curve Tilt", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_curve_tilt_exec; - ntype.declare = blender::nodes::geo_node_set_curve_tilt_declare; + 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_set_id.cc b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc index 77d8e786501..db4083acd4b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_id_cc { -static void geo_node_set_id_declare(NodeDeclarationBuilder &b) +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(); @@ -36,26 +36,24 @@ static void set_id_in_component(GeometryComponent &component, return; } - fn::FieldEvaluator selection_evaluator{field_context, domain_size}; - selection_evaluator.add(selection_field); - selection_evaluator.evaluate(); - const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0); + fn::FieldEvaluator evaluator{field_context, domain_size}; + evaluator.set_selection(selection_field); /* Since adding the ID attribute can change the result of the field evaluation (the random value * node uses the index if the ID is unavailable), make sure that it isn't added before evaluating * the field. However, as an optimization, use a faster code path when it already exists. */ - fn::FieldEvaluator id_evaluator{field_context, &selection}; if (component.attribute_exists("id")) { OutputAttribute_Typed<int> id_attribute = component.attribute_try_get_for_output_only<int>( "id", ATTR_DOMAIN_POINT); - id_evaluator.add_with_destination(id_field, id_attribute.varray()); - id_evaluator.evaluate(); + evaluator.add_with_destination(id_field, id_attribute.varray()); + evaluator.evaluate(); id_attribute.save(); } else { - id_evaluator.add(id_field); - id_evaluator.evaluate(); - const VArray<int> &result_ids = id_evaluator.get_evaluated<int>(0); + evaluator.add(id_field); + evaluator.evaluate(); + const IndexMask selection = evaluator.get_evaluated_selection_as_mask(); + const VArray<int> &result_ids = evaluator.get_evaluated<int>(0); OutputAttribute_Typed<int> id_attribute = component.attribute_try_get_for_output_only<int>( "id", ATTR_DOMAIN_POINT); result_ids.materialize(selection, id_attribute.as_span()); @@ -63,7 +61,7 @@ static void set_id_in_component(GeometryComponent &component, } } -static void geo_node_set_id_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -81,14 +79,16 @@ static void geo_node_set_id_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_id_cc void register_node_type_geo_set_id() { + namespace file_ns = blender::nodes::node_geo_set_id_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SET_ID, "Set ID", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_id_exec; - ntype.declare = blender::nodes::geo_node_set_id_declare; + 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_set_material.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc index 3817de02a38..30510c3570c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_material.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc @@ -21,16 +21,18 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "DNA_pointcloud_types.h" #include "DNA_volume_types.h" #include "BKE_material.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_material_cc { -static void geo_node_set_material_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")) - .supported_type({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_VOLUME}); + .supported_type( + {GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_VOLUME, GEO_COMPONENT_TYPE_POINT_CLOUD}); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); b.add_input<decl::Material>(N_("Material")).hide_label(); b.add_output<decl::Geometry>(N_("Geometry")); @@ -59,58 +61,68 @@ static void assign_material_to_faces(Mesh &mesh, const IndexMask selection, Mate } } -static void geo_node_set_material_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Material *material = params.extract_input<Material *>("Material"); const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); + /* Only add the warnings once, even if there are many unique instances. */ + bool point_selection_warning = false; bool volume_selection_warning = false; + geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { - if (geometry_set.has<MeshComponent>()) { + if (geometry_set.has_mesh()) { MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>(); - Mesh *mesh = mesh_component.get_for_write(); - if (mesh != nullptr) { - GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_FACE}; + Mesh &mesh = *mesh_component.get_for_write(); + GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_FACE}; - fn::FieldEvaluator selection_evaluator{field_context, mesh->totpoly}; - selection_evaluator.add(selection_field); - selection_evaluator.evaluate(); - const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0); + fn::FieldEvaluator selection_evaluator{field_context, mesh.totpoly}; + selection_evaluator.add(selection_field); + selection_evaluator.evaluate(); + const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0); - assign_material_to_faces(*mesh, selection, material); - } + assign_material_to_faces(mesh, selection, material); } - if (geometry_set.has_volume()) { - Volume &volume = *geometry_set.get_volume_for_write(); - + if (Volume *volume = geometry_set.get_volume_for_write()) { + BKE_id_material_eval_assign(&volume->id, 1, material); if (selection_field.node().depends_on_input()) { volume_selection_warning = true; } - - BKE_id_material_eval_assign(&volume.id, 1, material); + } + if (PointCloud *pointcloud = geometry_set.get_pointcloud_for_write()) { + BKE_id_material_eval_assign(&pointcloud->id, 1, material); + if (selection_field.node().depends_on_input()) { + point_selection_warning = true; + } } }); if (volume_selection_warning) { - /* Only add the warning once, even if there are many unique volume instances. */ params.error_message_add( NodeWarningType::Info, TIP_("Volumes only support a single material; selection input can not be a field")); } + if (point_selection_warning) { + params.error_message_add( + NodeWarningType::Info, + TIP_("Point clouds only support a single material; selection input can not be a field")); + } params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_material_cc void register_node_type_geo_set_material() { + namespace file_ns = blender::nodes::node_geo_set_material_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SET_MATERIAL, "Set Material", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_set_material_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_set_material_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc index a8bb1bd8644..4451907132a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_material_index_cc { -static void geo_node_set_material_index_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_MESH); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -36,20 +36,17 @@ static void set_material_index_in_component(GeometryComponent &component, return; } - fn::FieldEvaluator selection_evaluator{field_context, domain_size}; - selection_evaluator.add(selection_field); - selection_evaluator.evaluate(); - const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0); - OutputAttribute_Typed<int> indices = component.attribute_try_get_for_output_only<int>( "material_index", ATTR_DOMAIN_FACE); - fn::FieldEvaluator material_evaluator{field_context, &selection}; - material_evaluator.add_with_destination(index_field, indices.varray()); - material_evaluator.evaluate(); + + fn::FieldEvaluator evaluator{field_context, domain_size}; + evaluator.set_selection(selection_field); + evaluator.add_with_destination(index_field, indices.varray()); + evaluator.evaluate(); indices.save(); } -static void geo_node_set_material_index_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -64,15 +61,17 @@ static void geo_node_set_material_index_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_material_index_cc void register_node_type_geo_set_material_index() { + namespace file_ns = blender::nodes::node_geo_set_material_index_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_SET_MATERIAL_INDEX, "Set Material Index", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_material_index_exec; - ntype.declare = blender::nodes::geo_node_set_material_index_declare; + 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_set_point_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc index 9ff299542b4..98adff7c939 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_point_radius_cc { -static void geo_node_set_point_radius_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Points")).supported_type(GEO_COMPONENT_TYPE_POINT_CLOUD); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -40,20 +40,18 @@ static void set_radius_in_component(GeometryComponent &component, return; } - fn::FieldEvaluator selection_evaluator{field_context, domain_size}; - selection_evaluator.add(selection_field); - selection_evaluator.evaluate(); - const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0); - OutputAttribute_Typed<float> radii = component.attribute_try_get_for_output_only<float>( "radius", ATTR_DOMAIN_POINT); - fn::FieldEvaluator radii_evaluator{field_context, &selection}; - radii_evaluator.add_with_destination(radius_field, radii.varray()); - radii_evaluator.evaluate(); + + fn::FieldEvaluator evaluator{field_context, domain_size}; + evaluator.set_selection(selection_field); + evaluator.add_with_destination(radius_field, radii.varray()); + evaluator.evaluate(); + radii.save(); } -static void geo_node_set_point_radius_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Points"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -70,15 +68,17 @@ static void geo_node_set_point_radius_exec(GeoNodeExecParams params) params.set_output("Points", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_point_radius_cc void register_node_type_geo_set_point_radius() { + namespace file_ns = blender::nodes::node_geo_set_point_radius_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_SET_POINT_RADIUS, "Set Point Radius", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_point_radius_exec; - ntype.declare = blender::nodes::geo_node_set_point_radius_declare; + 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_set_position.cc b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc index 5fe9fb1b3d4..93073c2436d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc @@ -16,11 +16,16 @@ #include "DEG_depsgraph_query.h" +#include "BLI_task.hh" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_position_cc { -static void geo_node_set_position_declare(NodeDeclarationBuilder &b) +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(); @@ -29,6 +34,77 @@ static void geo_node_set_position_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } +static void set_computed_position_and_offset(GeometryComponent &component, + const VArray<float3> &in_positions, + const VArray<float3> &in_offsets, + const AttributeDomain domain, + const IndexMask selection) +{ + + OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output<float3>( + "position", domain, {0, 0, 0}); + + const int grain_size = 10000; + + switch (component.type()) { + case GEO_COMPONENT_TYPE_MESH: { + Mesh *mesh = static_cast<MeshComponent &>(component).get_for_write(); + MutableSpan<MVert> mverts{mesh->mvert, mesh->totvert}; + if (in_positions.is_same(positions.varray())) { + devirtualize_varray(in_offsets, [&](const auto in_offsets) { + threading::parallel_for( + selection.index_range(), grain_size, [&](const IndexRange range) { + for (const int i : selection.slice(range)) { + const float3 offset = in_offsets[i]; + add_v3_v3(mverts[i].co, offset); + } + }); + }); + } + else { + devirtualize_varray2( + in_positions, in_offsets, [&](const auto in_positions, const auto in_offsets) { + threading::parallel_for( + selection.index_range(), grain_size, [&](const IndexRange range) { + for (const int i : selection.slice(range)) { + const float3 new_position = in_positions[i] + in_offsets[i]; + copy_v3_v3(mverts[i].co, new_position); + } + }); + }); + } + break; + } + default: { + MutableSpan<float3> out_positions_span = positions.as_span(); + if (in_positions.is_same(positions.varray())) { + devirtualize_varray(in_offsets, [&](const auto in_offsets) { + threading::parallel_for( + selection.index_range(), grain_size, [&](const IndexRange range) { + for (const int i : selection.slice(range)) { + out_positions_span[i] += in_offsets[i]; + } + }); + }); + } + else { + devirtualize_varray2( + in_positions, in_offsets, [&](const auto in_positions, const auto in_offsets) { + threading::parallel_for( + selection.index_range(), grain_size, [&](const IndexRange range) { + for (const int i : selection.slice(range)) { + out_positions_span[i] = in_positions[i] + in_offsets[i]; + } + }); + }); + } + break; + } + } + + positions.save(); +} + static void set_position_in_component(GeometryComponent &component, const Field<bool> &selection_field, const Field<float3> &position_field, @@ -43,33 +119,19 @@ static void set_position_in_component(GeometryComponent &component, return; } - fn::FieldEvaluator selection_evaluator{field_context, domain_size}; - selection_evaluator.add(selection_field); - selection_evaluator.evaluate(); - const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0); - - fn::FieldEvaluator position_evaluator{field_context, &selection}; - position_evaluator.add(position_field); - position_evaluator.add(offset_field); - position_evaluator.evaluate(); + fn::FieldEvaluator evaluator{field_context, domain_size}; + evaluator.set_selection(selection_field); + evaluator.add(position_field); + evaluator.add(offset_field); + evaluator.evaluate(); - /* TODO: We could have different code paths depending on whether the offset input is a single - * value or not */ - - const VArray<float3> &positions_input = position_evaluator.get_evaluated<float3>(0); - const VArray<float3> &offsets_input = position_evaluator.get_evaluated<float3>(1); - - OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output<float3>( - "position", domain, {0, 0, 0}); - MutableSpan<float3> position_mutable = positions.as_span(); - - for (int i : selection) { - position_mutable[i] = positions_input[i] + offsets_input[i]; - } - positions.save(); + const IndexMask selection = evaluator.get_evaluated_selection_as_mask(); + const VArray<float3> &positions_input = evaluator.get_evaluated<float3>(0); + const VArray<float3> &offsets_input = evaluator.get_evaluated<float3>(1); + set_computed_position_and_offset(component, positions_input, offsets_input, domain, selection); } -static void geo_node_set_position_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry = params.extract_input<GeometrySet>("Geometry"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -89,14 +151,16 @@ static void geo_node_set_position_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_position_cc void register_node_type_geo_set_position() { + namespace file_ns = blender::nodes::node_geo_set_position_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SET_POSITION, "Set Position", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_position_exec; - ntype.declare = blender::nodes::geo_node_set_position_declare; + 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_set_shade_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc index 06e25c2ed55..879a868cc0e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_shade_smooth_cc { -static void geo_node_set_shade_smooth_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_MESH); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -36,20 +36,18 @@ static void set_smooth_in_component(GeometryComponent &component, return; } - fn::FieldEvaluator selection_evaluator{field_context, domain_size}; - selection_evaluator.add(selection_field); - selection_evaluator.evaluate(); - const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0); - OutputAttribute_Typed<bool> shades = component.attribute_try_get_for_output_only<bool>( "shade_smooth", ATTR_DOMAIN_FACE); - fn::FieldEvaluator shade_evaluator{field_context, &selection}; - shade_evaluator.add_with_destination(shade_field, shades.varray()); - shade_evaluator.evaluate(); + + fn::FieldEvaluator evaluator{field_context, domain_size}; + evaluator.set_selection(selection_field); + evaluator.add_with_destination(shade_field, shades.varray()); + evaluator.evaluate(); + shades.save(); } -static void geo_node_set_shade_smooth_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -64,15 +62,17 @@ static void geo_node_set_shade_smooth_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_shade_smooth_cc void register_node_type_geo_set_shade_smooth() { + namespace file_ns = blender::nodes::node_geo_set_shade_smooth_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_SET_SHADE_SMOOTH, "Set Shade Smooth", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_shade_smooth_exec; - ntype.declare = blender::nodes::geo_node_set_shade_smooth_declare; + 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_set_spline_cyclic.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc index ec751ae1d2b..694491d7e6d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_spline_cyclic_cc { -static void geo_node_set_spline_cyclic_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -36,20 +36,18 @@ static void set_cyclic_in_component(GeometryComponent &component, return; } - fn::FieldEvaluator selection_evaluator{field_context, domain_size}; - selection_evaluator.add(selection_field); - selection_evaluator.evaluate(); - const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0); - OutputAttribute_Typed<bool> cyclics = component.attribute_try_get_for_output_only<bool>( "cyclic", ATTR_DOMAIN_CURVE); - fn::FieldEvaluator cyclic_evaluator{field_context, &selection}; - cyclic_evaluator.add_with_destination(cyclic_field, cyclics.varray()); - cyclic_evaluator.evaluate(); + + fn::FieldEvaluator evaluator{field_context, domain_size}; + evaluator.set_selection(selection_field); + evaluator.add_with_destination(cyclic_field, cyclics.varray()); + evaluator.evaluate(); + cyclics.save(); } -static void geo_node_set_spline_cyclic_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -65,15 +63,17 @@ static void geo_node_set_spline_cyclic_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_spline_cyclic_cc void register_node_type_geo_set_spline_cyclic() { + namespace file_ns = blender::nodes::node_geo_set_spline_cyclic_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_SET_SPLINE_CYCLIC, "Set Spline Cyclic", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_spline_cyclic_exec; - ntype.declare = blender::nodes::geo_node_set_spline_cyclic_declare; + 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_set_spline_resolution.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc index ccf419975ca..0f93db5e6f6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc @@ -18,13 +18,13 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_spline_resolution_cc { -static void geo_node_set_spline_resolution_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); - b.add_input<decl::Int>(N_("Resolution")).default_value(12).supports_field(); + b.add_input<decl::Int>(N_("Resolution")).min(1).default_value(12).supports_field(); b.add_output<decl::Geometry>(N_("Geometry")); } @@ -38,20 +38,18 @@ static void set_resolution_in_component(GeometryComponent &component, return; } - fn::FieldEvaluator selection_evaluator{field_context, domain_size}; - selection_evaluator.add(selection_field); - selection_evaluator.evaluate(); - const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0); - OutputAttribute_Typed<int> resolutions = component.attribute_try_get_for_output_only<int>( "resolution", ATTR_DOMAIN_CURVE); - fn::FieldEvaluator resolution_evaluator{field_context, &selection}; - resolution_evaluator.add_with_destination(resolution_field, resolutions.varray()); - resolution_evaluator.evaluate(); + + fn::FieldEvaluator evaluator{field_context, domain_size}; + evaluator.set_selection(selection_field); + evaluator.add_with_destination(resolution_field, resolutions.varray()); + evaluator.evaluate(); + resolutions.save(); } -static void geo_node_set_spline_resolution_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -81,15 +79,17 @@ static void geo_node_set_spline_resolution_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_spline_resolution_cc void register_node_type_geo_set_spline_resolution() { + namespace file_ns = blender::nodes::node_geo_set_spline_resolution_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_SET_SPLINE_RESOLUTION, "Set Spline Resolution", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_spline_resolution_exec; - ntype.declare = blender::nodes::geo_node_set_spline_resolution_declare; + 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_string_join.cc b/source/blender/nodes/geometry/nodes/node_geo_string_join.cc index 98d0aca084a..5308b43afb2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_string_join.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_string_join.cc @@ -16,16 +16,16 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_string_join_cc { -static void geo_node_string_join_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::String>(N_("Delimiter")); b.add_input<decl::String>(N_("Strings")).multi_input().hide_value(); b.add_output<decl::String>(N_("String")); }; -static void geo_node_string_join_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Vector<std::string> strings = params.extract_multi_input<std::string>("Strings"); const std::string delim = params.extract_input<std::string>("Delimiter"); @@ -40,14 +40,16 @@ static void geo_node_string_join_exec(GeoNodeExecParams params) params.set_output("String", std::move(output)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_string_join_cc void register_node_type_geo_string_join() { + namespace file_ns = blender::nodes::node_geo_string_join_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_STRING_JOIN, "Join Strings", NODE_CLASS_CONVERTER, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_string_join_exec; - ntype.declare = blender::nodes::geo_node_string_join_declare; + 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_string_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc index 9e3ff10a3c5..33614eb3c46 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 @@ -30,9 +30,11 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_string_to_curves_cc { -static void geo_node_string_to_curves_declare(NodeDeclarationBuilder &b) +NODE_STORAGE_FUNCS(NodeGeometryStringToCurves) + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::String>(N_("String")); b.add_input<decl::Float>(N_("Size")).default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE); @@ -55,12 +57,17 @@ static void geo_node_string_to_curves_declare(NodeDeclarationBuilder &b) b.add_input<decl::Float>(N_("Text Box Height")) .default_value(0.0f) .min(0.0f) - .subtype(PROP_DISTANCE); + .subtype(PROP_DISTANCE) + .make_available([](bNode &node) { + node_storage(node).overflow = GEO_NODE_STRING_TO_CURVES_MODE_SCALE_TO_FIT; + }); b.add_output<decl::Geometry>(N_("Curves")); - b.add_output<decl::String>(N_("Remainder")); + b.add_output<decl::String>(N_("Remainder")).make_available([](bNode &node) { + node_storage(node).overflow = GEO_NODE_STRING_TO_CURVES_MODE_TRUNCATE; + }); } -static void geo_node_string_to_curves_layout(uiLayout *layout, struct bContext *C, PointerRNA *ptr) +static void node_layout(uiLayout *layout, struct bContext *C, PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -79,7 +86,7 @@ static void geo_node_string_to_curves_layout(uiLayout *layout, struct bContext * uiItemR(layout, ptr, "align_y", 0, "", ICON_NONE); } -static void geo_node_string_to_curves_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryStringToCurves *data = (NodeGeometryStringToCurves *)MEM_callocN( sizeof(NodeGeometryStringToCurves), __func__); @@ -91,11 +98,11 @@ static void geo_node_string_to_curves_init(bNodeTree *UNUSED(ntree), bNode *node node->id = (ID *)BKE_vfont_builtin_get(); } -static void geo_node_string_to_curves_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { - const NodeGeometryStringToCurves *storage = (const NodeGeometryStringToCurves *)node->storage; + const NodeGeometryStringToCurves &storage = node_storage(*node); const GeometryNodeStringToCurvesOverflowMode overflow = (GeometryNodeStringToCurvesOverflowMode) - storage->overflow; + storage.overflow; bNodeSocket *socket_remainder = ((bNodeSocket *)node->outputs.first)->next; nodeSetSocketAvailability( ntree, socket_remainder, overflow == GEO_NODE_STRING_TO_CURVES_MODE_TRUNCATE); @@ -131,8 +138,7 @@ static TextLayout get_text_layout(GeoNodeExecParams ¶ms) return {}; } - const NodeGeometryStringToCurves &storage = - *(const NodeGeometryStringToCurves *)params.node().storage; + const NodeGeometryStringToCurves &storage = node_storage(params.node()); const GeometryNodeStringToCurvesOverflowMode overflow = (GeometryNodeStringToCurvesOverflowMode) storage.overflow; const GeometryNodeStringToCurvesAlignXMode align_x = (GeometryNodeStringToCurvesAlignXMode) @@ -265,7 +271,7 @@ static void add_instances_from_handles(InstancesComponent &instances, }); } -static void geo_node_string_to_curves_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { TextLayout layout = get_text_layout(params); @@ -297,23 +303,25 @@ static void geo_node_string_to_curves_exec(GeoNodeExecParams params) params.set_output("Curves", std::move(geometry_set_out)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_string_to_curves_cc void register_node_type_geo_string_to_curves() { + namespace file_ns = blender::nodes::node_geo_string_to_curves_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_STRING_TO_CURVES, "String to Curves", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_string_to_curves_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_string_to_curves_exec; - node_type_init(&ntype, blender::nodes::geo_node_string_to_curves_init); - node_type_update(&ntype, blender::nodes::geo_node_string_to_curves_update); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_size(&ntype, 190, 120, 700); node_type_storage(&ntype, "NodeGeometryStringToCurves", node_free_standard_storage, node_copy_standard_storage); - ntype.draw_buttons = blender::nodes::geo_node_string_to_curves_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc index 2b3430a5ed0..74e0560b32f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc @@ -27,9 +27,11 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_subdivision_surface_cc { -static void geo_node_subdivision_surface_declare(NodeDeclarationBuilder &b) +NODE_STORAGE_FUNCS(NodeGeometrySubdivisionSurface) + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH); b.add_input<decl::Int>(N_("Level")).default_value(1).min(0).max(6); @@ -42,15 +44,13 @@ static void geo_node_subdivision_surface_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Mesh")); } -static void geo_node_subdivision_surface_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "uv_smooth", 0, "", ICON_NONE); uiItemR(layout, ptr, "boundary_smooth", 0, "", ICON_NONE); } -static void geo_node_subdivision_surface_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometrySubdivisionSurface *data = (NodeGeometrySubdivisionSurface *)MEM_callocN( sizeof(NodeGeometrySubdivisionSurface), __func__); @@ -59,7 +59,7 @@ static void geo_node_subdivision_surface_init(bNodeTree *UNUSED(ntree), bNode *n node->storage = data; } -static void geo_node_subdivision_surface_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); #ifndef WITH_OPENSUBDIV @@ -68,8 +68,7 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params) #else Field<float> crease_field = params.extract_input<Field<float>>("Crease"); - const NodeGeometrySubdivisionSurface &storage = - *(const NodeGeometrySubdivisionSurface *)params.node().storage; + const NodeGeometrySubdivisionSurface &storage = node_storage(params.node()); const int uv_smooth = storage.uv_smooth; const int boundary_smooth = storage.boundary_smooth; const int subdiv_level = clamp_i(params.extract_input<int>("Level"), 0, 30); @@ -145,18 +144,20 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params) params.set_output("Mesh", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_subdivision_surface_cc void register_node_type_geo_subdivision_surface() { + namespace file_ns = blender::nodes::node_geo_subdivision_surface_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_subdivision_surface_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_subdivision_surface_exec; - ntype.draw_buttons = blender::nodes::geo_node_subdivision_surface_layout; - node_type_init(&ntype, blender::nodes::geo_node_subdivision_surface_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + node_type_init(&ntype, file_ns::node_init); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); node_type_storage(&ntype, "NodeGeometrySubdivisionSurface", diff --git a/source/blender/nodes/geometry/nodes/node_geo_switch.cc b/source/blender/nodes/geometry/nodes/node_geo_switch.cc index 8d6f53ae375..d22522fe087 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_switch.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_switch.cc @@ -24,11 +24,15 @@ #include "BKE_material.h" +#include "NOD_socket_search_link.hh" + #include "FN_multi_function_signature.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_switch_cc { + +NODE_STORAGE_FUNCS(NodeSwitch) -static void geo_node_switch_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Bool>(N_("Switch")).default_value(false).supports_field(); b.add_input<decl::Bool>(N_("Switch"), "Switch_001").default_value(false); @@ -83,32 +87,27 @@ static void geo_node_switch_declare(NodeDeclarationBuilder &b) b.add_output<decl::Image>(N_("Output"), "Output_011"); } -static void geo_node_switch_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "input_type", 0, "", ICON_NONE); } -static void geo_node_switch_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeSwitch *data = (NodeSwitch *)MEM_callocN(sizeof(NodeSwitch), __func__); data->input_type = SOCK_GEOMETRY; node->storage = data; } -static void geo_node_switch_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { - NodeSwitch *node_storage = (NodeSwitch *)node->storage; + const NodeSwitch &storage = node_storage(*node); int index = 0; bNodeSocket *field_switch = (bNodeSocket *)node->inputs.first; bNodeSocket *non_field_switch = (bNodeSocket *)field_switch->next; - const bool fields_type = ELEM((eNodeSocketDatatype)node_storage->input_type, - SOCK_FLOAT, - SOCK_INT, - SOCK_BOOLEAN, - SOCK_VECTOR, - SOCK_RGBA, - SOCK_STRING); + const bool fields_type = ELEM( + storage.input_type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA, SOCK_STRING); nodeSetSocketAvailability(ntree, field_switch, fields_type); nodeSetSocketAvailability(ntree, non_field_switch, !fields_type); @@ -117,13 +116,40 @@ static void geo_node_switch_update(bNodeTree *ntree, bNode *node) if (index <= 1) { continue; } - nodeSetSocketAvailability( - ntree, socket, socket->type == (eNodeSocketDatatype)node_storage->input_type); + nodeSetSocketAvailability(ntree, socket, socket->type == storage.input_type); } LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) { - nodeSetSocketAvailability( - ntree, socket, socket->type == (eNodeSocketDatatype)node_storage->input_type); + nodeSetSocketAvailability(ntree, socket, socket->type == storage.input_type); + } +} + +static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) +{ + if (params.in_out() == SOCK_OUT) { + params.add_item(IFACE_("Output"), [](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("GeometryNodeSwitch"); + node_storage(node).input_type = params.socket.type; + params.update_and_connect_available_socket(node, "Output"); + }); + } + else { + if (params.other_socket().type == SOCK_BOOLEAN) { + params.add_item(IFACE_("Switch"), [](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("GeometryNodeSwitch"); + params.connect_available_socket(node, "Start"); + }); + } + params.add_item(IFACE_("False"), [](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("GeometryNodeSwitch"); + node_storage(node).input_type = params.socket.type; + params.update_and_connect_available_socket(node, "False"); + }); + params.add_item(IFACE_("True"), [](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("GeometryNodeSwitch"); + node_storage(node).input_type = params.socket.type; + params.update_and_connect_available_socket(node, "True"); + }); } } @@ -232,9 +258,9 @@ template<typename T> void switch_no_fields(GeoNodeExecParams ¶ms, const Stri } } -static void geo_node_switch_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { - const NodeSwitch &storage = *(const NodeSwitch *)params.node().storage; + const NodeSwitch &storage = node_storage(params.node()); const eNodeSocketDatatype data_type = static_cast<eNodeSocketDatatype>(storage.input_type); switch (data_type) { @@ -293,19 +319,22 @@ static void geo_node_switch_exec(GeoNodeExecParams params) } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_switch_cc void register_node_type_geo_switch() { + namespace file_ns = blender::nodes::node_geo_switch_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SWITCH, "Switch", NODE_CLASS_CONVERTER, 0); - ntype.declare = blender::nodes::geo_node_switch_declare; - node_type_init(&ntype, blender::nodes::geo_node_switch_init); - node_type_update(&ntype, blender::nodes::geo_node_switch_update); + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage(&ntype, "NodeSwitch", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_switch_exec; + ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.geometry_node_execute_supports_laziness = true; - ntype.draw_buttons = blender::nodes::geo_node_switch_layout; + ntype.gather_link_search_ops = file_ns::node_gather_link_searches; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc index 3b30806d8ae..1f099dcd04d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc @@ -31,19 +31,24 @@ #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; using blender::fn::GArray; -namespace blender::nodes { +NODE_STORAGE_FUNCS(NodeGeometryTransferAttribute) -static void geo_node_transfer_attribute_declare(NodeDeclarationBuilder &b) +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, GEO_COMPONENT_TYPE_CURVE}); + .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(); @@ -51,8 +56,14 @@ static void geo_node_transfer_attribute_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::Int>(N_("Index")).implicit_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}); @@ -61,14 +72,12 @@ static void geo_node_transfer_attribute_declare(NodeDeclarationBuilder &b) b.add_output<decl::Int>(N_("Attribute"), "Attribute_004").dependent_field({6, 7}); } -static void geo_node_transfer_attribute_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { const bNode &node = *static_cast<const bNode *>(ptr->data); - const NodeGeometryTransferAttribute &data = *static_cast<const NodeGeometryTransferAttribute *>( - node.storage); - const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode)data.mode; + 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); @@ -77,7 +86,7 @@ static void geo_node_transfer_attribute_layout(uiLayout *layout, } } -static void geo_node_transfer_attribute_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryTransferAttribute *data = (NodeGeometryTransferAttribute *)MEM_callocN( sizeof(NodeGeometryTransferAttribute), __func__); @@ -86,12 +95,12 @@ static void geo_node_transfer_attribute_init(bNodeTree *UNUSED(tree), bNode *nod node->storage = data; } -static void geo_node_transfer_attribute_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { - const NodeGeometryTransferAttribute &data = *(const NodeGeometryTransferAttribute *) - node->storage; - const CustomDataType data_type = static_cast<CustomDataType>(data.data_type); - const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode)data.mode; + const NodeGeometryTransferAttribute &storage = node_storage(*node); + const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); + const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode) + storage.mode; bNodeSocket *socket_geometry = (bNodeSocket *)node->inputs.first; bNodeSocket *socket_vector = socket_geometry->next; @@ -125,6 +134,24 @@ static void geo_node_transfer_attribute_update(bNodeTree *ntree, bNode *node) nodeSetSocketAvailability(ntree, out_socket_int32, data_type == CD_PROP_INT32); } +static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) +{ + 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<CustomDataType> 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 ¶ms) { + 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, @@ -132,9 +159,9 @@ static void get_closest_in_bvhtree(BVHTreeFromMesh &tree_data, const MutableSpan<float> r_distances_sq, const MutableSpan<float3> r_positions) { - BLI_assert(positions.size() == r_indices.size() || r_indices.is_empty()); - BLI_assert(positions.size() == r_distances_sq.size() || r_distances_sq.is_empty()); - BLI_assert(positions.size() == r_positions.size() || r_positions.is_empty()); + 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; @@ -160,7 +187,7 @@ static void get_closest_pointcloud_points(const PointCloud &pointcloud, const MutableSpan<int> r_indices, const MutableSpan<float> r_distances_sq) { - BLI_assert(positions.size() == r_indices.size()); + BLI_assert(positions.size() >= r_indices.size()); BLI_assert(pointcloud.totpoint > 0); BVHTreeFromPointCloud tree_data; @@ -500,7 +527,7 @@ class NearestTransferFunction : public fn::MultiFunction { Array<int> mesh_indices; Array<float> mesh_distances; - /* If there is a point-cloud, find the closest points. */ + /* If there is a point cloud, find the closest points. */ if (use_points_) { point_indices.reinitialize(tot_samples); if (use_mesh_) { @@ -593,8 +620,10 @@ static const GeometryComponent *find_target_component(const GeometrySet &geometr { /* 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}; + 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); @@ -719,14 +748,14 @@ static void output_attribute_field(GeoNodeExecParams ¶ms, GField field) } } -static void geo_node_transfer_attribute_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry = params.extract_input<GeometrySet>("Target"); - const bNode &node = params.node(); - const NodeGeometryTransferAttribute &data = *(const NodeGeometryTransferAttribute *)node.storage; - const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode)data.mode; - const CustomDataType data_type = static_cast<CustomDataType>(data.data_type); - const AttributeDomain domain = static_cast<AttributeDomain>(data.domain); + const NodeGeometryTransferAttribute &storage = node_storage(params.node()); + const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode) + storage.mode; + const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); + const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain); GField field = get_input_attribute_field(params, data_type); @@ -737,10 +766,6 @@ static void geo_node_transfer_attribute_exec(GeoNodeExecParams params) }); }; - /* Since the instances are not used, there is no point in keeping - * a reference to them while the field is passed around. */ - geometry.remove(GEO_COMPONENT_TYPE_INSTANCES); - GField output_field; switch (mapping) { case GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED: { @@ -794,22 +819,25 @@ static void geo_node_transfer_attribute_exec(GeoNodeExecParams params) output_attribute_field(params, std::move(output_field)); } -} // namespace blender::nodes +} // 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, 0); - node_type_init(&ntype, blender::nodes::geo_node_transfer_attribute_init); - node_type_update(&ntype, blender::nodes::geo_node_transfer_attribute_update); + 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 = blender::nodes::geo_node_transfer_attribute_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_transfer_attribute_exec; - ntype.draw_buttons = blender::nodes::geo_node_transfer_attribute_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + ntype.gather_link_search_ops = file_ns::node_gather_link_searches; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc index 2c55a255b5d..8322de20d20 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc @@ -35,15 +35,6 @@ namespace blender::nodes { -static void geo_node_transform_declare(NodeDeclarationBuilder &b) -{ - b.add_input<decl::Geometry>(N_("Geometry")); - b.add_input<decl::Vector>(N_("Translation")).subtype(PROP_TRANSLATION); - b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER); - b.add_input<decl::Vector>(N_("Scale")).default_value({1, 1, 1}).subtype(PROP_XYZ); - b.add_output<decl::Geometry>(N_("Geometry")); -} - static bool use_translate(const float3 rotation, const float3 scale) { if (compare_ff(rotation.length_squared(), 0.0f, 1e-9f) != 1) { @@ -69,15 +60,6 @@ static void transform_mesh(Mesh &mesh, const float4x4 &transform) BKE_mesh_normals_tag_dirty(&mesh); } -void transform_mesh(Mesh &mesh, - const float3 translation, - const float3 rotation, - const float3 scale) -{ - const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale); - transform_mesh(mesh, matrix); -} - static void translate_pointcloud(PointCloud &pointcloud, const float3 translation) { CustomData_duplicate_referenced_layer(&pointcloud.pdata, CD_PROP_FLOAT3, pointcloud.totpoint); @@ -153,49 +135,71 @@ static void translate_volume(Volume &volume, const float3 translation, const Dep transform_volume(volume, float4x4::from_location(translation), depsgraph); } -void transform_geometry_set(GeometrySet &geometry, - const float4x4 &transform, - const Depsgraph &depsgraph) +static void translate_geometry_set(GeometrySet &geometry, + const float3 translation, + const Depsgraph &depsgraph) { if (CurveEval *curve = geometry.get_curve_for_write()) { - curve->transform(transform); + curve->translate(translation); } if (Mesh *mesh = geometry.get_mesh_for_write()) { - transform_mesh(*mesh, transform); + translate_mesh(*mesh, translation); } if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) { - transform_pointcloud(*pointcloud, transform); + translate_pointcloud(*pointcloud, translation); } if (Volume *volume = geometry.get_volume_for_write()) { - transform_volume(*volume, transform, depsgraph); + translate_volume(*volume, translation, depsgraph); } if (geometry.has_instances()) { - transform_instances(geometry.get_component_for_write<InstancesComponent>(), transform); + translate_instances(geometry.get_component_for_write<InstancesComponent>(), translation); } } -static void translate_geometry_set(GeometrySet &geometry, - const float3 translation, - const Depsgraph &depsgraph) +void transform_geometry_set(GeometrySet &geometry, + const float4x4 &transform, + const Depsgraph &depsgraph) { if (CurveEval *curve = geometry.get_curve_for_write()) { - curve->translate(translation); + curve->transform(transform); } if (Mesh *mesh = geometry.get_mesh_for_write()) { - translate_mesh(*mesh, translation); + transform_mesh(*mesh, transform); } if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) { - translate_pointcloud(*pointcloud, translation); + transform_pointcloud(*pointcloud, transform); } if (Volume *volume = geometry.get_volume_for_write()) { - translate_volume(*volume, translation, depsgraph); + transform_volume(*volume, transform, depsgraph); } if (geometry.has_instances()) { - translate_instances(geometry.get_component_for_write<InstancesComponent>(), translation); + transform_instances(geometry.get_component_for_write<InstancesComponent>(), transform); } } -static void geo_node_transform_exec(GeoNodeExecParams params) +void transform_mesh(Mesh &mesh, + const float3 translation, + const float3 rotation, + const float3 scale) +{ + const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale); + transform_mesh(mesh, matrix); +} + +} // namespace blender::nodes + +namespace blender::nodes::node_geo_transform_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Geometry>(N_("Geometry")); + b.add_input<decl::Vector>(N_("Translation")).subtype(PROP_TRANSLATION); + b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER); + b.add_input<decl::Vector>(N_("Scale")).default_value({1, 1, 1}).subtype(PROP_XYZ); + b.add_output<decl::Geometry>(N_("Geometry")); +} + +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); const float3 translation = params.extract_input<float3>("Translation"); @@ -214,14 +218,16 @@ static void geo_node_transform_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_transform_cc void register_node_type_geo_transform() { + namespace file_ns = blender::nodes::node_geo_transform_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_TRANSFORM, "Transform", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_transform_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_transform_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc index 1a5a60fb1b0..59049ecf0ed 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc @@ -18,9 +18,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_translate_instances_cc { -static void geo_node_translate_instances_declare(NodeDeclarationBuilder &b) +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(); @@ -33,17 +33,15 @@ static void translate_instances(GeoNodeExecParams ¶ms, InstancesComponent &i { GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE}; - fn::FieldEvaluator selection_evaluator{field_context, instances_component.instances_amount()}; - selection_evaluator.add(params.extract_input<Field<bool>>("Selection")); - selection_evaluator.evaluate(); - const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0); + fn::FieldEvaluator evaluator{field_context, instances_component.instances_amount()}; + evaluator.set_selection(params.extract_input<Field<bool>>("Selection")); + evaluator.add(params.extract_input<Field<float3>>("Translation")); + evaluator.add(params.extract_input<Field<bool>>("Local Space")); + evaluator.evaluate(); - fn::FieldEvaluator transforms_evaluator{field_context, &selection}; - transforms_evaluator.add(params.extract_input<Field<float3>>("Translation")); - transforms_evaluator.add(params.extract_input<Field<bool>>("Local Space")); - transforms_evaluator.evaluate(); - const VArray<float3> &translations = transforms_evaluator.get_evaluated<float3>(0); - const VArray<bool> &local_spaces = transforms_evaluator.get_evaluated<bool>(1); + const IndexMask selection = evaluator.get_evaluated_selection_as_mask(); + const VArray<float3> &translations = evaluator.get_evaluated<float3>(0); + const VArray<bool> &local_spaces = evaluator.get_evaluated<bool>(1); MutableSpan<float4x4> instance_transforms = instances_component.instance_transforms(); @@ -60,7 +58,7 @@ static void translate_instances(GeoNodeExecParams ¶ms, InstancesComponent &i }); } -static void geo_node_translate_instances_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances"); if (geometry_set.has_instances()) { @@ -70,15 +68,17 @@ static void geo_node_translate_instances_exec(GeoNodeExecParams params) params.set_output("Instances", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_translate_instances_cc void register_node_type_geo_translate_instances() { + namespace file_ns = blender::nodes::node_geo_translate_instances_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_TRANSLATE_INSTANCES, "Translate Instances", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_translate_instances_exec; - ntype.declare = blender::nodes::geo_node_translate_instances_declare; + 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_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc index c869846e1f8..f8deaaa4a14 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc @@ -27,16 +27,16 @@ Mesh *triangulate_mesh(Mesh *mesh, const int flag); } -namespace blender::nodes { +namespace blender::nodes::node_geo_triangulate_cc { -static void geo_node_triangulate_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH); b.add_input<decl::Int>(N_("Minimum Vertices")).default_value(4).min(4).max(10000); b.add_output<decl::Geometry>(N_("Mesh")); } -static void geo_node_triangulate_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "quad_method", 0, "", ICON_NONE); uiItemR(layout, ptr, "ngon_method", 0, "", ICON_NONE); @@ -48,7 +48,7 @@ static void geo_triangulate_init(bNodeTree *UNUSED(ntree), bNode *node) node->custom2 = GEO_NODE_TRIANGULATE_NGON_BEAUTY; } -static void geo_node_triangulate_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); const int min_vertices = std::max(params.extract_input<int>("Minimum Vertices"), 4); @@ -69,16 +69,18 @@ static void geo_node_triangulate_exec(GeoNodeExecParams params) params.set_output("Mesh", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_triangulate_cc void register_node_type_geo_triangulate() { + namespace file_ns = blender::nodes::node_geo_triangulate_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_TRIANGULATE, "Triangulate", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_triangulate_declare; - node_type_init(&ntype, blender::nodes::geo_triangulate_init); - ntype.geometry_node_execute = blender::nodes::geo_node_triangulate_exec; - ntype.draw_buttons = blender::nodes::geo_node_triangulate_layout; + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::geo_triangulate_init); + 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_viewer.cc b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc index a46d7529124..18f2fa4cd36 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc @@ -14,13 +14,23 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "BKE_context.h" + #include "UI_interface.h" #include "UI_resources.h" +#include "ED_node.h" +#include "ED_spreadsheet.h" + +#include "NOD_socket_search_link.hh" + #include "node_geometry_util.hh" -namespace blender::nodes { -static void geo_node_viewer_declare(NodeDeclarationBuilder &b) +namespace blender::nodes::node_geo_viewer_cc { + +NODE_STORAGE_FUNCS(NodeGeometryViewer) + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Float>(N_("Value")).supports_field().hide_value(); @@ -30,7 +40,7 @@ static void geo_node_viewer_declare(NodeDeclarationBuilder &b) b.add_input<decl::Bool>(N_("Value"), "Value_004").supports_field().hide_value(); } -static void geo_node_viewer_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryViewer *data = (NodeGeometryViewer *)MEM_callocN(sizeof(NodeGeometryViewer), __func__); @@ -39,7 +49,7 @@ static void geo_node_viewer_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_viewer_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); } @@ -63,9 +73,9 @@ static eNodeSocketDatatype custom_data_type_to_socket_type(const CustomDataType } } -static void geo_node_viewer_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { - const NodeGeometryViewer &storage = *(const NodeGeometryViewer *)node->storage; + const NodeGeometryViewer &storage = node_storage(*node); const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); const eNodeSocketDatatype socket_type = custom_data_type_to_socket_type(data_type); @@ -77,18 +87,67 @@ static void geo_node_viewer_update(bNodeTree *ntree, bNode *node) } } -} // namespace blender::nodes +static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) +{ + auto set_active_fn = [](LinkSearchOpParams ¶ms, bNode &viewer_node) { + /* Set this new viewer node active in spreadsheet editors. */ + SpaceNode *snode = CTX_wm_space_node(¶ms.C); + Main *bmain = CTX_data_main(¶ms.C); + ED_node_set_active(bmain, snode, ¶ms.node_tree, &viewer_node, nullptr); + ED_spreadsheet_context_paths_set_geometry_node(bmain, snode, &viewer_node); + }; + + const std::optional<CustomDataType> type = node_socket_to_custom_data_type( + params.other_socket()); + if (params.in_out() == SOCK_OUT) { + /* The viewer node only has inputs. */ + return; + } + if (params.other_socket().type == SOCK_GEOMETRY) { + params.add_item(IFACE_("Geometry"), [set_active_fn](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("GeometryNodeViewer"); + params.connect_available_socket(node, "Geometry"); + set_active_fn(params, node); + }); + } + if (type && + ELEM(type, CD_PROP_FLOAT, CD_PROP_BOOL, CD_PROP_INT32, CD_PROP_FLOAT3, CD_PROP_COLOR)) { + params.add_item(IFACE_("Value"), [type, set_active_fn](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("GeometryNodeViewer"); + node_storage(node).data_type = *type; + params.update_and_connect_available_socket(node, "Value"); + + /* If the source node has a geometry socket, connect it to the new viewer node as well. */ + LISTBASE_FOREACH (bNodeSocket *, socket, ¶ms.node.outputs) { + if (socket->type == SOCK_GEOMETRY && !(socket->flag & (SOCK_UNAVAIL | SOCK_HIDDEN))) { + nodeAddLink(¶ms.node_tree, + ¶ms.node, + socket, + &node, + static_cast<bNodeSocket *>(node.inputs.first)); + } + } + + set_active_fn(params, node); + }); + } +} + +} // namespace blender::nodes::node_geo_viewer_cc void register_node_type_geo_viewer() { + namespace file_ns = blender::nodes::node_geo_viewer_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT, 0); node_type_storage( &ntype, "NodeGeometryViewer", node_free_standard_storage, node_copy_standard_storage); - node_type_update(&ntype, blender::nodes::geo_node_viewer_update); - node_type_init(&ntype, blender::nodes::geo_node_viewer_init); - ntype.declare = blender::nodes::geo_node_viewer_declare; - ntype.draw_buttons_ex = blender::nodes::geo_node_viewer_layout; + node_type_update(&ntype, file_ns::node_update); + node_type_init(&ntype, file_ns::node_init); + ntype.declare = file_ns::node_declare; + ntype.draw_buttons_ex = file_ns::node_layout; + ntype.gather_link_search_ops = file_ns::node_gather_link_searches; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc index 99eeae370fe..0819b401941 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc @@ -35,26 +35,39 @@ #include "UI_interface.h" #include "UI_resources.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_volume_to_mesh_cc { -static void geo_node_volume_to_mesh_declare(NodeDeclarationBuilder &b) +NODE_STORAGE_FUNCS(NodeGeometryVolumeToMesh) + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Volume")).supported_type(GEO_COMPONENT_TYPE_VOLUME); - b.add_input<decl::Float>(N_("Voxel Size")).default_value(0.3f).min(0.01f).subtype(PROP_DISTANCE); - b.add_input<decl::Float>(N_("Voxel Amount")).default_value(64.0f).min(0.0f); + b.add_input<decl::Float>(N_("Voxel Size")) + .default_value(0.3f) + .min(0.01f) + .subtype(PROP_DISTANCE) + .make_available([](bNode &node) { + node_storage(node).resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE; + }); + b.add_input<decl::Float>(N_("Voxel Amount")) + .default_value(64.0f) + .min(0.0f) + .make_available([](bNode &node) { + node_storage(node).resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT; + }); b.add_input<decl::Float>(N_("Threshold")).default_value(0.1f).min(0.0f); b.add_input<decl::Float>(N_("Adaptivity")).min(0.0f).max(1.0f).subtype(PROP_FACTOR); b.add_output<decl::Geometry>(N_("Mesh")); } -static void geo_node_volume_to_mesh_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); uiItemR(layout, ptr, "resolution_mode", 0, IFACE_("Resolution"), ICON_NONE); } -static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)MEM_callocN( sizeof(NodeGeometryVolumeToMesh), __func__); @@ -62,26 +75,26 @@ static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node) node->storage = data; } -static void geo_node_volume_to_mesh_update(bNodeTree *ntree, bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { - NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)node->storage; + const NodeGeometryVolumeToMesh &storage = 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 == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT); + storage.resolution_mode == + VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT); nodeSetSocketAvailability(ntree, voxel_size_socket, - data->resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE); + storage.resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE); } #ifdef WITH_OPENVDB static bke::VolumeToMeshResolution get_resolution_param(const GeoNodeExecParams ¶ms) { - const NodeGeometryVolumeToMesh &storage = - *(const NodeGeometryVolumeToMesh *)params.node().storage; + const NodeGeometryVolumeToMesh &storage = node_storage(params.node()); bke::VolumeToMeshResolution resolution; resolution.mode = (VolumeToMeshResolutionMode)storage.resolution_mode; @@ -176,7 +189,7 @@ static Mesh *create_mesh_from_volume(GeometrySet &geometry_set, GeoNodeExecParam #endif /* WITH_OPENVDB */ -static void geo_node_volume_to_mesh_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Volume"); @@ -194,20 +207,22 @@ static void geo_node_volume_to_mesh_exec(GeoNodeExecParams params) params.set_output("Mesh", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_volume_to_mesh_cc void register_node_type_geo_volume_to_mesh() { + namespace file_ns = blender::nodes::node_geo_volume_to_mesh_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_VOLUME_TO_MESH, "Volume to Mesh", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_volume_to_mesh_declare; + ntype.declare = file_ns::node_declare; node_type_storage( &ntype, "NodeGeometryVolumeToMesh", node_free_standard_storage, node_copy_standard_storage); node_type_size(&ntype, 170, 120, 700); - node_type_init(&ntype, blender::nodes::geo_node_volume_to_mesh_init); - node_type_update(&ntype, blender::nodes::geo_node_volume_to_mesh_update); - ntype.geometry_node_execute = blender::nodes::geo_node_volume_to_mesh_exec; - ntype.draw_buttons = blender::nodes::geo_node_volume_to_mesh_layout; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc index 8a9386c1137..dc223f07a26 100644 --- a/source/blender/nodes/intern/derived_node_tree.cc +++ b/source/blender/nodes/intern/derived_node_tree.cc @@ -20,10 +20,6 @@ namespace blender::nodes { -/* Construct a new derived node tree for a given root node tree. The generated derived node tree - * does not own the used node tree refs (so that those can be used by others as well). The caller - * has to make sure that the node tree refs added to #node_tree_refs live at least as long as the - * derived node tree. */ DerivedNodeTree::DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs) { /* Construct all possible contexts immediately. This is significantly cheaper than inlining all @@ -73,9 +69,6 @@ void DerivedNodeTree::destruct_context_recursively(DTreeContext *context) context->~DTreeContext(); } -/** - * \return True when there is a link cycle. Unavailable sockets are ignored. - */ bool DerivedNodeTree::has_link_cycles() const { for (const NodeTreeRef *tree_ref : used_node_tree_refs_) { @@ -96,7 +89,6 @@ bool DerivedNodeTree::has_undefined_nodes_or_sockets() const return false; } -/* Calls the given callback on all nodes in the (possibly nested) derived node tree. */ void DerivedNodeTree::foreach_node(FunctionRef<void(DNode)> callback) const { this->foreach_node_in_context_recursive(*root_context_, callback); @@ -168,7 +160,7 @@ DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const const DTreeContext *child_context = context_->child_context(socket_ref_->node()); if (child_context == nullptr) { - /* Can happen when the group node references a non-existant group (e.g. when the group is + /* Can happen when the group node references a non-existent group (e.g. when the group is * linked but the original file is not found). */ return {}; } @@ -184,9 +176,6 @@ DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const return {}; } -/* Call `origin_fn` for every "real" origin socket. "Real" means that reroutes, muted nodes - * and node groups are handled by this function. Origin sockets are ones where a node gets its - * inputs from. */ void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> origin_fn) const { BLI_assert(*this); @@ -233,9 +222,6 @@ void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> origin_fn) c } } -/* Calls `target_fn` for every "real" target socket. "Real" means that reroutes, muted nodes - * and node groups are handled by this function. Target sockets are on the nodes that use the value - * from this socket. */ void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn) const { TargetSocketPathInfo path_info; @@ -281,7 +267,6 @@ void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn, mute_output.foreach_target_socket(target_fn, path_info); path_info.sockets.pop_last(); path_info.sockets.pop_last(); - break; } } else if (linked_node->is_group_output_node()) { @@ -343,7 +328,6 @@ static dot::Cluster *get_dot_cluster_for_context( }); } -/* Generates a graph in dot format. The generated graph has all node groups inlined. */ std::string DerivedNodeTree::to_dot() const { dot::DirectedGraph digraph; diff --git a/source/blender/nodes/intern/extern_implementations.cc b/source/blender/nodes/intern/extern_implementations.cc deleted file mode 100644 index 35de319f20b..00000000000 --- a/source/blender/nodes/intern/extern_implementations.cc +++ /dev/null @@ -1,35 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "NOD_socket_declarations.hh" -#include "NOD_socket_declarations_geometry.hh" - -namespace blender::nodes { -#define MAKE_EXTERN_SOCKET_IMPLEMENTATION(TYPE) \ - template class SocketDeclarationBuilder<TYPE>; \ - template TYPE::Builder &NodeDeclarationBuilder::add_input<TYPE>(StringRef, StringRef); \ - template TYPE::Builder &NodeDeclarationBuilder::add_output<TYPE>(StringRef, StringRef); - -MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::Float) -MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::Int) -MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::Vector) -MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::Bool) -MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::Color) -MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::String) -MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::Geometry) - -#undef MAKE_EXTERN_SOCKET_IMPLEMENTATION -} // namespace blender::nodes diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc index ddd3c991518..e33f6cf345d 100644 --- a/source/blender/nodes/intern/geometry_nodes_eval_log.cc +++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc @@ -25,12 +25,15 @@ #include "BLT_translation.h" +#include <chrono> + namespace blender::nodes::geometry_nodes_eval_log { using fn::CPPType; using fn::FieldCPPType; using fn::FieldInput; using fn::GField; +using fn::ValueOrFieldCPPType; ModifierLog::ModifierLog(GeoLogger &logger) : input_geometry_log_(std::move(logger.input_geometry_log_)), @@ -63,6 +66,17 @@ ModifierLog::ModifierLog(GeoLogger &logger) node_with_warning.node); node_log.warnings_.append(node_with_warning.warning); } + + for (NodeWithExecutionTime &node_with_exec_time : local_logger.node_exec_times_) { + NodeLog &node_log = this->lookup_or_add_node_log(log_by_tree_context, + node_with_exec_time.node); + node_log.exec_time_ = node_with_exec_time.exec_time; + } + + for (NodeWithDebugMessage &debug_message : local_logger.node_debug_messages_) { + NodeLog &node_log = this->lookup_or_add_node_log(log_by_tree_context, debug_message.node); + node_log.debug_messages_.append(debug_message.message); + } } } @@ -177,12 +191,14 @@ const SocketLog *NodeLog::lookup_socket_log(const bNode &node, const bNodeSocket GFieldValueLog::GFieldValueLog(fn::GField field, bool log_full_field) : type_(field.cpp_type()) { - Set<std::reference_wrapper<const FieldInput>> field_inputs_set; - field.node().foreach_field_input( - [&](const FieldInput &field_input) { field_inputs_set.add(field_input); }); + const std::shared_ptr<const fn::FieldInputs> &field_input_nodes = field.node().field_inputs(); + /* Put the deduplicated field inputs into a vector so that they can be sorted below. */ Vector<std::reference_wrapper<const FieldInput>> field_inputs; - field_inputs.extend(field_inputs_set.begin(), field_inputs_set.end()); + if (field_input_nodes) { + field_inputs.extend(field_input_nodes->deduplicated_nodes.begin(), + field_input_nodes->deduplicated_nodes.end()); + } std::sort( field_inputs.begin(), field_inputs.end(), [](const FieldInput &a, const FieldInput &b) { @@ -417,25 +433,38 @@ void LocalGeoLogger::log_value_for_sockets(Span<DSocket> sockets, GPointer value geometry_set, log_full_geometry); values_.append({copied_sockets, std::move(value_log)}); } - else if (const FieldCPPType *field_type = dynamic_cast<const FieldCPPType *>(&type)) { - GField field = field_type->get_gfield(value.get()); - bool log_full_field = false; - if (!field.node().depends_on_input()) { - /* Always log constant fields so that their value can be shown in socket inspection. - * In the future we can also evaluate the field here and only store the value. */ - log_full_field = true; - } - if (!log_full_field) { - for (const DSocket &socket : sockets) { - if (main_logger_->log_full_sockets_.contains(socket)) { - log_full_field = true; - break; + else if (const ValueOrFieldCPPType *value_or_field_type = + dynamic_cast<const ValueOrFieldCPPType *>(&type)) { + const void *value_or_field = value.get(); + if (value_or_field_type->is_field(value_or_field)) { + GField field = *value_or_field_type->get_field_ptr(value_or_field); + bool log_full_field = false; + if (!field.node().depends_on_input()) { + /* Always log constant fields so that their value can be shown in socket inspection. + * In the future we can also evaluate the field here and only store the value. */ + log_full_field = true; + } + if (!log_full_field) { + for (const DSocket &socket : sockets) { + if (main_logger_->log_full_sockets_.contains(socket)) { + log_full_field = true; + break; + } } } + destruct_ptr<GFieldValueLog> value_log = allocator_->construct<GFieldValueLog>( + std::move(field), log_full_field); + values_.append({copied_sockets, std::move(value_log)}); + } + else { + const CPPType &base_type = value_or_field_type->base_type(); + const void *value = value_or_field_type->get_value_ptr(value_or_field); + void *buffer = allocator_->allocate(base_type.size(), base_type.alignment()); + base_type.copy_construct(value, buffer); + destruct_ptr<GenericValueLog> value_log = allocator_->construct<GenericValueLog>( + GMutablePointer{base_type, buffer}); + values_.append({copied_sockets, std::move(value_log)}); } - destruct_ptr<GFieldValueLog> value_log = allocator_->construct<GFieldValueLog>( - std::move(field), log_full_field); - values_.append({copied_sockets, std::move(value_log)}); } else { void *buffer = allocator_->allocate(type.size(), type.alignment()); @@ -457,4 +486,14 @@ void LocalGeoLogger::log_node_warning(DNode node, NodeWarningType type, std::str node_warnings_.append({node, {type, std::move(message)}}); } +void LocalGeoLogger::log_execution_time(DNode node, std::chrono::microseconds exec_time) +{ + node_exec_times_.append({node, exec_time}); +} + +void LocalGeoLogger::log_debug_message(DNode node, std::string message) +{ + node_debug_messages_.append({node, std::move(message)}); +} + } // namespace blender::nodes::geometry_nodes_eval_log diff --git a/source/blender/nodes/intern/math_functions.cc b/source/blender/nodes/intern/math_functions.cc index aa23777b664..00f4f2a3405 100644 --- a/source/blender/nodes/intern/math_functions.cc +++ b/source/blender/nodes/intern/math_functions.cc @@ -127,17 +127,17 @@ const FloatMathOperationInfo *get_float_compare_operation_info(const int operati ((void)0) switch (operation) { - case NODE_FLOAT_COMPARE_LESS_THAN: + case NODE_COMPARE_LESS_THAN: RETURN_OPERATION_INFO("Less Than", "math_less_than"); - case NODE_FLOAT_COMPARE_LESS_EQUAL: + case NODE_COMPARE_LESS_EQUAL: RETURN_OPERATION_INFO("Less Than or Equal", "math_less_equal"); - case NODE_FLOAT_COMPARE_GREATER_THAN: + case NODE_COMPARE_GREATER_THAN: RETURN_OPERATION_INFO("Greater Than", "math_greater_than"); - case NODE_FLOAT_COMPARE_GREATER_EQUAL: + case NODE_COMPARE_GREATER_EQUAL: RETURN_OPERATION_INFO("Greater Than or Equal", "math_greater_equal"); - case NODE_FLOAT_COMPARE_EQUAL: + case NODE_COMPARE_EQUAL: RETURN_OPERATION_INFO("Equal", "math_equal"); - case NODE_FLOAT_COMPARE_NOT_EQUAL: + case NODE_COMPARE_NOT_EQUAL: RETURN_OPERATION_INFO("Not Equal", "math_not_equal"); } diff --git a/source/blender/nodes/intern/node_common.cc b/source/blender/nodes/intern/node_common.cc index b80cedc9352..c302b1081af 100644 --- a/source/blender/nodes/intern/node_common.cc +++ b/source/blender/nodes/intern/node_common.cc @@ -32,6 +32,7 @@ #include "BLI_set.hh" #include "BLI_stack.hh" #include "BLI_string.h" +#include "BLI_string_ref.hh" #include "BLI_utildefines.h" #include "BLT_translation.h" @@ -50,33 +51,33 @@ using blender::Map; using blender::MultiValueMap; using blender::Set; using blender::Stack; +using blender::StringRef; /* -------------------------------------------------------------------- */ /** \name Node Group * \{ */ -bNodeSocket *node_group_find_input_socket(bNode *groupnode, const char *identifier) +static bNodeSocket *find_matching_socket(ListBase &sockets, StringRef identifier) { - LISTBASE_FOREACH (bNodeSocket *, sock, &groupnode->inputs) { - if (STREQ(sock->identifier, identifier)) { - return sock; + LISTBASE_FOREACH (bNodeSocket *, socket, &sockets) { + if (socket->identifier == identifier) { + return socket; } } return nullptr; } +bNodeSocket *node_group_find_input_socket(bNode *groupnode, const char *identifier) +{ + return find_matching_socket(groupnode->inputs, identifier); +} + bNodeSocket *node_group_find_output_socket(bNode *groupnode, const char *identifier) { - LISTBASE_FOREACH (bNodeSocket *, sock, &groupnode->outputs) { - if (STREQ(sock->identifier, identifier)) { - return sock; - } - } - return nullptr; + return find_matching_socket(groupnode->outputs, identifier); } -/* groups display their internal tree name as label */ -void node_group_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen) +void node_group_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen) { BLI_strncpy(label, (node->id) ? node->id->name + 2 : IFACE_("Missing Data-Block"), maxlen); } @@ -107,7 +108,7 @@ bool nodeGroupPoll(bNodeTree *nodetree, bNodeTree *grouptree, const char **r_dis } if (nodetree == grouptree) { - *r_disabled_hint = "Nesting a node group inside of itself is not allowed"; + *r_disabled_hint = TIP_("Nesting a node group inside of itself is not allowed"); return false; } @@ -121,83 +122,84 @@ bool nodeGroupPoll(bNodeTree *nodetree, bNodeTree *grouptree, const char **r_dis return valid; } -/* used for both group nodes and interface nodes */ -static bNodeSocket *group_verify_socket(bNodeTree *ntree, - bNode *gnode, - bNodeSocket *iosock, - ListBase *verify_lb, - eNodeSocketInOut in_out) +static void add_new_socket_from_interface(bNodeTree &node_tree, + bNode &node, + const bNodeSocket &interface_socket, + const eNodeSocketInOut in_out) { - bNodeSocket *sock; + bNodeSocket *socket = nodeAddSocket(&node_tree, + &node, + in_out, + interface_socket.idname, + interface_socket.identifier, + interface_socket.name); - for (sock = (bNodeSocket *)verify_lb->first; sock; sock = sock->next) { - if (STREQ(sock->identifier, iosock->identifier)) { - break; - } + if (interface_socket.typeinfo->interface_init_socket) { + interface_socket.typeinfo->interface_init_socket( + &node_tree, &interface_socket, &node, socket, "interface"); } - if (sock) { - strcpy(sock->name, iosock->name); +} - const int mask = SOCK_HIDE_VALUE; - sock->flag = (sock->flag & ~mask) | (iosock->flag & mask); +static void update_socket_to_match_interface(bNodeTree &node_tree, + bNode &node, + bNodeSocket &socket_to_update, + const bNodeSocket &interface_socket) +{ + strcpy(socket_to_update.name, interface_socket.name); - /* Update socket type if necessary */ - if (sock->typeinfo != iosock->typeinfo) { - nodeModifySocketType(ntree, gnode, sock, iosock->idname); - /* Flag the tree to make sure link validity is updated after type changes. */ - ntree->update |= NTREE_UPDATE_LINKS; - } + const int mask = SOCK_HIDE_VALUE; + socket_to_update.flag = (socket_to_update.flag & ~mask) | (interface_socket.flag & mask); - if (iosock->typeinfo->interface_verify_socket) { - iosock->typeinfo->interface_verify_socket(ntree, iosock, gnode, sock, "interface"); - } + /* Update socket type if necessary */ + if (socket_to_update.typeinfo != interface_socket.typeinfo) { + nodeModifySocketType(&node_tree, &node, &socket_to_update, interface_socket.idname); + /* Flag the tree to make sure link validity is updated after type changes. */ + node_tree.update |= NTREE_UPDATE_LINKS; } - else { - sock = nodeAddSocket(ntree, gnode, in_out, iosock->idname, iosock->identifier, iosock->name); - if (iosock->typeinfo->interface_init_socket) { - iosock->typeinfo->interface_init_socket(ntree, iosock, gnode, sock, "interface"); - } + if (interface_socket.typeinfo->interface_verify_socket) { + interface_socket.typeinfo->interface_verify_socket( + &node_tree, &interface_socket, &node, &socket_to_update, "interface"); } - - /* remove from list temporarily, to distinguish from orphaned sockets */ - BLI_remlink(verify_lb, sock); - - return sock; } -/* used for both group nodes and interface nodes */ -static void group_verify_socket_list(bNodeTree *ntree, - bNode *gnode, - ListBase *iosock_lb, - ListBase *verify_lb, - eNodeSocketInOut in_out) +/** + * Used for group nodes and group input/output nodes to update the list of input or output sockets + * on a node to match the provided interface. Assumes that \a verify_lb is the node's matching + * input or output socket list, depending on whether the node is a group input/output or a group + * node. + */ +static void group_verify_socket_list(bNodeTree &node_tree, + bNode &node, + const ListBase &interface_sockets, + ListBase &verify_lb, + const eNodeSocketInOut in_out) { - bNodeSocket *sock, *nextsock; - - /* step by step compare */ - - bNodeSocket *iosock = (bNodeSocket *)iosock_lb->first; - for (; iosock; iosock = iosock->next) { - /* abusing new_sock pointer for verification here! only used inside this function */ - iosock->new_sock = group_verify_socket(ntree, gnode, iosock, verify_lb, in_out); - } - /* leftovers are removed */ - for (sock = (bNodeSocket *)verify_lb->first; sock; sock = nextsock) { - nextsock = sock->next; - nodeRemoveSocket(ntree, gnode, sock); - } - /* and we put back the verified sockets */ - iosock = (bNodeSocket *)iosock_lb->first; - for (; iosock; iosock = iosock->next) { - if (iosock->new_sock) { - BLI_addtail(verify_lb, iosock->new_sock); - iosock->new_sock = nullptr; + ListBase old_sockets = verify_lb; + BLI_listbase_clear(&verify_lb); + + LISTBASE_FOREACH (const bNodeSocket *, interface_socket, &interface_sockets) { + bNodeSocket *matching_socket = find_matching_socket(old_sockets, interface_socket->identifier); + if (matching_socket) { + /* If a socket with the same identifier exists in the previous socket list, update it + * with the correct name, type, etc. Then move it from the old list to the new one. */ + update_socket_to_match_interface(node_tree, node, *matching_socket, *interface_socket); + BLI_remlink(&old_sockets, matching_socket); + BLI_addtail(&verify_lb, matching_socket); + } + else { + /* If there was no socket withe the same identifier already, simply create a new socket + * based on the interface socket, which will already add it to the new list. */ + add_new_socket_from_interface(node_tree, node, *interface_socket, in_out); } } + + /* Remove leftover sockets that didn't match the node group's interface. */ + LISTBASE_FOREACH_MUTABLE (bNodeSocket *, unused_socket, &old_sockets) { + nodeRemoveSocket(&node_tree, &node, unused_socket); + } } -/* make sure all group node in ntree, which use ngroup, are sync'd */ void node_group_update(struct bNodeTree *ntree, struct bNode *node) { /* check inputs and outputs, and remove or insert them */ @@ -210,8 +212,8 @@ void node_group_update(struct bNodeTree *ntree, struct bNode *node) } else { bNodeTree *ngroup = (bNodeTree *)node->id; - group_verify_socket_list(ntree, node, &ngroup->inputs, &node->inputs, SOCK_IN); - group_verify_socket_list(ntree, node, &ngroup->outputs, &node->outputs, SOCK_OUT); + group_verify_socket_list(*ntree, *node, ngroup->inputs, node->inputs, SOCK_IN); + group_verify_socket_list(*ntree, *node, ngroup->outputs, node->outputs, SOCK_OUT); } } @@ -305,9 +307,6 @@ static void propagate_reroute_type_from_start_socket( } } -/* Global update function for Reroute node types. - * This depends on connected nodes, so must be done as a tree-wide update. - */ void ntree_update_reroute_nodes(bNodeTree *ntree) { /* Contains nodes that are linked to at least one reroute node. */ @@ -497,7 +496,7 @@ void node_group_input_update(bNodeTree *ntree, bNode *node) /* check inputs and outputs, and remove or insert them */ { /* value_in_out inverted for interface nodes to get correct socket value_property */ - group_verify_socket_list(ntree, node, &ntree->inputs, &node->outputs, SOCK_OUT); + group_verify_socket_list(*ntree, *node, ntree->inputs, node->outputs, SOCK_OUT); /* add virtual extension socket */ nodeAddSocket(ntree, node, SOCK_OUT, "NodeSocketVirtual", "__extend__", ""); @@ -595,7 +594,7 @@ void node_group_output_update(bNodeTree *ntree, bNode *node) /* check inputs and outputs, and remove or insert them */ { /* value_in_out inverted for interface nodes to get correct socket value_property */ - group_verify_socket_list(ntree, node, &ntree->outputs, &node->inputs, SOCK_IN); + group_verify_socket_list(*ntree, *node, ntree->outputs, node->inputs, SOCK_IN); /* add virtual extension socket */ nodeAddSocket(ntree, node, SOCK_IN, "NodeSocketVirtual", "__extend__", ""); @@ -613,6 +612,8 @@ void register_node_type_group_output(void) node_type_init(ntype, node_group_output_init); node_type_update(ntype, node_group_output_update); + ntype->no_muting = true; + nodeRegisterType(ntype); } diff --git a/source/blender/nodes/intern/node_common.h b/source/blender/nodes/intern/node_common.h index cdb7b6897b9..0d1b51224e6 100644 --- a/source/blender/nodes/intern/node_common.h +++ b/source/blender/nodes/intern/node_common.h @@ -31,11 +31,19 @@ extern "C" { struct bNodeTree; -void node_group_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); +/** Groups display their internal tree name as label. */ +void node_group_label(const struct bNodeTree *ntree, + const struct bNode *node, + char *label, + int maxlen); bool node_group_poll_instance(struct bNode *node, struct bNodeTree *nodetree, const char **r_disabled_hint); +/** + * Global update function for Reroute node types. + * This depends on connected nodes, so must be done as a tree-wide update. + */ void ntree_update_reroute_nodes(struct bNodeTree *ntree); #ifdef __cplusplus diff --git a/source/blender/nodes/intern/node_declaration.cc b/source/blender/nodes/intern/node_declaration.cc index e804d10ad75..75d47cfd386 100644 --- a/source/blender/nodes/intern/node_declaration.cc +++ b/source/blender/nodes/intern/node_declaration.cc @@ -51,11 +51,14 @@ bNodeSocket &SocketDeclaration::update_or_build(bNodeTree &ntree, bNodeSocket &socket) const { /* By default just rebuild. */ - return this->build(ntree, node, (eNodeSocketInOut)socket.in_out); + BLI_assert(socket.in_out == in_out_); + UNUSED_VARS_NDEBUG(socket); + return this->build(ntree, node); } void SocketDeclaration::set_common_flags(bNodeSocket &socket) const { + SET_FLAG_FROM_TEST(socket.flag, compact_, SOCK_COMPACT); SET_FLAG_FROM_TEST(socket.flag, hide_value_, SOCK_HIDE_VALUE); SET_FLAG_FROM_TEST(socket.flag, hide_label_, SOCK_HIDE_LABEL); SET_FLAG_FROM_TEST(socket.flag, is_multi_input_, SOCK_MULTI_INPUT); @@ -70,6 +73,9 @@ bool SocketDeclaration::matches_common_data(const bNodeSocket &socket) const if (socket.identifier != identifier_) { return false; } + if (((socket.flag & SOCK_COMPACT) != 0) != compact_) { + return false; + } if (((socket.flag & SOCK_HIDE_VALUE) != 0) != hide_value_) { return false; } diff --git a/source/blender/nodes/intern/node_exec.cc b/source/blender/nodes/intern/node_exec.cc index 18403417af3..95070bf735e 100644 --- a/source/blender/nodes/intern/node_exec.cc +++ b/source/blender/nodes/intern/node_exec.cc @@ -34,14 +34,12 @@ #include "node_exec.h" #include "node_util.h" -/* supported socket types in old nodes */ int node_exec_socket_use_stack(bNodeSocket *sock) { /* NOTE: INT supported as FLOAT. Only for EEVEE. */ return ELEM(sock->type, SOCK_INT, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_SHADER); } -/* for a given socket, find the actual stack entry */ bNodeStack *node_get_socket_stack(bNodeStack *stack, bNodeSocket *sock) { if (stack && sock && sock->stack_index >= 0) { diff --git a/source/blender/nodes/intern/node_exec.h b/source/blender/nodes/intern/node_exec.h index de7cbb8cedb..b2e1c6564b6 100644 --- a/source/blender/nodes/intern/node_exec.h +++ b/source/blender/nodes/intern/node_exec.h @@ -71,8 +71,10 @@ typedef struct bNodeThreadStack { bool used; } bNodeThreadStack; +/** Supported socket types in old nodes. */ int node_exec_socket_use_stack(struct bNodeSocket *sock); +/** For a given socket, find the actual stack entry. */ struct bNodeStack *node_get_socket_stack(struct bNodeStack *stack, struct bNodeSocket *sock); void node_get_stack(struct bNode *node, struct bNodeStack *stack, diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc index faa4337ba7e..b5c4e71df74 100644 --- a/source/blender/nodes/intern/node_geometry_exec.cc +++ b/source/blender/nodes/intern/node_geometry_exec.cc @@ -18,8 +18,9 @@ #include "DEG_depsgraph_query.h" +#include "BKE_type_conversions.hh" + #include "NOD_geometry_exec.hh" -#include "NOD_type_conversions.hh" #include "node_geometry_util.hh" @@ -149,7 +150,7 @@ GVArray GeoNodeExecParams::get_input_attribute(const StringRef name, } return GVArray::ForSingle(*cpp_type, domain_size, default_value); } - const DataTypeConversions &conversions = get_implicit_type_conversions(); + const bke::DataTypeConversions &conversions = bke::get_implicit_type_conversions(); if (found_socket->type == SOCK_FLOAT) { const float value = this->get_input<float>(found_socket->identifier); BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer); @@ -215,11 +216,6 @@ CustomDataType GeoNodeExecParams::get_input_attribute_data_type( return default_type; } -/** - * If any of the corresponding input sockets are attributes instead of single values, - * use the highest priority attribute domain from among them. - * Otherwise return the default domain. - */ AttributeDomain GeoNodeExecParams::get_highest_priority_input_domain( Span<std::string> names, const GeometryComponent &component, @@ -254,6 +250,11 @@ std::string GeoNodeExecParams::attribute_producer_name() const return provider_->dnode->label_or_name() + TIP_(" node"); } +void GeoNodeExecParams::set_default_remaining_outputs() +{ + provider_->set_default_remaining_outputs(); +} + void GeoNodeExecParams::check_input_access(StringRef identifier, const CPPType *requested_type) const { @@ -288,7 +289,7 @@ void GeoNodeExecParams::check_input_access(StringRef identifier, BLI_assert_unreachable(); } else if (requested_type != nullptr) { - const CPPType &expected_type = *found_socket->typeinfo->get_geometry_nodes_cpp_type(); + const CPPType &expected_type = *found_socket->typeinfo->geometry_nodes_cpp_type; if (*requested_type != expected_type) { std::cout << "The requested type '" << requested_type->name() << "' is incorrect. Expected '" << expected_type.name() << "'.\n"; @@ -328,7 +329,7 @@ void GeoNodeExecParams::check_output_access(StringRef identifier, const CPPType BLI_assert_unreachable(); } else { - const CPPType &expected_type = *found_socket->typeinfo->get_geometry_nodes_cpp_type(); + const CPPType &expected_type = *found_socket->typeinfo->geometry_nodes_cpp_type; if (value_type != expected_type) { std::cout << "The value type '" << value_type.name() << "' is incorrect. Expected '" << expected_type.name() << "'.\n"; diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc index dce54d58dce..d83c05b38a1 100644 --- a/source/blender/nodes/intern/node_socket.cc +++ b/source/blender/nodes/intern/node_socket.cc @@ -28,7 +28,6 @@ #include "BLI_color.hh" #include "BLI_float3.hh" #include "BLI_listbase.h" -#include "BLI_math.h" #include "BLI_string.h" #include "BLI_utildefines.h" @@ -51,6 +50,7 @@ #include "FN_field.hh" using namespace blender; +using blender::fn::ValueOrField; using blender::nodes::SocketDeclarationPtr; struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, @@ -191,7 +191,6 @@ static void refresh_socket_list(bNodeTree &ntree, bNode &node, ListBase &sockets, Span<SocketDeclarationPtr> socket_decls, - const eNodeSocketInOut in_out, const bool do_id_user) { Vector<bNodeSocket *> old_sockets = sockets; @@ -210,7 +209,7 @@ static void refresh_socket_list(bNodeTree &ntree, bNodeSocket *new_socket = nullptr; if (old_socket_with_same_identifier == nullptr) { /* Create a completely new socket. */ - new_socket = &socket_decl->build(ntree, node, in_out); + new_socket = &socket_decl->build(ntree, node); } else { STRNCPY(old_socket_with_same_identifier->name, socket_decl->name().c_str()); @@ -258,8 +257,8 @@ static void refresh_node(bNodeTree &ntree, blender::nodes::NodeDeclaration &node_decl, bool do_id_user) { - refresh_socket_list(ntree, node, node.inputs, node_decl.inputs(), SOCK_IN, do_id_user); - refresh_socket_list(ntree, node, node.outputs, node_decl.outputs(), SOCK_OUT, do_id_user); + refresh_socket_list(ntree, node, node.inputs, node_decl.inputs(), do_id_user); + refresh_socket_list(ntree, node, node.outputs, node_decl.outputs(), do_id_user); } void node_verify_sockets(bNodeTree *ntree, bNode *node, bool do_id_user) @@ -548,7 +547,7 @@ void node_socket_skip_reroutes( } static void standard_node_socket_interface_init_socket(bNodeTree *UNUSED(ntree), - bNodeSocket *stemp, + const bNodeSocket *interface_socket, bNode *UNUSED(node), bNodeSocket *sock, const char *UNUSED(data_path)) @@ -559,47 +558,50 @@ static void standard_node_socket_interface_init_socket(bNodeTree *UNUSED(ntree), /* XXX socket interface 'type' value is not used really, * but has to match or the copy function will bail out */ - stemp->type = stemp->typeinfo->type; + const_cast<bNodeSocket *>(interface_socket)->type = interface_socket->typeinfo->type; /* copy default_value settings */ - node_socket_copy_default_value(sock, stemp); + node_socket_copy_default_value(sock, interface_socket); } /* copies settings that are not changed for each socket instance */ static void standard_node_socket_interface_verify_socket(bNodeTree *UNUSED(ntree), - bNodeSocket *stemp, + const bNodeSocket *interface_socket, bNode *UNUSED(node), bNodeSocket *sock, const char *UNUSED(data_path)) { /* sanity check */ - if (sock->type != stemp->typeinfo->type) { + if (sock->type != interface_socket->typeinfo->type) { return; } /* make sure both exist */ - if (!stemp->default_value) { + if (!interface_socket->default_value) { return; } node_socket_init_default_value(sock); - switch (stemp->typeinfo->type) { + switch (interface_socket->typeinfo->type) { case SOCK_FLOAT: { bNodeSocketValueFloat *toval = (bNodeSocketValueFloat *)sock->default_value; - bNodeSocketValueFloat *fromval = (bNodeSocketValueFloat *)stemp->default_value; + const bNodeSocketValueFloat *fromval = (const bNodeSocketValueFloat *) + interface_socket->default_value; toval->min = fromval->min; toval->max = fromval->max; break; } case SOCK_INT: { bNodeSocketValueInt *toval = (bNodeSocketValueInt *)sock->default_value; - bNodeSocketValueInt *fromval = (bNodeSocketValueInt *)stemp->default_value; + const bNodeSocketValueInt *fromval = (const bNodeSocketValueInt *) + interface_socket->default_value; toval->min = fromval->min; toval->max = fromval->max; break; } case SOCK_VECTOR: { bNodeSocketValueVector *toval = (bNodeSocketValueVector *)sock->default_value; - bNodeSocketValueVector *fromval = (bNodeSocketValueVector *)stemp->default_value; + const bNodeSocketValueVector *fromval = (const bNodeSocketValueVector *) + interface_socket->default_value; toval->min = fromval->min; toval->max = fromval->max; break; @@ -697,17 +699,15 @@ static bNodeSocketType *make_socket_type_virtual() static bNodeSocketType *make_socket_type_bool() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_BOOLEAN, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<bool>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<bool>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(bool *)r_value = ((bNodeSocketValueBoolean *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<bool>>(); - }; + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<bool>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { bool value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<bool>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<bool>(value); }; return socktype; } @@ -715,17 +715,15 @@ static bNodeSocketType *make_socket_type_bool() static bNodeSocketType *make_socket_type_float(PropertySubType subtype) { bNodeSocketType *socktype = make_standard_socket_type(SOCK_FLOAT, subtype); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<float>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<float>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(float *)r_value = ((bNodeSocketValueFloat *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<float>>(); - }; + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<float>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { float value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<float>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<float>(value); }; return socktype; } @@ -733,17 +731,15 @@ static bNodeSocketType *make_socket_type_float(PropertySubType subtype) static bNodeSocketType *make_socket_type_int(PropertySubType subtype) { bNodeSocketType *socktype = make_standard_socket_type(SOCK_INT, subtype); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<int>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<int>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(int *)r_value = ((bNodeSocketValueInt *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<int>>(); - }; + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<int>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { int value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<int>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<int>(value); }; return socktype; } @@ -751,17 +747,15 @@ static bNodeSocketType *make_socket_type_int(PropertySubType subtype) static bNodeSocketType *make_socket_type_vector(PropertySubType subtype) { bNodeSocketType *socktype = make_standard_socket_type(SOCK_VECTOR, subtype); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<blender::float3>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<blender::float3>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(blender::float3 *)r_value = ((bNodeSocketValueVector *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<blender::float3>>(); - }; + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<blender::float3>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { blender::float3 value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<blender::float3>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<blender::float3>(value); }; return socktype; } @@ -769,20 +763,16 @@ static bNodeSocketType *make_socket_type_vector(PropertySubType subtype) static bNodeSocketType *make_socket_type_rgba() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_RGBA, PROP_NONE); - socktype->get_base_cpp_type = []() { - return &blender::fn::CPPType::get<blender::ColorGeometry4f>(); - }; + socktype->base_cpp_type = &blender::fn::CPPType::get<blender::ColorGeometry4f>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(blender::ColorGeometry4f *)r_value = ((bNodeSocketValueRGBA *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<blender::ColorGeometry4f>>(); - }; + socktype->geometry_nodes_cpp_type = + &blender::fn::CPPType::get<ValueOrField<blender::ColorGeometry4f>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { blender::ColorGeometry4f value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) - blender::fn::Field<blender::ColorGeometry4f>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<blender::ColorGeometry4f>(value); }; return socktype; } @@ -790,18 +780,16 @@ static bNodeSocketType *make_socket_type_rgba() static bNodeSocketType *make_socket_type_string() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_STRING, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<std::string>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<std::string>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { new (r_value) std::string(((bNodeSocketValueString *)socket.default_value)->value); }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<std::string>>(); - }; + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<std::string>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { std::string value; value.~basic_string(); socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<std::string>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<std::string>(value); }; return socktype; } @@ -815,11 +803,11 @@ MAKE_CPP_TYPE(Material, Material *, CPPTypeFlags::BasicType) static bNodeSocketType *make_socket_type_object() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_OBJECT, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Object *>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<Object *>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Object **)r_value = ((bNodeSocketValueObject *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } @@ -827,11 +815,11 @@ static bNodeSocketType *make_socket_type_object() static bNodeSocketType *make_socket_type_geometry() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_GEOMETRY, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<GeometrySet>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<GeometrySet>(); socktype->get_base_cpp_value = [](const bNodeSocket &UNUSED(socket), void *r_value) { new (r_value) GeometrySet(); }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } @@ -839,11 +827,11 @@ static bNodeSocketType *make_socket_type_geometry() static bNodeSocketType *make_socket_type_collection() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_COLLECTION, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Collection *>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<Collection *>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Collection **)r_value = ((bNodeSocketValueCollection *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } @@ -851,11 +839,11 @@ static bNodeSocketType *make_socket_type_collection() static bNodeSocketType *make_socket_type_texture() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_TEXTURE, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Tex *>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<Tex *>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Tex **)r_value = ((bNodeSocketValueTexture *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } @@ -863,11 +851,11 @@ static bNodeSocketType *make_socket_type_texture() static bNodeSocketType *make_socket_type_image() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_IMAGE, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Image *>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<Image *>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Image **)r_value = ((bNodeSocketValueImage *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } @@ -875,11 +863,11 @@ static bNodeSocketType *make_socket_type_image() static bNodeSocketType *make_socket_type_material() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_MATERIAL, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Material *>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<Material *>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Material **)r_value = ((bNodeSocketValueMaterial *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } diff --git a/source/blender/nodes/intern/node_socket_declarations.cc b/source/blender/nodes/intern/node_socket_declarations.cc index ed5691ebf7f..4fef5b96e9f 100644 --- a/source/blender/nodes/intern/node_socket_declarations.cc +++ b/source/blender/nodes/intern/node_socket_declarations.cc @@ -23,6 +23,52 @@ namespace blender::nodes::decl { +/** + * \note This function only deals with declarations, not the field status of existing nodes. If the + * field status of existing nodes was stored on the sockets, an improvement would be to check the + * existing socket's current status instead of the declaration. + */ +static bool field_types_are_compatible(const SocketDeclaration &input, + const SocketDeclaration &output) +{ + if (output.output_field_dependency().field_type() == OutputSocketFieldType::FieldSource) { + if (input.input_field_type() == InputSocketFieldType::None) { + return false; + } + } + return true; +} + +static bool sockets_can_connect(const SocketDeclaration &socket_decl, + const bNodeSocket &other_socket) +{ + /* Input sockets cannot connect to input sockets, outputs cannot connect to outputs. */ + if (socket_decl.in_out() == other_socket.in_out) { + return false; + } + + if (other_socket.declaration) { + if (socket_decl.in_out() == SOCK_IN) { + if (!field_types_are_compatible(socket_decl, *other_socket.declaration)) { + return false; + } + } + else { + if (!field_types_are_compatible(*other_socket.declaration, socket_decl)) { + return false; + } + } + } + + return true; +} + +static bool basic_types_can_connect(const SocketDeclaration &UNUSED(socket_decl), + const bNodeSocket &other_socket) +{ + return ELEM(other_socket.type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA); +} + static void modify_subtype_except_for_storage(bNodeSocket &socket, int new_subtype) { const char *idname = nodeStaticSocketType(socket.type, new_subtype); @@ -35,10 +81,10 @@ static void modify_subtype_except_for_storage(bNodeSocket &socket, int new_subty /** \name #Float * \{ */ -bNodeSocket &Float::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const +bNodeSocket &Float::build(bNodeTree &ntree, bNode &node) const { bNodeSocket &socket = *nodeAddStaticSocket( - &ntree, &node, in_out, SOCK_FLOAT, subtype_, identifier_.c_str(), name_.c_str()); + &ntree, &node, in_out_, SOCK_FLOAT, subtype_, identifier_.c_str(), name_.c_str()); this->set_common_flags(socket); bNodeSocketValueFloat &value = *(bNodeSocketValueFloat *)socket.default_value; value.min = soft_min_value_; @@ -68,10 +114,19 @@ bool Float::matches(const bNodeSocket &socket) const return true; } +bool Float::can_connect(const bNodeSocket &socket) const +{ + if (!sockets_can_connect(*this, socket)) { + return false; + } + return basic_types_can_connect(*this, socket); +} + bNodeSocket &Float::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const { if (socket.type != SOCK_FLOAT) { - return this->build(ntree, node, (eNodeSocketInOut)socket.in_out); + BLI_assert(socket.in_out == in_out_); + return this->build(ntree, node); } if (socket.typeinfo->subtype != subtype_) { modify_subtype_except_for_storage(socket, subtype_); @@ -90,10 +145,10 @@ bNodeSocket &Float::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket & /** \name #Int * \{ */ -bNodeSocket &Int::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const +bNodeSocket &Int::build(bNodeTree &ntree, bNode &node) const { bNodeSocket &socket = *nodeAddStaticSocket( - &ntree, &node, in_out, SOCK_INT, subtype_, identifier_.c_str(), name_.c_str()); + &ntree, &node, in_out_, SOCK_INT, subtype_, identifier_.c_str(), name_.c_str()); this->set_common_flags(socket); bNodeSocketValueInt &value = *(bNodeSocketValueInt *)socket.default_value; value.min = soft_min_value_; @@ -123,10 +178,19 @@ bool Int::matches(const bNodeSocket &socket) const return true; } +bool Int::can_connect(const bNodeSocket &socket) const +{ + if (!sockets_can_connect(*this, socket)) { + return false; + } + return basic_types_can_connect(*this, socket); +} + bNodeSocket &Int::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const { if (socket.type != SOCK_INT) { - return this->build(ntree, node, (eNodeSocketInOut)socket.in_out); + BLI_assert(socket.in_out == in_out_); + return this->build(ntree, node); } if (socket.typeinfo->subtype != subtype_) { modify_subtype_except_for_storage(socket, subtype_); @@ -145,10 +209,10 @@ bNodeSocket &Int::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &so /** \name #Vector * \{ */ -bNodeSocket &Vector::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const +bNodeSocket &Vector::build(bNodeTree &ntree, bNode &node) const { bNodeSocket &socket = *nodeAddStaticSocket( - &ntree, &node, in_out, SOCK_VECTOR, subtype_, identifier_.c_str(), name_.c_str()); + &ntree, &node, in_out_, SOCK_VECTOR, subtype_, identifier_.c_str(), name_.c_str()); this->set_common_flags(socket); bNodeSocketValueVector &value = *(bNodeSocketValueVector *)socket.default_value; copy_v3_v3(value.value, default_value_); @@ -171,10 +235,19 @@ bool Vector::matches(const bNodeSocket &socket) const return true; } +bool Vector::can_connect(const bNodeSocket &socket) const +{ + if (!sockets_can_connect(*this, socket)) { + return false; + } + return basic_types_can_connect(*this, socket); +} + bNodeSocket &Vector::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const { if (socket.type != SOCK_VECTOR) { - return this->build(ntree, node, (eNodeSocketInOut)socket.in_out); + BLI_assert(socket.in_out == in_out_); + return this->build(ntree, node); } if (socket.typeinfo->subtype != subtype_) { modify_subtype_except_for_storage(socket, subtype_); @@ -192,10 +265,10 @@ bNodeSocket &Vector::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket /** \name #Bool * \{ */ -bNodeSocket &Bool::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const +bNodeSocket &Bool::build(bNodeTree &ntree, bNode &node) const { bNodeSocket &socket = *nodeAddStaticSocket( - &ntree, &node, in_out, SOCK_BOOLEAN, PROP_NONE, identifier_.c_str(), name_.c_str()); + &ntree, &node, in_out_, SOCK_BOOLEAN, PROP_NONE, identifier_.c_str(), name_.c_str()); this->set_common_flags(socket); bNodeSocketValueBoolean &value = *(bNodeSocketValueBoolean *)socket.default_value; value.value = default_value_; @@ -213,16 +286,24 @@ bool Bool::matches(const bNodeSocket &socket) const return true; } +bool Bool::can_connect(const bNodeSocket &socket) const +{ + if (!sockets_can_connect(*this, socket)) { + return false; + } + return basic_types_can_connect(*this, socket); +} + /** \} */ /* -------------------------------------------------------------------- */ /** \name #Color * \{ */ -bNodeSocket &Color::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const +bNodeSocket &Color::build(bNodeTree &ntree, bNode &node) const { bNodeSocket &socket = *nodeAddStaticSocket( - &ntree, &node, in_out, SOCK_RGBA, PROP_NONE, identifier_.c_str(), name_.c_str()); + &ntree, &node, in_out_, SOCK_RGBA, PROP_NONE, identifier_.c_str(), name_.c_str()); this->set_common_flags(socket); bNodeSocketValueRGBA &value = *(bNodeSocketValueRGBA *)socket.default_value; copy_v4_v4(value.value, default_value_); @@ -245,16 +326,24 @@ bool Color::matches(const bNodeSocket &socket) const return true; } +bool Color::can_connect(const bNodeSocket &socket) const +{ + if (!sockets_can_connect(*this, socket)) { + return false; + } + return basic_types_can_connect(*this, socket); +} + /** \} */ /* -------------------------------------------------------------------- */ /** \name #String * \{ */ -bNodeSocket &String::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const +bNodeSocket &String::build(bNodeTree &ntree, bNode &node) const { bNodeSocket &socket = *nodeAddStaticSocket( - &ntree, &node, in_out, SOCK_STRING, PROP_NONE, identifier_.c_str(), name_.c_str()); + &ntree, &node, in_out_, SOCK_STRING, PROP_NONE, identifier_.c_str(), name_.c_str()); STRNCPY(((bNodeSocketValueString *)socket.default_value)->value, default_value_.c_str()); this->set_common_flags(socket); return socket; @@ -271,18 +360,21 @@ bool String::matches(const bNodeSocket &socket) const return true; } +bool String::can_connect(const bNodeSocket &socket) const +{ + return sockets_can_connect(*this, socket) && socket.type == SOCK_STRING; +} + /** \} */ /* -------------------------------------------------------------------- */ /** \name #IDSocketDeclaration * \{ */ -bNodeSocket &IDSocketDeclaration::build(bNodeTree &ntree, - bNode &node, - eNodeSocketInOut in_out) const +bNodeSocket &IDSocketDeclaration::build(bNodeTree &ntree, bNode &node) const { bNodeSocket &socket = *nodeAddSocket( - &ntree, &node, in_out, idname_, identifier_.c_str(), name_.c_str()); + &ntree, &node, in_out_, idname_, identifier_.c_str(), name_.c_str()); this->set_common_flags(socket); return socket; } @@ -298,12 +390,18 @@ bool IDSocketDeclaration::matches(const bNodeSocket &socket) const return true; } +bool IDSocketDeclaration::can_connect(const bNodeSocket &socket) const +{ + return sockets_can_connect(*this, socket) && STREQ(socket.idname, idname_); +} + bNodeSocket &IDSocketDeclaration::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const { if (StringRef(socket.idname) != idname_) { - return this->build(ntree, node, (eNodeSocketInOut)socket.in_out); + BLI_assert(socket.in_out == in_out_); + return this->build(ntree, node); } this->set_common_flags(socket); return socket; @@ -315,10 +413,10 @@ bNodeSocket &IDSocketDeclaration::update_or_build(bNodeTree &ntree, /** \name #Geometry * \{ */ -bNodeSocket &Geometry::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const +bNodeSocket &Geometry::build(bNodeTree &ntree, bNode &node) const { bNodeSocket &socket = *nodeAddSocket( - &ntree, &node, in_out, "NodeSocketGeometry", identifier_.c_str(), name_.c_str()); + &ntree, &node, in_out_, "NodeSocketGeometry", identifier_.c_str(), name_.c_str()); this->set_common_flags(socket); return socket; } @@ -334,6 +432,11 @@ bool Geometry::matches(const bNodeSocket &socket) const return true; } +bool Geometry::can_connect(const bNodeSocket &socket) const +{ + return sockets_can_connect(*this, socket) && socket.type == SOCK_GEOMETRY; +} + Span<GeometryComponentType> Geometry::supported_types() const { return supported_types_; @@ -376,4 +479,41 @@ GeometryBuilder &GeometryBuilder::only_instances(bool value) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name #Shader + * \{ */ + +bNodeSocket &Shader::build(bNodeTree &ntree, bNode &node) const +{ + bNodeSocket &socket = *nodeAddSocket( + &ntree, &node, in_out_, "NodeSocketShader", identifier_.c_str(), name_.c_str()); + this->set_common_flags(socket); + return socket; +} + +bool Shader::matches(const bNodeSocket &socket) const +{ + if (!this->matches_common_data(socket)) { + return false; + } + if (socket.type != SOCK_SHADER) { + return false; + } + return true; +} + +bool Shader::can_connect(const bNodeSocket &socket) const +{ + if (!sockets_can_connect(*this, socket)) { + return false; + } + /* Basic types can convert to shaders, but not the other way around. */ + if (in_out_ == SOCK_IN) { + return ELEM(socket.type, SOCK_VECTOR, SOCK_RGBA, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN); + } + return socket.type == SOCK_SHADER; +} + +/** \} */ + } // namespace blender::nodes::decl diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc index 5481465aef6..912d5e5322c 100644 --- a/source/blender/nodes/intern/node_tree_ref.cc +++ b/source/blender/nodes/intern/node_tree_ref.cc @@ -262,7 +262,6 @@ void InputSocketRef::foreach_logical_origin( skipped_fn.call_safe(origin); skipped_fn.call_safe(mute_input); mute_input.foreach_logical_origin(origin_fn, skipped_fn, true, seen_sockets_stack); - break; } } } @@ -442,9 +441,6 @@ static bool has_link_cycles_recursive(const NodeRef &node, return false; } -/** - * \return True when there is a link cycle. Unavailable sockets are ignored. - */ bool NodeTreeRef::has_link_cycles() const { const int node_amount = nodes_by_id_.size(); @@ -571,10 +567,6 @@ static void toposort_from_start_node(const NodeTreeRef::ToposortDirection direct } } -/** - * Sort nodes topologically from left to right or right to left. - * In the future the result if this could be cached on #NodeTreeRef. - */ NodeTreeRef::ToposortResult NodeTreeRef::toposort(const ToposortDirection direction) const { ToposortResult result; diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c index 231030030eb..7620c8fa1a8 100644 --- a/source/blender/nodes/intern/node_util.c +++ b/source/blender/nodes/intern/node_util.c @@ -190,7 +190,7 @@ void node_math_update(bNodeTree *ntree, bNode *node) /** \name Labels * \{ */ -void node_blend_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen) +void node_blend_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen) { const char *name; bool enum_label = RNA_enum_name(rna_enum_ramp_blend_items, node->custom1, &name); @@ -200,14 +200,14 @@ void node_blend_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int ma BLI_strncpy(label, IFACE_(name), maxlen); } -void node_image_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen) +void node_image_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen) { /* If there is no loaded image, return an empty string, * and let nodeLabel() fill in the proper type translation. */ BLI_strncpy(label, (node->id) ? node->id->name + 2 : "", maxlen); } -void node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen) +void node_math_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen) { const char *name; bool enum_label = RNA_enum_name(rna_enum_node_math_items, node->custom1, &name); @@ -217,7 +217,10 @@ void node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int max BLI_strncpy(label, IFACE_(name), maxlen); } -void node_vector_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen) +void node_vector_math_label(const bNodeTree *UNUSED(ntree), + const bNode *node, + char *label, + int maxlen) { const char *name; bool enum_label = RNA_enum_name(rna_enum_node_vec_math_items, node->custom1, &name); @@ -227,7 +230,7 @@ void node_vector_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, BLI_strncpy(label, IFACE_(name), maxlen); } -void node_filter_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen) +void node_filter_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen) { const char *name; bool enum_label = RNA_enum_name(rna_enum_node_filter_items, node->custom1, &name); @@ -301,11 +304,6 @@ static bNodeSocket *node_find_linkable_socket(bNodeTree *ntree, return NULL; } -/** - * The idea behind this is: When a user connects an input to a socket that is - * already linked (and if its not an Multi Input Socket), we try to find a replacement socket for - * the link that we try to overwrite and connect that previous link to the new socket. - */ void node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link) { bNodeSocket *socket = link->tosock; @@ -351,11 +349,11 @@ void node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link) * `< 0`: never connect these types. * `>= 0`: priority of connection (higher values chosen first). */ -static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype to) +static int node_datatype_priority(const bNodeSocketType *from, const bNodeSocketType *to) { - switch (to) { + switch (to->type) { case SOCK_RGBA: - switch (from) { + switch (from->type) { case SOCK_RGBA: return 4; case SOCK_FLOAT: @@ -364,11 +362,10 @@ static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype return 2; case SOCK_BOOLEAN: return 1; - default: - return -1; } + return -1; case SOCK_VECTOR: - switch (from) { + switch (from->type) { case SOCK_VECTOR: return 4; case SOCK_FLOAT: @@ -377,11 +374,10 @@ static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype return 2; case SOCK_BOOLEAN: return 1; - default: - return -1; } + return -1; case SOCK_FLOAT: - switch (from) { + switch (from->type) { case SOCK_FLOAT: return 5; case SOCK_INT: @@ -392,11 +388,10 @@ static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype return 2; case SOCK_VECTOR: return 1; - default: - return -1; } + return -1; case SOCK_INT: - switch (from) { + switch (from->type) { case SOCK_INT: return 5; case SOCK_FLOAT: @@ -407,11 +402,10 @@ static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype return 2; case SOCK_VECTOR: return 1; - default: - return -1; } + return -1; case SOCK_BOOLEAN: - switch (from) { + switch (from->type) { case SOCK_BOOLEAN: return 5; case SOCK_INT: @@ -422,74 +416,17 @@ static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype return 2; case SOCK_VECTOR: return 1; - default: - return -1; - } - case SOCK_SHADER: - switch (from) { - case SOCK_SHADER: - return 1; - default: - return -1; } - case SOCK_STRING: - switch (from) { - case SOCK_STRING: - return 1; - default: - return -1; - } - case SOCK_OBJECT: { - switch (from) { - case SOCK_OBJECT: - return 1; - default: - return -1; - } - } - case SOCK_GEOMETRY: { - switch (from) { - case SOCK_GEOMETRY: - return 1; - default: - return -1; - } - } - case SOCK_COLLECTION: { - switch (from) { - case SOCK_COLLECTION: - return 1; - default: - return -1; - } - } - case SOCK_TEXTURE: { - switch (from) { - case SOCK_TEXTURE: - return 1; - default: - return -1; - } - } - case SOCK_IMAGE: { - switch (from) { - case SOCK_IMAGE: - return 1; - default: - return -1; - } - } - case SOCK_MATERIAL: { - switch (from) { - case SOCK_MATERIAL: - return 1; - default: - return -1; - } - } - default: return -1; } + + /* The rest of the socket types only allow an internal link if both the input and output socket + * have the same type. If the sockets are custom, we check the idname instead. */ + if (to->type == from->type && (to->type != SOCK_CUSTOM || STREQ(to->idname, from->idname))) { + return 1; + } + + return -1; } /* select a suitable input socket for an output */ @@ -505,7 +442,7 @@ static bNodeSocket *select_internal_link_input(bNode *node, bNodeSocket *output) bool sel_is_linked = false; for (input = node->inputs.first, i = 0; input; input = input->next, i++) { - int priority = node_datatype_priority(input->type, output->type); + int priority = node_datatype_priority(input->typeinfo, output->typeinfo); bool is_linked = (input->link != NULL); bool preferred; diff --git a/source/blender/nodes/intern/node_util.h b/source/blender/nodes/intern/node_util.h index c064ef4ab36..d7da2303088 100644 --- a/source/blender/nodes/intern/node_util.h +++ b/source/blender/nodes/intern/node_util.h @@ -23,20 +23,6 @@ #pragma once -#include "DNA_listBase.h" - -#include "BLI_utildefines.h" - -#include "BKE_node.h" - -#include "MEM_guardedalloc.h" - -#include "NOD_socket.h" - -#include "GPU_material.h" /* For Shader muting GPU code... */ - -#include "RNA_access.h" - #ifdef __cplusplus extern "C" { #endif @@ -56,18 +42,18 @@ typedef struct bNodeExecData { /**** Storage Data ****/ -extern void node_free_curves(struct bNode *node); -extern void node_free_standard_storage(struct bNode *node); +void node_free_curves(struct bNode *node); +void node_free_standard_storage(struct bNode *node); -extern void node_copy_curves(struct bNodeTree *dest_ntree, - struct bNode *dest_node, - const struct bNode *src_node); -extern void node_copy_standard_storage(struct bNodeTree *dest_ntree, - struct bNode *dest_node, - const struct bNode *src_node); -extern void *node_initexec_curves(struct bNodeExecContext *context, - struct bNode *node, - bNodeInstanceKey key); +void node_copy_curves(struct bNodeTree *dest_ntree, + struct bNode *dest_node, + const struct bNode *src_node); +void node_copy_standard_storage(struct bNodeTree *dest_ntree, + struct bNode *dest_node, + const struct bNode *src_node); +void *node_initexec_curves(struct bNodeExecContext *context, + struct bNode *node, + bNodeInstanceKey key); /**** Updates ****/ void node_sock_label(struct bNodeSocket *sock, const char *name); @@ -75,13 +61,34 @@ void node_sock_label_clear(struct bNodeSocket *sock); void node_math_update(struct bNodeTree *ntree, struct bNode *node); /**** Labels ****/ -void node_blend_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); -void node_image_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); -void node_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); -void node_vector_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); -void node_filter_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); +void node_blend_label(const struct bNodeTree *ntree, + const struct bNode *node, + char *label, + int maxlen); +void node_image_label(const struct bNodeTree *ntree, + const struct bNode *node, + char *label, + int maxlen); +void node_math_label(const struct bNodeTree *ntree, + const struct bNode *node, + char *label, + int maxlen); +void node_vector_math_label(const struct bNodeTree *ntree, + const struct bNode *node, + char *label, + int maxlen); +void node_filter_label(const struct bNodeTree *ntree, + const struct bNode *node, + char *label, + int maxlen); /*** Link Handling */ + +/** + * The idea behind this is: When a user connects an input to a socket that is + * already linked (and if its not an Multi Input Socket), we try to find a replacement socket for + * the link that we try to overwrite and connect that previous link to the new socket. + */ void node_insert_link_default(struct bNodeTree *ntree, struct bNode *node, struct bNodeLink *link); float node_socket_get_float(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock); diff --git a/source/blender/nodes/intern/socket_search_link.cc b/source/blender/nodes/intern/socket_search_link.cc new file mode 100644 index 00000000000..8543efe7f9b --- /dev/null +++ b/source/blender/nodes/intern/socket_search_link.cc @@ -0,0 +1,199 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "BLI_set.hh" + +#include "BKE_node.h" + +#include "UI_interface.h" + +#include "NOD_node_declaration.hh" +#include "NOD_socket_search_link.hh" + +namespace blender::nodes { + +void GatherLinkSearchOpParams::add_item(std::string socket_name, + SocketLinkOperation::LinkSocketFn fn, + const int weight) +{ + + std::string name = std::string(node_type_.ui_name) + " " + UI_MENU_ARROW_SEP + socket_name; + + items_.append({std::move(name), std::move(fn), weight}); +} + +const bNodeSocket &GatherLinkSearchOpParams::other_socket() const +{ + return other_socket_; +} + +const bNodeTree &GatherLinkSearchOpParams::node_tree() const +{ + return node_tree_; +} + +const bNodeType &GatherLinkSearchOpParams::node_type() const +{ + return node_type_; +} + +eNodeSocketInOut GatherLinkSearchOpParams::in_out() const +{ + return other_socket_.in_out == SOCK_IN ? SOCK_OUT : SOCK_IN; +} + +void LinkSearchOpParams::connect_available_socket(bNode &new_node, StringRef socket_name) +{ + const eNodeSocketInOut in_out = socket.in_out == SOCK_IN ? SOCK_OUT : SOCK_IN; + bNodeSocket *new_node_socket = bke::node_find_enabled_socket(new_node, in_out, socket_name); + if (new_node_socket == nullptr) { + /* If the socket isn't found, some node's search gather functions probably aren't configured + * properly. It's likely enough that it's worth avoiding a crash in a release build though. */ + BLI_assert_unreachable(); + return; + } + nodeAddLink(&node_tree, &new_node, new_node_socket, &node, &socket); +} + +bNode &LinkSearchOpParams::add_node(StringRef idname) +{ + std::string idname_str = idname; + bNode *node = nodeAddNode(&C, &node_tree, idname_str.c_str()); + BLI_assert(node != nullptr); + added_nodes_.append(node); + return *node; +} + +bNode &LinkSearchOpParams::add_node(const bNodeType &node_type) +{ + return this->add_node(node_type.idname); +} + +void LinkSearchOpParams::update_and_connect_available_socket(bNode &new_node, + StringRef socket_name) +{ + if (new_node.typeinfo->updatefunc) { + new_node.typeinfo->updatefunc(&node_tree, &new_node); + } + this->connect_available_socket(new_node, socket_name); +} + +void search_link_ops_for_declarations(GatherLinkSearchOpParams ¶ms, + Span<SocketDeclarationPtr> declarations) +{ + const bNodeType &node_type = params.node_type(); + + const SocketDeclaration *main_socket = nullptr; + Vector<const SocketDeclaration *> connectable_sockets; + + Set<StringRef> socket_names; + for (const int i : declarations.index_range()) { + const SocketDeclaration &socket = *declarations[i]; + if (!socket_names.add(socket.name())) { + /* Don't add sockets with the same name to the search. Needed to support being called from + * #search_link_ops_for_basic_node, which should have "okay" behavior for nodes with + * duplicate socket names. */ + continue; + } + if (!socket.can_connect(params.other_socket())) { + continue; + } + if (socket.is_default_link_socket() || main_socket == nullptr) { + /* Either the first connectable or explicitly tagged socket is the main socket. */ + main_socket = &socket; + } + connectable_sockets.append(&socket); + } + for (const int i : connectable_sockets.index_range()) { + const SocketDeclaration &socket = *connectable_sockets[i]; + /* Give non-main sockets a lower weight so that they don't show up at the top of the search + * when they are not explicitly searched for. The -1 is used to make sure that the first socket + * has a smaller weight than zero so that it does not have the same weight as the main socket. + * Negative weights are used to avoid making the highest weight dependent on the number of + * sockets. */ + const int weight = (&socket == main_socket) ? 0 : -1 - i; + params.add_item( + socket.name(), + [&node_type, &socket](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node(node_type); + socket.make_available(node); + params.update_and_connect_available_socket(node, socket.name()); + }, + weight); + } +} + +static void search_link_ops_for_socket_templates(GatherLinkSearchOpParams ¶ms, + const bNodeSocketTemplate *templates, + const eNodeSocketInOut in_out) +{ + const bNodeType &node_type = params.node_type(); + const bNodeTreeType &node_tree_type = *params.node_tree().typeinfo; + + Set<StringRef> socket_names; + for (const bNodeSocketTemplate *socket_template = templates; socket_template->type != -1; + socket_template++) { + eNodeSocketDatatype from = (eNodeSocketDatatype)socket_template->type; + eNodeSocketDatatype to = (eNodeSocketDatatype)params.other_socket().type; + if (in_out == SOCK_IN) { + std::swap(from, to); + } + if (node_tree_type.validate_link && !node_tree_type.validate_link(from, to)) { + continue; + } + if (!socket_names.add(socket_template->name)) { + /* See comment in #search_link_ops_for_declarations. */ + continue; + } + + params.add_item( + socket_template->name, [socket_template, node_type, in_out](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node(node_type); + bNodeSocket *new_node_socket = bke::node_find_enabled_socket( + node, in_out, socket_template->name); + if (new_node_socket != nullptr) { + /* Rely on the way #nodeAddLink switches in/out if necessary. */ + nodeAddLink(¶ms.node_tree, ¶ms.node, ¶ms.socket, &node, new_node_socket); + } + }); + } +} + +void search_link_ops_for_basic_node(GatherLinkSearchOpParams ¶ms) +{ + const bNodeType &node_type = params.node_type(); + + if (node_type.declare) { + if (node_type.declaration_is_dynamic) { + /* Dynamic declarations (whatever they end up being) aren't supported + * by this function, but still avoid a crash in release builds. */ + BLI_assert_unreachable(); + return; + } + + const NodeDeclaration &declaration = *node_type.fixed_declaration; + + search_link_ops_for_declarations(params, declaration.sockets(params.in_out())); + } + else if (node_type.inputs && params.in_out() == SOCK_IN) { + search_link_ops_for_socket_templates(params, node_type.inputs, SOCK_IN); + } + else if (node_type.outputs && params.in_out() == SOCK_OUT) { + search_link_ops_for_socket_templates(params, node_type.outputs, SOCK_OUT); + } +} + +} // namespace blender::nodes diff --git a/source/blender/nodes/intern/type_conversions.cc b/source/blender/nodes/intern/type_conversions.cc deleted file mode 100644 index b1611679ced..00000000000 --- a/source/blender/nodes/intern/type_conversions.cc +++ /dev/null @@ -1,347 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "NOD_type_conversions.hh" - -#include "FN_multi_function_builder.hh" - -#include "BLI_color.hh" -#include "BLI_float2.hh" -#include "BLI_float3.hh" - -namespace blender::nodes { - -using fn::MFDataType; - -template<typename From, typename To, To (*ConversionF)(const From &)> -static void add_implicit_conversion(DataTypeConversions &conversions) -{ - const CPPType &from_type = CPPType::get<From>(); - const CPPType &to_type = CPPType::get<To>(); - const std::string conversion_name = from_type.name() + " to " + to_type.name(); - - static fn::CustomMF_SI_SO<From, To> multi_function{conversion_name, ConversionF}; - static auto convert_single_to_initialized = [](const void *src, void *dst) { - *(To *)dst = ConversionF(*(const From *)src); - }; - static auto convert_single_to_uninitialized = [](const void *src, void *dst) { - new (dst) To(ConversionF(*(const From *)src)); - }; - conversions.add(fn::MFDataType::ForSingle<From>(), - fn::MFDataType::ForSingle<To>(), - multi_function, - convert_single_to_initialized, - convert_single_to_uninitialized); -} - -static float2 float_to_float2(const float &a) -{ - return float2(a); -} -static float3 float_to_float3(const float &a) -{ - return float3(a); -} -static int32_t float_to_int(const float &a) -{ - return (int32_t)a; -} -static bool float_to_bool(const float &a) -{ - return a > 0.0f; -} -static ColorGeometry4f float_to_color(const float &a) -{ - return ColorGeometry4f(a, a, a, 1.0f); -} - -static float3 float2_to_float3(const float2 &a) -{ - return float3(a.x, a.y, 0.0f); -} -static float float2_to_float(const float2 &a) -{ - return (a.x + a.y) / 2.0f; -} -static int float2_to_int(const float2 &a) -{ - return (int32_t)((a.x + a.y) / 2.0f); -} -static bool float2_to_bool(const float2 &a) -{ - return !is_zero_v2(a); -} -static ColorGeometry4f float2_to_color(const float2 &a) -{ - return ColorGeometry4f(a.x, a.y, 0.0f, 1.0f); -} - -static bool float3_to_bool(const float3 &a) -{ - return !is_zero_v3(a); -} -static float float3_to_float(const float3 &a) -{ - return (a.x + a.y + a.z) / 3.0f; -} -static int float3_to_int(const float3 &a) -{ - return (int)((a.x + a.y + a.z) / 3.0f); -} -static float2 float3_to_float2(const float3 &a) -{ - return float2(a); -} -static ColorGeometry4f float3_to_color(const float3 &a) -{ - return ColorGeometry4f(a.x, a.y, a.z, 1.0f); -} - -static bool int_to_bool(const int32_t &a) -{ - return a > 0; -} -static float int_to_float(const int32_t &a) -{ - return (float)a; -} -static float2 int_to_float2(const int32_t &a) -{ - return float2((float)a); -} -static float3 int_to_float3(const int32_t &a) -{ - return float3((float)a); -} -static ColorGeometry4f int_to_color(const int32_t &a) -{ - return ColorGeometry4f((float)a, (float)a, (float)a, 1.0f); -} - -static float bool_to_float(const bool &a) -{ - return (bool)a; -} -static int32_t bool_to_int(const bool &a) -{ - return (int32_t)a; -} -static float2 bool_to_float2(const bool &a) -{ - return (a) ? float2(1.0f) : float2(0.0f); -} -static float3 bool_to_float3(const bool &a) -{ - return (a) ? float3(1.0f) : float3(0.0f); -} -static ColorGeometry4f bool_to_color(const bool &a) -{ - return (a) ? ColorGeometry4f(1.0f, 1.0f, 1.0f, 1.0f) : ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f); -} - -static bool color_to_bool(const ColorGeometry4f &a) -{ - return rgb_to_grayscale(a) > 0.0f; -} -static float color_to_float(const ColorGeometry4f &a) -{ - return rgb_to_grayscale(a); -} -static int32_t color_to_int(const ColorGeometry4f &a) -{ - return (int)rgb_to_grayscale(a); -} -static float2 color_to_float2(const ColorGeometry4f &a) -{ - return float2(a.r, a.g); -} -static float3 color_to_float3(const ColorGeometry4f &a) -{ - return float3(a.r, a.g, a.b); -} - -static DataTypeConversions create_implicit_conversions() -{ - DataTypeConversions conversions; - - add_implicit_conversion<float, float2, float_to_float2>(conversions); - add_implicit_conversion<float, float3, float_to_float3>(conversions); - add_implicit_conversion<float, int32_t, float_to_int>(conversions); - add_implicit_conversion<float, bool, float_to_bool>(conversions); - add_implicit_conversion<float, ColorGeometry4f, float_to_color>(conversions); - - add_implicit_conversion<float2, float3, float2_to_float3>(conversions); - add_implicit_conversion<float2, float, float2_to_float>(conversions); - add_implicit_conversion<float2, int32_t, float2_to_int>(conversions); - add_implicit_conversion<float2, bool, float2_to_bool>(conversions); - add_implicit_conversion<float2, ColorGeometry4f, float2_to_color>(conversions); - - add_implicit_conversion<float3, bool, float3_to_bool>(conversions); - add_implicit_conversion<float3, float, float3_to_float>(conversions); - add_implicit_conversion<float3, int32_t, float3_to_int>(conversions); - add_implicit_conversion<float3, float2, float3_to_float2>(conversions); - add_implicit_conversion<float3, ColorGeometry4f, float3_to_color>(conversions); - - add_implicit_conversion<int32_t, bool, int_to_bool>(conversions); - add_implicit_conversion<int32_t, float, int_to_float>(conversions); - add_implicit_conversion<int32_t, float2, int_to_float2>(conversions); - add_implicit_conversion<int32_t, float3, int_to_float3>(conversions); - add_implicit_conversion<int32_t, ColorGeometry4f, int_to_color>(conversions); - - add_implicit_conversion<bool, float, bool_to_float>(conversions); - add_implicit_conversion<bool, int32_t, bool_to_int>(conversions); - add_implicit_conversion<bool, float2, bool_to_float2>(conversions); - add_implicit_conversion<bool, float3, bool_to_float3>(conversions); - add_implicit_conversion<bool, ColorGeometry4f, bool_to_color>(conversions); - - add_implicit_conversion<ColorGeometry4f, bool, color_to_bool>(conversions); - add_implicit_conversion<ColorGeometry4f, float, color_to_float>(conversions); - add_implicit_conversion<ColorGeometry4f, int32_t, color_to_int>(conversions); - add_implicit_conversion<ColorGeometry4f, float2, color_to_float2>(conversions); - add_implicit_conversion<ColorGeometry4f, float3, color_to_float3>(conversions); - - return conversions; -} - -const DataTypeConversions &get_implicit_type_conversions() -{ - static const DataTypeConversions conversions = create_implicit_conversions(); - return conversions; -} - -void DataTypeConversions::convert_to_uninitialized(const CPPType &from_type, - const CPPType &to_type, - const void *from_value, - void *to_value) const -{ - if (from_type == to_type) { - from_type.copy_construct(from_value, to_value); - return; - } - - const ConversionFunctions *functions = this->get_conversion_functions( - MFDataType::ForSingle(from_type), MFDataType::ForSingle(to_type)); - BLI_assert(functions != nullptr); - - functions->convert_single_to_uninitialized(from_value, to_value); -} - -class GVArray_For_ConvertedGVArray : public fn::GVArrayImpl { - private: - fn::GVArray varray_; - const CPPType &from_type_; - ConversionFunctions old_to_new_conversions_; - - public: - GVArray_For_ConvertedGVArray(fn::GVArray varray, - const CPPType &to_type, - const DataTypeConversions &conversions) - : fn::GVArrayImpl(to_type, varray.size()), - varray_(std::move(varray)), - from_type_(varray_.type()) - { - old_to_new_conversions_ = *conversions.get_conversion_functions(from_type_, to_type); - } - - private: - void get(const int64_t index, void *r_value) const override - { - BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); - varray_.get(index, buffer); - old_to_new_conversions_.convert_single_to_initialized(buffer, r_value); - from_type_.destruct(buffer); - } - - void get_to_uninitialized(const int64_t index, void *r_value) const override - { - BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); - varray_.get(index, buffer); - old_to_new_conversions_.convert_single_to_uninitialized(buffer, r_value); - from_type_.destruct(buffer); - } -}; - -class GVMutableArray_For_ConvertedGVMutableArray : public fn::GVMutableArrayImpl { - private: - fn::GVMutableArray varray_; - const CPPType &from_type_; - ConversionFunctions old_to_new_conversions_; - ConversionFunctions new_to_old_conversions_; - - public: - GVMutableArray_For_ConvertedGVMutableArray(fn::GVMutableArray varray, - const CPPType &to_type, - const DataTypeConversions &conversions) - : fn::GVMutableArrayImpl(to_type, varray.size()), - varray_(std::move(varray)), - from_type_(varray_.type()) - { - old_to_new_conversions_ = *conversions.get_conversion_functions(from_type_, to_type); - new_to_old_conversions_ = *conversions.get_conversion_functions(to_type, from_type_); - } - - private: - void get(const int64_t index, void *r_value) const override - { - BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); - varray_.get(index, buffer); - old_to_new_conversions_.convert_single_to_initialized(buffer, r_value); - from_type_.destruct(buffer); - } - - void get_to_uninitialized(const int64_t index, void *r_value) const override - { - BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); - varray_.get(index, buffer); - old_to_new_conversions_.convert_single_to_uninitialized(buffer, r_value); - from_type_.destruct(buffer); - } - - void set_by_move(const int64_t index, void *value) override - { - BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); - new_to_old_conversions_.convert_single_to_uninitialized(value, buffer); - varray_.set_by_relocate(index, buffer); - } -}; - -fn::GVArray DataTypeConversions::try_convert(fn::GVArray varray, const CPPType &to_type) const -{ - const CPPType &from_type = varray.type(); - if (from_type == to_type) { - return varray; - } - if (!this->is_convertible(from_type, to_type)) { - return {}; - } - return fn::GVArray::For<GVArray_For_ConvertedGVArray>(std::move(varray), to_type, *this); -} - -fn::GVMutableArray DataTypeConversions::try_convert(fn::GVMutableArray varray, - const CPPType &to_type) const -{ - const CPPType &from_type = varray.type(); - if (from_type == to_type) { - return varray; - } - if (!this->is_convertible(from_type, to_type)) { - return {}; - } - return fn::GVMutableArray::For<GVMutableArray_For_ConvertedGVMutableArray>( - std::move(varray), to_type, *this); -} - -} // namespace blender::nodes diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt new file mode 100644 index 00000000000..7d99c233197 --- /dev/null +++ b/source/blender/nodes/shader/CMakeLists.txt @@ -0,0 +1,166 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The Original Code is Copyright (C) 2021, Blender Foundation +# All rights reserved. +# ***** END GPL LICENSE BLOCK ***** + +set(INC + . + ../ + ../intern + ../../blenkernel + ../../blenlib + ../../blentranslation + ../../depsgraph + ../../functions + ../../gpu + ../../imbuf + ../../makesdna + ../../makesrna + ../../render + ../../windowmanager + ../../../../intern/guardedalloc + ../../../../intern/sky/include +) + + +set(SRC + nodes/node_shader_add_shader.c + nodes/node_shader_ambient_occlusion.c + nodes/node_shader_attribute.c + nodes/node_shader_background.c + nodes/node_shader_bevel.c + nodes/node_shader_blackbody.c + nodes/node_shader_brightness.c + nodes/node_shader_bsdf_anisotropic.c + nodes/node_shader_bsdf_diffuse.c + nodes/node_shader_bsdf_glass.c + nodes/node_shader_bsdf_glossy.c + nodes/node_shader_bsdf_hair.c + nodes/node_shader_bsdf_hair_principled.c + nodes/node_shader_bsdf_principled.c + nodes/node_shader_bsdf_refraction.c + nodes/node_shader_bsdf_toon.c + nodes/node_shader_bsdf_translucent.c + nodes/node_shader_bsdf_transparent.c + nodes/node_shader_bsdf_velvet.c + nodes/node_shader_bump.c + nodes/node_shader_camera.c + nodes/node_shader_clamp.cc + nodes/node_shader_common.c + nodes/node_shader_curves.cc + nodes/node_shader_displacement.c + nodes/node_shader_eevee_specular.c + nodes/node_shader_emission.c + nodes/node_shader_fresnel.c + nodes/node_shader_gamma.c + nodes/node_shader_geometry.c + nodes/node_shader_hair_info.c + nodes/node_shader_holdout.c + nodes/node_shader_hueSatVal.c + nodes/node_shader_ies_light.c + nodes/node_shader_invert.c + nodes/node_shader_layer_weight.c + nodes/node_shader_light_falloff.c + nodes/node_shader_light_path.c + nodes/node_shader_map_range.cc + nodes/node_shader_mapping.c + nodes/node_shader_math.cc + nodes/node_shader_mix_rgb.cc + nodes/node_shader_mix_shader.c + nodes/node_shader_normal.c + nodes/node_shader_normal_map.c + nodes/node_shader_object_info.c + nodes/node_shader_output_aov.c + nodes/node_shader_output_light.c + nodes/node_shader_output_linestyle.c + nodes/node_shader_output_material.c + nodes/node_shader_output_world.c + nodes/node_shader_particle_info.c + nodes/node_shader_rgb_to_bw.cc + nodes/node_shader_rgb.c + nodes/node_shader_script.c + nodes/node_shader_sepcomb_hsv.c + nodes/node_shader_sepcomb_rgb.cc + nodes/node_shader_sepcomb_xyz.cc + nodes/node_shader_shader_to_rgb.c + nodes/node_shader_squeeze.c + nodes/node_shader_subsurface_scattering.c + nodes/node_shader_tangent.c + nodes/node_shader_tex_brick.cc + nodes/node_shader_tex_checker.cc + nodes/node_shader_tex_coord.c + nodes/node_shader_tex_environment.c + nodes/node_shader_tex_gradient.cc + nodes/node_shader_tex_image.cc + nodes/node_shader_tex_magic.cc + nodes/node_shader_tex_musgrave.cc + nodes/node_shader_tex_noise.cc + nodes/node_shader_tex_pointdensity.c + nodes/node_shader_tex_sky.c + nodes/node_shader_tex_voronoi.cc + nodes/node_shader_tex_wave.cc + nodes/node_shader_tex_white_noise.cc + nodes/node_shader_uv_along_stroke.c + nodes/node_shader_uvmap.c + nodes/node_shader_value.cc + nodes/node_shader_vector_displacement.c + nodes/node_shader_vector_math.cc + nodes/node_shader_vector_rotate.cc + nodes/node_shader_vector_transform.c + nodes/node_shader_vertex_color.c + nodes/node_shader_volume_absorption.c + nodes/node_shader_volume_info.c + nodes/node_shader_volume_principled.c + nodes/node_shader_volume_scatter.c + nodes/node_shader_wavelength.c + nodes/node_shader_wireframe.c + + node_shader_tree.c + node_shader_util.cc + + node_shader_util.h +) + +set(LIB + bf_functions + bf_intern_sky +) + +if(WITH_PYTHON) + list(APPEND INC + ../../python + ) + list(APPEND INC_SYS + ${PYTHON_INCLUDE_DIRS} + ) + list(APPEND LIB + ${PYTHON_LINKFLAGS} + ${PYTHON_LIBRARIES} + ) + add_definitions(-DWITH_PYTHON) +endif() + +if(WITH_INTERNATIONAL) + add_definitions(-DWITH_INTERNATIONAL) +endif() + +if(WITH_FREESTYLE) + add_definitions(-DWITH_FREESTYLE) +endif() + +blender_add_lib(bf_nodes_shader "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c index 83ee0c2f411..c3b5236373c 100644 --- a/source/blender/nodes/shader/node_shader_tree.c +++ b/source/blender/nodes/shader/node_shader_tree.c @@ -139,12 +139,8 @@ static void foreach_nodeclass(Scene *UNUSED(scene), void *calldata, bNodeClassCa static void localize(bNodeTree *localtree, bNodeTree *UNUSED(ntree)) { - bNode *node, *node_next; - /* replace muted nodes and reroute nodes by internal links */ - for (node = localtree->nodes.first; node; node = node_next) { - node_next = node->next; - + LISTBASE_FOREACH_MUTABLE (bNode *, node, &localtree->nodes) { if (node->flag & NODE_MUTED || node->type == NODE_REROUTE) { nodeInternalRelink(localtree, node); ntreeFreeLocalNode(localtree, node); @@ -174,12 +170,12 @@ static void update(bNodeTree *ntree) } } -static bool shader_validate_link(bNodeTree *UNUSED(ntree), bNodeLink *link) +static bool shader_validate_link(eNodeSocketDatatype from, eNodeSocketDatatype to) { /* Can't connect shader into other socket types, other way around is fine * since it will be interpreted as emission. */ - if (link->fromsock->type == SOCK_SHADER) { - return (link->tosock->type == SOCK_SHADER); + if (from == SOCK_SHADER) { + return to == SOCK_SHADER; } return true; } @@ -221,13 +217,6 @@ void register_node_tree_type_sh(void) /* GPU material from shader nodes */ -/* Find an output node of the shader tree. - * - * NOTE: it will only return output which is NOT in the group, which isn't how - * render engines works but it's how the GPU shader compilation works. This we - * can change in the future and make it a generic function, but for now it stays - * private here. - */ bNode *ntreeShaderOutputNode(bNodeTree *ntree, int target) { /* Make sure we only have single node tagged as output. */ @@ -887,7 +876,6 @@ void ntree_shader_tag_nodes(bNodeTree *ntree, bNode *output_node, nTreeTags *tag nodeChainIterBackwards(ntree, output_node, ntree_tag_bsdf_cb, tags, 0); } -/* This one needs to work on a local tree. */ void ntreeGPUMaterialNodes(bNodeTree *localtree, GPUMaterial *mat, bool *has_surface_output, diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.cc index e1f6c135568..f2464d4c1b4 100644 --- a/source/blender/nodes/shader/node_shader_util.c +++ b/source/blender/nodes/shader/node_shader_util.cc @@ -25,12 +25,14 @@ #include "node_shader_util.h" +#include "NOD_socket_search_link.hh" + #include "node_exec.h" bool sh_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree, const char **r_disabled_hint) { if (!STREQ(ntree->idname, "ShaderNodeTree")) { - *r_disabled_hint = "Not a shader node tree"; + *r_disabled_hint = TIP_("Not a shader node tree"); return false; } return true; @@ -41,7 +43,7 @@ static bool sh_fn_poll_default(bNodeType *UNUSED(ntype), const char **r_disabled_hint) { if (!STR_ELEM(ntree->idname, "ShaderNodeTree", "GeometryNodeTree")) { - *r_disabled_hint = "Not a shader or geometry node tree"; + *r_disabled_hint = TIP_("Not a shader or geometry node tree"); return false; } return true; @@ -54,12 +56,14 @@ void sh_node_type_base( ntype->poll = sh_node_poll_default; ntype->insert_link = node_insert_link_default; + ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node; } void sh_fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag) { sh_node_type_base(ntype, type, name, nclass, flag); ntype->poll = sh_fn_poll_default; + ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node; } /* ****** */ @@ -107,11 +111,11 @@ void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns) { memset(gs, 0, sizeof(*gs)); - if (ns == NULL) { - /* node_get_stack() will generate NULL bNodeStack pointers + if (ns == nullptr) { + /* node_get_stack() will generate nullptr bNodeStack pointers * for unknown/unsupported types of sockets. */ zero_v4(gs->vec); - gs->link = NULL; + gs->link = nullptr; gs->type = GPU_NONE; gs->hasinput = false; gs->hasoutput = false; @@ -119,7 +123,7 @@ void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns) } else { nodestack_get_vec(gs->vec, type, ns); - gs->link = ns->data; + gs->link = (GPUNodeLink *)ns->data; if (type == SOCK_FLOAT) { gs->type = GPU_FLOAT; @@ -159,11 +163,9 @@ void node_data_from_gpu_stack(bNodeStack *ns, GPUNodeStack *gs) static void gpu_stack_from_data_list(GPUNodeStack *gs, ListBase *sockets, bNodeStack **ns) { - bNodeSocket *sock; int i; - - for (sock = sockets->first, i = 0; sock; sock = sock->next, i++) { - node_gpu_stack_from_data(&gs[i], sock->type, ns[i]); + LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, sockets, i) { + node_gpu_stack_from_data(&gs[i], socket->type, ns[i]); } gs[i].end = true; @@ -171,10 +173,8 @@ static void gpu_stack_from_data_list(GPUNodeStack *gs, ListBase *sockets, bNodeS static void data_from_gpu_stack_list(ListBase *sockets, bNodeStack **ns, GPUNodeStack *gs) { - bNodeSocket *sock; int i; - - for (sock = sockets->first, i = 0; sock; sock = sock->next, i++) { + LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, sockets, i) { node_data_from_gpu_stack(ns[i], &gs[i]); } } @@ -182,14 +182,14 @@ static void data_from_gpu_stack_list(ListBase *sockets, bNodeStack **ns, GPUNode bNode *nodeGetActiveTexture(bNodeTree *ntree) { /* this is the node we texture paint and draw in textured draw */ - bNode *node, *tnode, *inactivenode = NULL, *activetexnode = NULL, *activegroup = NULL; + bNode *inactivenode = nullptr, *activetexnode = nullptr, *activegroup = nullptr; bool hasgroup = false; if (!ntree) { - return NULL; + return nullptr; } - for (node = ntree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->flag & NODE_ACTIVE_TEXTURE) { activetexnode = node; /* if active we can return immediately */ @@ -212,7 +212,7 @@ bNode *nodeGetActiveTexture(bNodeTree *ntree) /* first, check active group for textures */ if (activegroup) { - tnode = nodeGetActiveTexture((bNodeTree *)activegroup->id); + bNode *tnode = nodeGetActiveTexture((bNodeTree *)activegroup->id); /* active node takes priority, so ignore any other possible nodes here */ if (tnode) { return tnode; @@ -225,9 +225,9 @@ bNode *nodeGetActiveTexture(bNodeTree *ntree) if (hasgroup) { /* node active texture node in this tree, look inside groups */ - for (node = ntree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->type == NODE_GROUP) { - tnode = nodeGetActiveTexture((bNodeTree *)node->id); + bNode *tnode = nodeGetActiveTexture((bNodeTree *)node->id); if (tnode && ((tnode->flag & NODE_ACTIVE_TEXTURE) || !inactivenode)) { return tnode; } @@ -257,7 +257,7 @@ void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, bNode *output_node do_it = false; /* for groups, only execute outputs for edited group */ if (node->typeinfo->nclass == NODE_CLASS_OUTPUT) { - if ((output_node != NULL) && (node == output_node)) { + if ((output_node != nullptr) && (node == output_node)) { do_it = true; } } @@ -281,11 +281,11 @@ void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, bNode *output_node void node_shader_gpu_bump_tex_coord(GPUMaterial *mat, bNode *node, GPUNodeLink **link) { if (node->branch_tag == 1) { - /* Add one time the value fo derivative to the input vector. */ + /* Add one time the value for derivative to the input vector. */ GPU_link(mat, "dfdx_v3", *link, link); } else if (node->branch_tag == 2) { - /* Add one time the value fo derivative to the input vector. */ + /* Add one time the value for derivative to the input vector. */ GPU_link(mat, "dfdy_v3", *link, link); } else { @@ -307,7 +307,7 @@ void node_shader_gpu_tex_mapping(GPUMaterial *mat, GPUNodeStack *in, GPUNodeStack *UNUSED(out)) { - NodeTexBase *base = node->storage; + NodeTexBase *base = (NodeTexBase *)node->storage; TexMapping *texmap = &base->tex_mapping; float domin = (texmap->flag & TEXMAP_CLIP_MIN) != 0; float domax = (texmap->flag & TEXMAP_CLIP_MAX) != 0; diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c index 89b7164693f..b9f4106c79a 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c @@ -169,17 +169,16 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, static void node_shader_update_principled(bNodeTree *ntree, bNode *node) { - bNodeSocket *sock; - int distribution = node->custom1; - int sss_method = node->custom2; + const int distribution = node->custom1; + const int sss_method = node->custom2; - for (sock = node->inputs.first; sock; sock = sock->next) { + for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) { if (STREQ(sock->name, "Transmission Roughness")) { nodeSetSocketAvailability(ntree, sock, distribution == SHD_GLOSSY_GGX); } if (STR_ELEM(sock->name, "Subsurface IOR", "Subsurface Anisotropy")) { - nodeSetSocketAvailability(ntree, sock, sss_method == SHD_SUBSURFACE_BURLEY); + nodeSetSocketAvailability(ntree, sock, sss_method != SHD_SUBSURFACE_BURLEY); } } } diff --git a/source/blender/nodes/shader/nodes/node_shader_clamp.cc b/source/blender/nodes/shader/nodes/node_shader_clamp.cc index 57a992a4275..6c3457151e5 100644 --- a/source/blender/nodes/shader/nodes/node_shader_clamp.cc +++ b/source/blender/nodes/shader/nodes/node_shader_clamp.cc @@ -75,7 +75,7 @@ static void sh_node_clamp_build_multi_function(blender::nodes::NodeMultiFunction } } -void register_node_type_sh_clamp(void) +void register_node_type_sh_clamp() { static bNodeType ntype; diff --git a/source/blender/nodes/shader/nodes/node_shader_common.c b/source/blender/nodes/shader/nodes/node_shader_common.c index a1dac05434e..190e0cfad4c 100644 --- a/source/blender/nodes/shader/nodes/node_shader_common.c +++ b/source/blender/nodes/shader/nodes/node_shader_common.c @@ -232,7 +232,7 @@ void register_node_type_sh_group(void) /* NOTE: cannot use #sh_node_type_base for node group, because it would map the node type * to the shared #NODE_GROUP integer type id. */ - node_type_base_custom(&ntype, "ShaderNodeGroup", "Group", NODE_CLASS_GROUP, NODE_CONST_OUTPUT); + node_type_base_custom(&ntype, "ShaderNodeGroup", "Group", NODE_CLASS_GROUP, 0); ntype.type = NODE_GROUP; ntype.poll = sh_node_poll_default; ntype.poll_instance = node_group_poll_instance; @@ -243,7 +243,7 @@ void register_node_type_sh_group(void) node_type_socket_templates(&ntype, NULL, NULL); node_type_size(&ntype, 140, 60, 400); - node_type_label(&ntype, node_group_label); + ntype.labelfunc = node_group_label; node_type_group_update(&ntype, node_group_update); node_type_exec(&ntype, group_initexec, group_freeexec, group_execute); node_type_gpu(&ntype, gpu_group_execute); diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.cc b/source/blender/nodes/shader/nodes/node_shader_curves.cc index 7ce5150bf85..09bbf3d851c 100644 --- a/source/blender/nodes/shader/nodes/node_shader_curves.cc +++ b/source/blender/nodes/shader/nodes/node_shader_curves.cc @@ -152,7 +152,7 @@ static void sh_node_curve_vec_build_multi_function( builder.construct_and_set_matching_fn<CurveVecFunction>(*cumap); } -void register_node_type_sh_curve_vec(void) +void register_node_type_sh_curve_vec() { static bNodeType ntype; @@ -329,7 +329,7 @@ static void sh_node_curve_rgb_build_multi_function( builder.construct_and_set_matching_fn<CurveRGBFunction>(*cumap); } -void register_node_type_sh_curve_rgb(void) +void register_node_type_sh_curve_rgb() { static bNodeType ntype; @@ -473,7 +473,7 @@ static void sh_node_curve_float_build_multi_function( builder.construct_and_set_matching_fn<CurveFloatFunction>(*cumap); } -void register_node_type_sh_curve_float(void) +void register_node_type_sh_curve_float() { static bNodeType ntype; diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.cc b/source/blender/nodes/shader/nodes/node_shader_map_range.cc index e55963eb500..615ae276eb4 100644 --- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc +++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc @@ -21,10 +21,14 @@ * \ingroup shdnodes */ +#include <algorithm> + #include "node_shader_util.h" #include "BLI_math_base_safe.h" +NODE_STORAGE_FUNCS(NodeMapRange) + namespace blender::nodes { static void sh_node_map_range_declare(NodeDeclarationBuilder &b) @@ -36,34 +40,80 @@ static void sh_node_map_range_declare(NodeDeclarationBuilder &b) b.add_input<decl::Float>(N_("To Min")).min(-10000.0f).max(10000.0f); b.add_input<decl::Float>(N_("To Max")).min(-10000.0f).max(10000.0f).default_value(1.0f); b.add_input<decl::Float>(N_("Steps")).min(-10000.0f).max(10000.0f).default_value(4.0f); + b.add_input<decl::Vector>(N_("Vector")).min(0.0f).max(1.0f).hide_value(); + b.add_input<decl::Vector>(N_("From Min"), "From_Min_FLOAT3"); + b.add_input<decl::Vector>(N_("From Max"), "From_Max_FLOAT3").default_value(float3(1.0f)); + b.add_input<decl::Vector>(N_("To Min"), "To_Min_FLOAT3"); + b.add_input<decl::Vector>(N_("To Max"), "To_Max_FLOAT3").default_value(float3(1.0f)); + b.add_input<decl::Vector>(N_("Steps"), "Steps_FLOAT3").default_value(float3(4.0f)); b.add_output<decl::Float>(N_("Result")); + b.add_output<decl::Vector>(N_("Vector")); }; } // namespace blender::nodes static void node_shader_update_map_range(bNodeTree *ntree, bNode *node) { - bNodeSocket *sockSteps = nodeFindSocket(node, SOCK_IN, "Steps"); - nodeSetSocketAvailability(ntree, sockSteps, node->custom2 == NODE_MAP_RANGE_STEPPED); + const NodeMapRange &storage = node_storage(*node); + const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); + const int type = (data_type == CD_PROP_FLOAT) ? SOCK_FLOAT : SOCK_VECTOR; + + LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { + nodeSetSocketAvailability(ntree, socket, socket->type == type); + } + + LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) { + nodeSetSocketAvailability(ntree, socket, socket->type == type); + } + + if (storage.interpolation_type != NODE_MAP_RANGE_STEPPED) { + if (type == SOCK_FLOAT) { + bNodeSocket *sockSteps = (bNodeSocket *)BLI_findlink(&node->inputs, 5); + nodeSetSocketAvailability(ntree, sockSteps, false); + } + else { + bNodeSocket *sockSteps = (bNodeSocket *)BLI_findlink(&node->inputs, 11); + nodeSetSocketAvailability(ntree, sockSteps, false); + } + } } static void node_shader_init_map_range(bNodeTree *UNUSED(ntree), bNode *node) { + NodeMapRange *data = (NodeMapRange *)MEM_callocN(sizeof(NodeMapRange), __func__); + data->clamp = 1; + data->data_type = CD_PROP_FLOAT; + data->interpolation_type = NODE_MAP_RANGE_LINEAR; node->custom1 = true; /* use_clamp */ node->custom2 = NODE_MAP_RANGE_LINEAR; /* interpolation */ + node->storage = data; } -static const char *gpu_shader_get_name(int mode) +static const char *gpu_shader_get_name(int mode, bool use_vector) { - switch (mode) { - case NODE_MAP_RANGE_LINEAR: - return "map_range_linear"; - case NODE_MAP_RANGE_STEPPED: - return "map_range_stepped"; - case NODE_MAP_RANGE_SMOOTHSTEP: - return "map_range_smoothstep"; - case NODE_MAP_RANGE_SMOOTHERSTEP: - return "map_range_smootherstep"; + if (use_vector) { + switch (mode) { + case NODE_MAP_RANGE_LINEAR: + return "vector_map_range_linear"; + case NODE_MAP_RANGE_STEPPED: + return "vector_map_range_stepped"; + case NODE_MAP_RANGE_SMOOTHSTEP: + return "vector_map_range_smoothstep"; + case NODE_MAP_RANGE_SMOOTHERSTEP: + return "vector_map_range_smootherstep"; + } + } + else { + switch (mode) { + case NODE_MAP_RANGE_LINEAR: + return "map_range_linear"; + case NODE_MAP_RANGE_STEPPED: + return "map_range_stepped"; + case NODE_MAP_RANGE_SMOOTHSTEP: + return "map_range_smoothstep"; + case NODE_MAP_RANGE_SMOOTHERSTEP: + return "map_range_smootherstep"; + } } return nullptr; @@ -75,22 +125,207 @@ static int gpu_shader_map_range(GPUMaterial *mat, GPUNodeStack *in, GPUNodeStack *out) { - const char *name = gpu_shader_get_name(node->custom2); - + const NodeMapRange &storage = node_storage(*node); + bool use_vector = (storage.data_type == CD_PROP_FLOAT3); + const char *name = gpu_shader_get_name(storage.interpolation_type, use_vector); + float clamp = storage.clamp ? 1.0f : 0.0f; int ret = 0; if (name != nullptr) { - ret = GPU_stack_link(mat, node, name, in, out); + ret = GPU_stack_link(mat, node, name, in, out, GPU_constant(&clamp)); } else { - ret = GPU_stack_link(mat, node, "map_range_linear", in, out); + ret = GPU_stack_link(mat, node, "map_range_linear", in, out, GPU_constant(&clamp)); } - if (ret && node->custom1 && - !ELEM(node->custom2, NODE_MAP_RANGE_SMOOTHSTEP, NODE_MAP_RANGE_SMOOTHERSTEP)) { + if (ret && storage.clamp && !use_vector && + !ELEM(storage.interpolation_type, NODE_MAP_RANGE_SMOOTHSTEP, NODE_MAP_RANGE_SMOOTHERSTEP)) { GPU_link(mat, "clamp_range", out[0].link, in[3].link, in[4].link, &out[0].link); } return ret; } +namespace blender::nodes { + +static inline float clamp_range(const float value, const float min, const float max) +{ + return (min > max) ? std::clamp(value, max, min) : std::clamp(value, min, max); +} + +static float3 clamp_range(const float3 value, const float3 min, const float3 max) +{ + return float3(clamp_range(value.x, min.x, max.x), + clamp_range(value.y, min.y, max.y), + clamp_range(value.z, min.z, max.z)); +} + +static void map_range_vector_signature(blender::fn::MFSignatureBuilder *signature, bool use_steps) +{ + signature->single_input<float3>("Vector"); + signature->single_input<float3>("From Min"); + signature->single_input<float3>("From Max"); + signature->single_input<float3>("To Min"); + signature->single_input<float3>("To Max"); + if (use_steps) { + signature->single_input<float3>("Steps"); + } + signature->single_output<float3>("Vector"); +} + +class MapRangeVectorFunction : public blender::fn::MultiFunction { + private: + bool clamp_; + + public: + MapRangeVectorFunction(bool clamp) : clamp_(clamp) + { + static blender::fn::MFSignature signature = create_signature(); + this->set_signature(&signature); + } + + static blender::fn::MFSignature create_signature() + { + blender::fn::MFSignatureBuilder signature{"Vector Map Range"}; + map_range_vector_signature(&signature, false); + return signature.build(); + } + + void call(blender::IndexMask mask, + blender::fn::MFParams params, + blender::fn::MFContext UNUSED(context)) const override + { + const blender::VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector"); + const blender::VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min"); + const blender::VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max"); + const blender::VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min"); + const blender::VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max"); + blender::MutableSpan<float3> results = params.uninitialized_single_output<float3>(5, "Vector"); + + for (int64_t i : mask) { + float3 factor = float3::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]); + results[i] = factor * (to_max[i] - to_min[i]) + to_min[i]; + } + + if (clamp_) { + for (int64_t i : mask) { + results[i] = clamp_range(results[i], to_min[i], to_max[i]); + } + } + } +}; + +class MapRangeSteppedVectorFunction : public blender::fn::MultiFunction { + private: + bool clamp_; + + public: + MapRangeSteppedVectorFunction(bool clamp) : clamp_(clamp) + { + static blender::fn::MFSignature signature = create_signature(); + this->set_signature(&signature); + } + + static blender::fn::MFSignature create_signature() + { + blender::fn::MFSignatureBuilder signature{"Vector Map Range Stepped"}; + map_range_vector_signature(&signature, true); + return signature.build(); + } + + void call(blender::IndexMask mask, + blender::fn::MFParams params, + blender::fn::MFContext UNUSED(context)) const override + { + const blender::VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector"); + const blender::VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min"); + const blender::VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max"); + const blender::VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min"); + const blender::VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max"); + const blender::VArray<float3> &steps = params.readonly_single_input<float3>(5, "Steps"); + blender::MutableSpan<float3> results = params.uninitialized_single_output<float3>(6, "Vector"); + + for (int64_t i : mask) { + float3 factor = float3::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]); + factor = float3::safe_divide(float3::floor(factor * (steps[i] + 1.0f)), steps[i]); + results[i] = factor * (to_max[i] - to_min[i]) + to_min[i]; + } + + if (clamp_) { + for (int64_t i : mask) { + results[i] = clamp_range(results[i], to_min[i], to_max[i]); + } + } + } +}; + +class MapRangeSmoothstepVectorFunction : public blender::fn::MultiFunction { + public: + MapRangeSmoothstepVectorFunction() + { + static blender::fn::MFSignature signature = create_signature(); + this->set_signature(&signature); + } + + static blender::fn::MFSignature create_signature() + { + blender::fn::MFSignatureBuilder signature{"Vector Map Range Smoothstep"}; + map_range_vector_signature(&signature, false); + return signature.build(); + } + + void call(blender::IndexMask mask, + blender::fn::MFParams params, + blender::fn::MFContext UNUSED(context)) const override + { + const blender::VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector"); + const blender::VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min"); + const blender::VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max"); + const blender::VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min"); + const blender::VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max"); + blender::MutableSpan<float3> results = params.uninitialized_single_output<float3>(5, "Vector"); + + for (int64_t i : mask) { + float3 factor = float3::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]); + clamp_v3(factor, 0.0f, 1.0f); + factor = (float3(3.0f) - 2.0f * factor) * (factor * factor); + results[i] = factor * (to_max[i] - to_min[i]) + to_min[i]; + } + } +}; + +class MapRangeSmootherstepVectorFunction : public blender::fn::MultiFunction { + public: + MapRangeSmootherstepVectorFunction() + { + static blender::fn::MFSignature signature = create_signature(); + this->set_signature(&signature); + } + + static blender::fn::MFSignature create_signature() + { + blender::fn::MFSignatureBuilder signature{"Vector Map Range Smoothstep"}; + map_range_vector_signature(&signature, false); + return signature.build(); + } + + void call(blender::IndexMask mask, + blender::fn::MFParams params, + blender::fn::MFContext UNUSED(context)) const override + { + const blender::VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector"); + const blender::VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min"); + const blender::VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max"); + const blender::VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min"); + const blender::VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max"); + blender::MutableSpan<float3> results = params.uninitialized_single_output<float3>(5, "Vector"); + + for (int64_t i : mask) { + float3 factor = float3::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]); + clamp_v3(factor, 0.0f, 1.0f); + factor = factor * factor * factor * (factor * (factor * 6.0f - 15.0f) + 10.0f); + results[i] = factor * (to_max[i] - to_min[i]) + to_min[i]; + } + } +}; + static void map_range_signature(blender::fn::MFSignatureBuilder *signature, bool use_steps) { signature->single_input<float>("Value"); @@ -140,8 +375,7 @@ class MapRangeFunction : public blender::fn::MultiFunction { if (clamp_) { for (int64_t i : mask) { - results[i] = (to_min[i] > to_max[i]) ? clamp_f(results[i], to_max[i], to_min[i]) : - clamp_f(results[i], to_min[i], to_max[i]); + results[i] = clamp_range(results[i], to_min[i], to_max[i]); } } } @@ -185,8 +419,7 @@ class MapRangeSteppedFunction : public blender::fn::MultiFunction { if (clamp_) { for (int64_t i : mask) { - results[i] = (to_min[i] > to_max[i]) ? clamp_f(results[i], to_max[i], to_min[i]) : - clamp_f(results[i], to_min[i], to_max[i]); + results[i] = clamp_range(results[i], to_min[i], to_max[i]); } } } @@ -265,58 +498,104 @@ class MapRangeSmootherstepFunction : public blender::fn::MultiFunction { static void sh_node_map_range_build_multi_function( blender::nodes::NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); - bool clamp = bnode.custom1 != 0; - int interpolation_type = bnode.custom2; - - switch (interpolation_type) { - case NODE_MAP_RANGE_LINEAR: { - if (clamp) { - static MapRangeFunction fn_with_clamp{true}; - builder.set_matching_fn(fn_with_clamp); - } - else { - static MapRangeFunction fn_without_clamp{false}; - builder.set_matching_fn(fn_without_clamp); + const NodeMapRange &storage = node_storage(builder.node()); + bool clamp = storage.clamp != 0; + int interpolation_type = storage.interpolation_type; + + switch (storage.data_type) { + case CD_PROP_FLOAT3: + switch (interpolation_type) { + case NODE_MAP_RANGE_LINEAR: { + if (clamp) { + static MapRangeVectorFunction fn_with_clamp{true}; + builder.set_matching_fn(fn_with_clamp); + } + else { + static MapRangeVectorFunction fn_without_clamp{false}; + builder.set_matching_fn(fn_without_clamp); + } + break; + } + case NODE_MAP_RANGE_STEPPED: { + if (clamp) { + static MapRangeSteppedVectorFunction fn_stepped_with_clamp{true}; + builder.set_matching_fn(fn_stepped_with_clamp); + } + else { + static MapRangeSteppedVectorFunction fn_stepped_without_clamp{false}; + builder.set_matching_fn(fn_stepped_without_clamp); + } + break; + } + case NODE_MAP_RANGE_SMOOTHSTEP: { + static MapRangeSmoothstepVectorFunction smoothstep; + builder.set_matching_fn(smoothstep); + break; + } + case NODE_MAP_RANGE_SMOOTHERSTEP: { + static MapRangeSmootherstepVectorFunction smootherstep; + builder.set_matching_fn(smootherstep); + break; + } + default: + break; } break; - } - case NODE_MAP_RANGE_STEPPED: { - if (clamp) { - static MapRangeSteppedFunction fn_stepped_with_clamp{true}; - builder.set_matching_fn(fn_stepped_with_clamp); - } - else { - static MapRangeSteppedFunction fn_stepped_without_clamp{false}; - builder.set_matching_fn(fn_stepped_without_clamp); + case CD_PROP_FLOAT: + switch (interpolation_type) { + case NODE_MAP_RANGE_LINEAR: { + if (clamp) { + static MapRangeFunction fn_with_clamp{true}; + builder.set_matching_fn(fn_with_clamp); + } + else { + static MapRangeFunction fn_without_clamp{false}; + builder.set_matching_fn(fn_without_clamp); + } + break; + } + case NODE_MAP_RANGE_STEPPED: { + if (clamp) { + static MapRangeSteppedFunction fn_stepped_with_clamp{true}; + builder.set_matching_fn(fn_stepped_with_clamp); + } + else { + static MapRangeSteppedFunction fn_stepped_without_clamp{false}; + builder.set_matching_fn(fn_stepped_without_clamp); + } + break; + } + case NODE_MAP_RANGE_SMOOTHSTEP: { + static MapRangeSmoothstepFunction smoothstep; + builder.set_matching_fn(smoothstep); + break; + } + case NODE_MAP_RANGE_SMOOTHERSTEP: { + static MapRangeSmootherstepFunction smootherstep; + builder.set_matching_fn(smootherstep); + break; + } + default: + break; } break; - } - case NODE_MAP_RANGE_SMOOTHSTEP: { - static MapRangeSmoothstepFunction smoothstep; - builder.set_matching_fn(smoothstep); - break; - } - case NODE_MAP_RANGE_SMOOTHERSTEP: { - static MapRangeSmootherstepFunction smootherstep; - builder.set_matching_fn(smootherstep); - break; - } - default: - break; } } -void register_node_type_sh_map_range(void) +} // namespace blender::nodes + +void register_node_type_sh_map_range() { static bNodeType ntype; sh_fn_node_type_base(&ntype, SH_NODE_MAP_RANGE, "Map Range", NODE_CLASS_CONVERTER, 0); ntype.declare = blender::nodes::sh_node_map_range_declare; node_type_init(&ntype, node_shader_init_map_range); + node_type_storage( + &ntype, "NodeMapRange", node_free_standard_storage, node_copy_standard_storage); node_type_update(&ntype, node_shader_update_map_range); node_type_gpu(&ntype, gpu_shader_map_range); - ntype.build_multi_function = sh_node_map_range_build_multi_function; + ntype.build_multi_function = blender::nodes::sh_node_map_range_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc index 284a5f1189f..da237be273f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_math.cc @@ -24,6 +24,7 @@ #include "node_shader_util.h" #include "NOD_math_functions.hh" +#include "NOD_socket_search_link.hh" /* **************** SCALAR MATH ******************** */ @@ -44,6 +45,18 @@ static void sh_node_math_declare(NodeDeclarationBuilder &b) b.add_output<decl::Float>(N_("Value")); }; +static void sh_node_math_gather_link_searches(GatherLinkSearchOpParams ¶ms) +{ + /* For now, do something very basic (only exposing "Add", and a single "Value" socket). */ + if (params.node_tree().typeinfo->validate_link( + static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_FLOAT)) { + params.add_item(IFACE_("Value"), [](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("ShaderNodeMath"); + params.update_and_connect_available_socket(node, "Value"); + }); + } +} + } // namespace blender::nodes static const char *gpu_shader_get_name(int mode) @@ -88,7 +101,8 @@ static const blender::fn::MultiFunction *get_base_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl_to_fl( mode, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SO<float, float> fn{info.title_case_name, function}; + static blender::fn::CustomMF_SI_SO<float, float> fn{info.title_case_name.c_str(), + function}; base_fn = &fn; }); if (base_fn != nullptr) { @@ -97,7 +111,7 @@ static const blender::fn::MultiFunction *get_base_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl_fl_to_fl( mode, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SI_SO<float, float, float> fn{info.title_case_name, + static blender::fn::CustomMF_SI_SI_SO<float, float, float> fn{info.title_case_name.c_str(), function}; base_fn = &fn; }); @@ -108,7 +122,7 @@ static const blender::fn::MultiFunction *get_base_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl_fl_fl_to_fl( mode, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { static blender::fn::CustomMF_SI_SI_SI_SO<float, float, float, float> fn{ - info.title_case_name, function}; + info.title_case_name.c_str(), function}; base_fn = &fn; }); if (base_fn != nullptr) { @@ -160,16 +174,17 @@ static void sh_node_math_build_multi_function(blender::nodes::NodeMultiFunctionB } } -void register_node_type_sh_math(void) +void register_node_type_sh_math() { static bNodeType ntype; sh_fn_node_type_base(&ntype, SH_NODE_MATH, "Math", NODE_CLASS_CONVERTER, 0); ntype.declare = blender::nodes::sh_node_math_declare; - node_type_label(&ntype, node_math_label); + ntype.labelfunc = node_math_label; node_type_gpu(&ntype, gpu_shader_math); node_type_update(&ntype, node_math_update); ntype.build_multi_function = sh_node_math_build_multi_function; + ntype.gather_link_search_ops = blender::nodes::sh_node_math_gather_link_searches; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc index 06fafff578e..b89e0527eed 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc +++ b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc @@ -183,13 +183,13 @@ static void sh_node_mix_rgb_build_multi_function(blender::nodes::NodeMultiFuncti builder.construct_and_set_matching_fn<MixRGBFunction>(clamp, mix_type); } -void register_node_type_sh_mix_rgb(void) +void register_node_type_sh_mix_rgb() { static bNodeType ntype; sh_fn_node_type_base(&ntype, SH_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, 0); ntype.declare = blender::nodes::sh_node_mix_rgb_declare; - node_type_label(&ntype, node_blend_label); + ntype.labelfunc = node_blend_label; node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_mix_rgb); node_type_gpu(&ntype, gpu_shader_mix_rgb); ntype.build_multi_function = sh_node_mix_rgb_build_multi_function; diff --git a/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc b/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc index e4f1b2c76f0..e3808985c0e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc +++ b/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc @@ -172,7 +172,7 @@ static void sh_node_valtorgb_build_multi_function( builder.construct_and_set_matching_fn<ColorBandFunction>(*color_band); } -void register_node_type_sh_valtorgb(void) +void register_node_type_sh_valtorgb() { static bNodeType ntype; @@ -222,7 +222,7 @@ static int gpu_shader_rgbtobw(GPUMaterial *mat, return GPU_stack_link(mat, node, "rgbtobw", in, out); } -void register_node_type_sh_rgbtobw(void) +void register_node_type_sh_rgbtobw() { static bNodeType ntype; diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c b/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.c index dfecb830b35..dfecb830b35 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c +++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.c diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc index 08a9e01786e..4984a530d8b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc +++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc @@ -103,7 +103,7 @@ static void sh_node_seprgb_build_multi_function(blender::nodes::NodeMultiFunctio builder.set_matching_fn(fn); } -void register_node_type_sh_seprgb(void) +void register_node_type_sh_seprgb() { static bNodeType ntype; @@ -163,7 +163,7 @@ static void sh_node_combrgb_build_multi_function(blender::nodes::NodeMultiFuncti builder.set_matching_fn(fn); } -void register_node_type_sh_combrgb(void) +void register_node_type_sh_combrgb() { static bNodeType ntype; diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc index 1bbfa629462..a414630829e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc +++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc @@ -88,7 +88,7 @@ static void sh_node_sepxyz_build_multi_function(blender::nodes::NodeMultiFunctio builder.set_matching_fn(separate_fn); } -void register_node_type_sh_sepxyz(void) +void register_node_type_sh_sepxyz() { static bNodeType ntype; @@ -129,7 +129,7 @@ static void sh_node_combxyz_build_multi_function(blender::nodes::NodeMultiFuncti builder.set_matching_fn(fn); } -void register_node_type_sh_combxyz(void) +void register_node_type_sh_combxyz() { static bNodeType ntype; diff --git a/source/blender/nodes/shader/nodes/node_shader_shaderToRgb.c b/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.c index 25c30aa4081..25c30aa4081 100644 --- a/source/blender/nodes/shader/nodes/node_shader_shaderToRgb.c +++ b/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.c diff --git a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c index e917858e0f2..85a4a6aa425 100644 --- a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c +++ b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c @@ -67,6 +67,17 @@ static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat, mat, node, "node_subsurface_scattering", in, out, GPU_constant(&node->sss_id)); } +static void node_shader_update_subsurface_scattering(bNodeTree *ntree, bNode *node) +{ + const int sss_method = node->custom1; + + for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) { + if (STR_ELEM(sock->name, "IOR", "Anisotropy")) { + nodeSetSocketAvailability(ntree, sock, sss_method != SHD_SUBSURFACE_BURLEY); + } + } +} + /* node type definition */ void register_node_type_sh_subsurface_scattering(void) { @@ -80,6 +91,7 @@ void register_node_type_sh_subsurface_scattering(void) node_type_init(&ntype, node_shader_init_subsurface_scattering); node_type_storage(&ntype, "", NULL, NULL); node_type_gpu(&ntype, node_shader_gpu_subsurface_scattering); + node_type_update(&ntype, node_shader_update_subsurface_scattering); nodeRegisterType(&ntype); } 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 b840bd75e42..7925c96db3d 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc @@ -268,7 +268,7 @@ static void sh_node_brick_build_multi_function(blender::nodes::NodeMultiFunction } // namespace blender::nodes -void register_node_type_sh_tex_brick(void) +void register_node_type_sh_tex_brick() { static bNodeType ntype; 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 7c1223a6a32..6d2d199aec8 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc @@ -123,7 +123,7 @@ static void sh_node_tex_checker_build_multi_function( } // namespace blender::nodes -void register_node_type_sh_tex_checker(void) +void register_node_type_sh_tex_checker() { static bNodeType ntype; diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c index 26a1db1f3a6..ff08961b3e9 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c @@ -143,7 +143,7 @@ void register_node_type_sh_tex_environment(void) node_type_storage( &ntype, "NodeTexEnvironment", node_free_standard_storage, node_copy_standard_storage); node_type_gpu(&ntype, node_shader_gpu_tex_environment); - node_type_label(&ntype, node_image_label); + ntype.labelfunc = node_image_label; node_type_size_preset(&ntype, NODE_SIZE_LARGE); nodeRegisterType(&ntype); 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 33832c42b3c..48199968547 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc @@ -160,7 +160,7 @@ static void sh_node_gradient_tex_build_multi_function( } // namespace blender::nodes -void register_node_type_sh_tex_gradient(void) +void register_node_type_sh_tex_gradient() { static bNodeType ntype; 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 f20fc85cbe0..d139707c6d7 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc @@ -174,7 +174,7 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, } /* node type definition */ -void register_node_type_sh_tex_image(void) +void register_node_type_sh_tex_image() { static bNodeType ntype; @@ -184,7 +184,7 @@ void register_node_type_sh_tex_image(void) node_type_storage( &ntype, "NodeTexImage", node_free_standard_storage, node_copy_standard_storage); node_type_gpu(&ntype, node_shader_gpu_tex_image); - node_type_label(&ntype, node_image_label); + ntype.labelfunc = node_image_label; node_type_size_preset(&ntype, NODE_SIZE_LARGE); nodeRegisterType(&ntype); 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 62e68d53d03..9bd5c335cee 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc @@ -181,7 +181,7 @@ static void sh_node_magic_tex_build_multi_function( } // namespace blender::nodes -void register_node_type_sh_tex_magic(void) +void register_node_type_sh_tex_magic() { static bNodeType ntype; 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 e426d9cc49c..97ac199bc03 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc @@ -21,13 +21,18 @@ #include "BLI_noise.hh" +NODE_STORAGE_FUNCS(NodeTexMusgrave) + namespace blender::nodes { 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::Float>(N_("W")).min(-1000.0f).max(1000.0f); + 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; + }); b.add_input<decl::Float>(N_("Scale")).min(-1000.0f).max(1000.0f).default_value(5.0f); b.add_input<decl::Float>(N_("Detail")).min(0.0f).max(15.0f).default_value(2.0f); b.add_input<decl::Float>(N_("Dimension")).min(0.0f).max(1000.0f).default_value(2.0f); @@ -106,23 +111,23 @@ static int node_shader_gpu_tex_musgrave(GPUMaterial *mat, static void node_shader_update_tex_musgrave(bNodeTree *ntree, bNode *node) { - NodeTexMusgrave *tex = (NodeTexMusgrave *)node->storage; + const NodeTexMusgrave &storage = node_storage(*node); bNodeSocket *inVectorSock = nodeFindSocket(node, SOCK_IN, "Vector"); bNodeSocket *inWSock = nodeFindSocket(node, SOCK_IN, "W"); bNodeSocket *inOffsetSock = nodeFindSocket(node, SOCK_IN, "Offset"); bNodeSocket *inGainSock = nodeFindSocket(node, SOCK_IN, "Gain"); - nodeSetSocketAvailability(ntree, inVectorSock, tex->dimensions != 1); - nodeSetSocketAvailability(ntree, inWSock, tex->dimensions == 1 || tex->dimensions == 4); + nodeSetSocketAvailability(ntree, inVectorSock, storage.dimensions != 1); + nodeSetSocketAvailability(ntree, inWSock, storage.dimensions == 1 || storage.dimensions == 4); nodeSetSocketAvailability(ntree, inOffsetSock, - tex->musgrave_type != SHD_MUSGRAVE_MULTIFRACTAL && - tex->musgrave_type != SHD_MUSGRAVE_FBM); + storage.musgrave_type != SHD_MUSGRAVE_MULTIFRACTAL && + storage.musgrave_type != SHD_MUSGRAVE_FBM); nodeSetSocketAvailability(ntree, inGainSock, - tex->musgrave_type == SHD_MUSGRAVE_HYBRID_MULTIFRACTAL || - tex->musgrave_type == SHD_MUSGRAVE_RIDGED_MULTIFRACTAL); + storage.musgrave_type == SHD_MUSGRAVE_HYBRID_MULTIFRACTAL || + storage.musgrave_type == SHD_MUSGRAVE_RIDGED_MULTIFRACTAL); bNodeSocket *outFacSock = nodeFindSocket(node, SOCK_OUT, "Fac"); node_sock_label(outFacSock, "Height"); @@ -531,7 +536,7 @@ static void sh_node_musgrave_build_multi_function( } // namespace blender::nodes -void register_node_type_sh_tex_musgrave(void) +void register_node_type_sh_tex_musgrave() { static bNodeType ntype; 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 7dd2695ecf7..d7f21853a01 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc @@ -21,13 +21,18 @@ #include "BLI_noise.hh" +NODE_STORAGE_FUNCS(NodeTexNoise) + namespace blender::nodes { 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::Float>(N_("W")).min(-1000.0f).max(1000.0f); + 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; + }); b.add_input<decl::Float>(N_("Scale")).min(-1000.0f).max(1000.0f).default_value(5.0f); b.add_input<decl::Float>(N_("Detail")).min(0.0f).max(15.0f).default_value(2.0f); b.add_input<decl::Float>(N_("Roughness")) @@ -71,8 +76,8 @@ static int node_shader_gpu_tex_noise(GPUMaterial *mat, node_shader_gpu_default_tex_coord(mat, node, &in[0].link); node_shader_gpu_tex_mapping(mat, node, in, out); - NodeTexNoise *tex = (NodeTexNoise *)node->storage; - const char *name = gpu_shader_get_name(tex->dimensions); + const NodeTexNoise &storage = node_storage(*node); + const char *name = gpu_shader_get_name(storage.dimensions); return GPU_stack_link(mat, node, name, in, out); } @@ -81,9 +86,9 @@ static void node_shader_update_tex_noise(bNodeTree *ntree, bNode *node) bNodeSocket *sockVector = nodeFindSocket(node, SOCK_IN, "Vector"); bNodeSocket *sockW = nodeFindSocket(node, SOCK_IN, "W"); - NodeTexNoise *tex = (NodeTexNoise *)node->storage; - nodeSetSocketAvailability(ntree, sockVector, tex->dimensions != 1); - nodeSetSocketAvailability(ntree, sockW, tex->dimensions == 1 || tex->dimensions == 4); + const NodeTexNoise &storage = node_storage(*node); + nodeSetSocketAvailability(ntree, sockVector, storage.dimensions != 1); + nodeSetSocketAvailability(ntree, sockW, storage.dimensions == 1 || storage.dimensions == 4); } namespace blender::nodes { @@ -229,19 +234,26 @@ class NoiseFunction : public fn::MultiFunction { } } } + + ExecutionHints get_execution_hints() const override + { + ExecutionHints hints; + hints.allocates_array = false; + hints.min_grain_size = 100; + return hints; + } }; static void sh_node_noise_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder) { - bNode &node = builder.node(); - NodeTexNoise *tex = (NodeTexNoise *)node.storage; - builder.construct_and_set_matching_fn<NoiseFunction>(tex->dimensions); + const NodeTexNoise &storage = node_storage(builder.node()); + builder.construct_and_set_matching_fn<NoiseFunction>(storage.dimensions); } } // namespace blender::nodes /* node type definition */ -void register_node_type_sh_tex_noise(void) +void register_node_type_sh_tex_noise() { static bNodeType ntype; 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 1bc3741d27c..8a1170de304 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc @@ -21,20 +21,30 @@ #include "BLI_noise.hh" +NODE_STORAGE_FUNCS(NodeTexVoronoi) + namespace blender::nodes { 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::Float>(N_("W")).min(-1000.0f).max(1000.0f); + 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; + }); b.add_input<decl::Float>(N_("Scale")).min(-1000.0f).max(1000.0f).default_value(5.0f); b.add_input<decl::Float>(N_("Smoothness")) .min(0.0f) .max(1.0f) .default_value(1.0f) - .subtype(PROP_FACTOR); - b.add_input<decl::Float>(N_("Exponent")).min(0.0f).max(32.0f).default_value(0.5f); + .subtype(PROP_FACTOR) + .make_available([](bNode &node) { node_storage(node).feature = SHD_VORONOI_SMOOTH_F1; }); + b.add_input<decl::Float>(N_("Exponent")) + .min(0.0f) + .max(32.0f) + .default_value(0.5f) + .make_available([](bNode &node) { node_storage(node).distance = SHD_VORONOI_MINKOWSKI; }); b.add_input<decl::Float>(N_("Randomness")) .min(0.0f) .max(1.0f) @@ -43,8 +53,13 @@ static void sh_node_tex_voronoi_declare(NodeDeclarationBuilder &b) b.add_output<decl::Float>(N_("Distance")).no_muted_links(); b.add_output<decl::Color>(N_("Color")).no_muted_links(); b.add_output<decl::Vector>(N_("Position")).no_muted_links(); - b.add_output<decl::Float>(N_("W")).no_muted_links(); - b.add_output<decl::Float>(N_("Radius")).no_muted_links(); + b.add_output<decl::Float>(N_("W")).no_muted_links().make_available([](bNode &node) { + /* Default to 1 instead of 4, because it is much faster. */ + node_storage(node).dimensions = 1; + }); + b.add_output<decl::Float>(N_("Radius")).no_muted_links().make_available([](bNode &node) { + node_storage(node).feature = SHD_VORONOI_N_SPHERE_RADIUS; + }); }; } // namespace blender::nodes @@ -136,37 +151,40 @@ static void node_shader_update_tex_voronoi(bNodeTree *ntree, bNode *node) bNodeSocket *outWSock = nodeFindSocket(node, SOCK_OUT, "W"); bNodeSocket *outRadiusSock = nodeFindSocket(node, SOCK_OUT, "Radius"); - NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage; + const NodeTexVoronoi &storage = node_storage(*node); - nodeSetSocketAvailability(ntree, inWSock, tex->dimensions == 1 || tex->dimensions == 4); - nodeSetSocketAvailability(ntree, inVectorSock, tex->dimensions != 1); + nodeSetSocketAvailability(ntree, inWSock, storage.dimensions == 1 || storage.dimensions == 4); + nodeSetSocketAvailability(ntree, inVectorSock, storage.dimensions != 1); nodeSetSocketAvailability( ntree, inExponentSock, - tex->distance == SHD_VORONOI_MINKOWSKI && tex->dimensions != 1 && - !ELEM(tex->feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS)); - nodeSetSocketAvailability(ntree, inSmoothnessSock, tex->feature == SHD_VORONOI_SMOOTH_F1); + storage.distance == SHD_VORONOI_MINKOWSKI && storage.dimensions != 1 && + !ELEM(storage.feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS)); + nodeSetSocketAvailability(ntree, inSmoothnessSock, storage.feature == SHD_VORONOI_SMOOTH_F1); - nodeSetSocketAvailability(ntree, outDistanceSock, tex->feature != SHD_VORONOI_N_SPHERE_RADIUS); + nodeSetSocketAvailability( + ntree, outDistanceSock, storage.feature != SHD_VORONOI_N_SPHERE_RADIUS); nodeSetSocketAvailability(ntree, outColorSock, - tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE && - tex->feature != SHD_VORONOI_N_SPHERE_RADIUS); + storage.feature != SHD_VORONOI_DISTANCE_TO_EDGE && + storage.feature != SHD_VORONOI_N_SPHERE_RADIUS); nodeSetSocketAvailability(ntree, outPositionSock, - tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE && - tex->feature != SHD_VORONOI_N_SPHERE_RADIUS && - tex->dimensions != 1); + storage.feature != SHD_VORONOI_DISTANCE_TO_EDGE && + storage.feature != SHD_VORONOI_N_SPHERE_RADIUS && + storage.dimensions != 1); nodeSetSocketAvailability(ntree, outWSock, - tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE && - tex->feature != SHD_VORONOI_N_SPHERE_RADIUS && - (ELEM(tex->dimensions, 1, 4))); - nodeSetSocketAvailability(ntree, outRadiusSock, tex->feature == SHD_VORONOI_N_SPHERE_RADIUS); + storage.feature != SHD_VORONOI_DISTANCE_TO_EDGE && + storage.feature != SHD_VORONOI_N_SPHERE_RADIUS && + (ELEM(storage.dimensions, 1, 4))); + nodeSetSocketAvailability(ntree, outRadiusSock, storage.feature == SHD_VORONOI_N_SPHERE_RADIUS); } namespace blender::nodes { +static MultiFunction::ExecutionHints voronoi_execution_hints{50, false}; + class VoronoiMinowskiFunction : public fn::MultiFunction { private: int dimensions_; @@ -592,6 +610,11 @@ class VoronoiMinowskiFunction : public fn::MultiFunction { } } } + + ExecutionHints get_execution_hints() const override + { + return voronoi_execution_hints; + } }; class VoronoiMetricFunction : public fn::MultiFunction { @@ -1106,6 +1129,11 @@ class VoronoiMetricFunction : public fn::MultiFunction { } } } + + ExecutionHints get_execution_hints() const override + { + return voronoi_execution_hints; + } }; class VoronoiEdgeFunction : public fn::MultiFunction { @@ -1282,31 +1310,39 @@ class VoronoiEdgeFunction : public fn::MultiFunction { break; } } - }; + } + + ExecutionHints get_execution_hints() const override + { + return voronoi_execution_hints; + } }; static void sh_node_voronoi_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder) { - bNode &node = builder.node(); - NodeTexVoronoi *tex = (NodeTexVoronoi *)node.storage; - bool minowski = (tex->distance == SHD_VORONOI_MINKOWSKI && tex->dimensions != 1 && - !ELEM(tex->feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS)); - bool dist_radius = ELEM(tex->feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS); + const NodeTexVoronoi &storage = node_storage(builder.node()); + bool minowski = + (storage.distance == SHD_VORONOI_MINKOWSKI && storage.dimensions != 1 && + !ELEM(storage.feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS)); + bool dist_radius = ELEM( + storage.feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS); if (dist_radius) { - builder.construct_and_set_matching_fn<VoronoiEdgeFunction>(tex->dimensions, tex->feature); + builder.construct_and_set_matching_fn<VoronoiEdgeFunction>(storage.dimensions, + storage.feature); } else if (minowski) { - builder.construct_and_set_matching_fn<VoronoiMinowskiFunction>(tex->dimensions, tex->feature); + builder.construct_and_set_matching_fn<VoronoiMinowskiFunction>(storage.dimensions, + storage.feature); } else { builder.construct_and_set_matching_fn<VoronoiMetricFunction>( - tex->dimensions, tex->feature, tex->distance); + storage.dimensions, storage.feature, storage.distance); } } } // namespace blender::nodes -void register_node_type_sh_tex_voronoi(void) +void register_node_type_sh_tex_voronoi() { static bNodeType ntype; 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 fe534c605e9..d3e25b533e5 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc @@ -218,7 +218,7 @@ static void sh_node_wave_tex_build_multi_function( } // namespace blender::nodes -void register_node_type_sh_tex_wave(void) +void register_node_type_sh_tex_wave() { static bNodeType ntype; 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 7b4ff7fec5c..0e72cee38e7 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 @@ -27,7 +27,10 @@ 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::Float>(N_("W")).min(-10000.0f).max(10000.0f); + 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; + }); b.add_output<decl::Float>(N_("Value")); b.add_output<decl::Color>(N_("Color")); }; @@ -191,7 +194,7 @@ static void sh_node_noise_build_multi_function(blender::nodes::NodeMultiFunction } // namespace blender::nodes -void register_node_type_sh_tex_white_noise(void) +void register_node_type_sh_tex_white_noise() { static bNodeType ntype; diff --git a/source/blender/nodes/shader/nodes/node_shader_uvAlongStroke.c b/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.c index 05c3248af65..05c3248af65 100644 --- a/source/blender/nodes/shader/nodes/node_shader_uvAlongStroke.c +++ b/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.c diff --git a/source/blender/nodes/shader/nodes/node_shader_value.cc b/source/blender/nodes/shader/nodes/node_shader_value.cc index b0f152d8526..f0eb3ea9bee 100644 --- a/source/blender/nodes/shader/nodes/node_shader_value.cc +++ b/source/blender/nodes/shader/nodes/node_shader_value.cc @@ -49,7 +49,7 @@ static void sh_node_value_build_multi_function(blender::nodes::NodeMultiFunction builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<float>>(value->value); } -void register_node_type_sh_value(void) +void register_node_type_sh_value() { static bNodeType ntype; diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc index fad93962708..5f5969de78c 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc @@ -24,6 +24,7 @@ #include "node_shader_util.h" #include "NOD_math_functions.hh" +#include "NOD_socket_search_link.hh" namespace blender::nodes { @@ -38,6 +39,18 @@ static void sh_node_vector_math_declare(NodeDeclarationBuilder &b) b.add_output<decl::Float>(N_("Value")); }; +static void sh_node_vector_math_gather_link_searches(GatherLinkSearchOpParams ¶ms) +{ + /* For now, do something very basic (only exposing "Add", and a single "Vector" socket). */ + if (params.node_tree().typeinfo->validate_link( + static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_VECTOR)) { + params.add_item(IFACE_("Vector"), [](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("ShaderNodeVectorMath"); + params.update_and_connect_available_socket(node, "Vector"); + }); + } +} + } // namespace blender::nodes static const char *gpu_shader_get_name(int mode) @@ -201,8 +214,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_fl3_to_fl3( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{info.title_case_name, - function}; + static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{ + info.title_case_name.c_str(), function}; multi_fn = &fn; }); if (multi_fn != nullptr) { @@ -212,7 +225,7 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_fl3_fl3_to_fl3( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{ - info.title_case_name, function}; + info.title_case_name.c_str(), function}; multi_fn = &fn; }); if (multi_fn != nullptr) { @@ -222,7 +235,7 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_fl3_fl_to_fl3( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{ - info.title_case_name, function}; + info.title_case_name.c_str(), function}; multi_fn = &fn; }); if (multi_fn != nullptr) { @@ -231,8 +244,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_fl3_to_fl( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SI_SO<float3, float3, float> fn{info.title_case_name, - function}; + static blender::fn::CustomMF_SI_SI_SO<float3, float3, float> fn{ + info.title_case_name.c_str(), function}; multi_fn = &fn; }); if (multi_fn != nullptr) { @@ -241,8 +254,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_fl_to_fl3( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SI_SO<float3, float, float3> fn{info.title_case_name, - function}; + static blender::fn::CustomMF_SI_SI_SO<float3, float, float3> fn{ + info.title_case_name.c_str(), function}; multi_fn = &fn; }); if (multi_fn != nullptr) { @@ -251,7 +264,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_to_fl3( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SO<float3, float3> fn{info.title_case_name, function}; + static blender::fn::CustomMF_SI_SO<float3, float3> fn{info.title_case_name.c_str(), + function}; multi_fn = &fn; }); if (multi_fn != nullptr) { @@ -260,7 +274,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_to_fl( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SO<float3, float> fn{info.title_case_name, function}; + static blender::fn::CustomMF_SI_SO<float3, float> fn{info.title_case_name.c_str(), + function}; multi_fn = &fn; }); if (multi_fn != nullptr) { @@ -277,16 +292,17 @@ static void sh_node_vector_math_build_multi_function( builder.set_matching_fn(fn); } -void register_node_type_sh_vect_math(void) +void register_node_type_sh_vect_math() { static bNodeType ntype; sh_fn_node_type_base(&ntype, SH_NODE_VECTOR_MATH, "Vector Math", NODE_CLASS_OP_VECTOR, 0); ntype.declare = blender::nodes::sh_node_vector_math_declare; - node_type_label(&ntype, node_vector_math_label); + ntype.labelfunc = node_vector_math_label; node_type_gpu(&ntype, gpu_shader_vector_math); node_type_update(&ntype, node_shader_update_vector_math); ntype.build_multi_function = sh_node_vector_math_build_multi_function; + ntype.gather_link_search_ops = blender::nodes::sh_node_vector_math_gather_link_searches; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc index 3c1f1ed8d39..a3cb82f3245 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc @@ -205,7 +205,7 @@ static void node_shader_update_vector_rotate(bNodeTree *ntree, bNode *node) ntree, sock_angle, !ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ)); } -void register_node_type_sh_vector_rotate(void) +void register_node_type_sh_vector_rotate() { static bNodeType ntype; diff --git a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c b/source/blender/nodes/shader/nodes/node_shader_vector_transform.c index 7b08178f874..7b08178f874 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c +++ b/source/blender/nodes/shader/nodes/node_shader_vector_transform.c diff --git a/source/blender/nodes/texture/node_texture_util.c b/source/blender/nodes/texture/node_texture_util.c index c968d0bae56..fe8e68bfc42 100644 --- a/source/blender/nodes/texture/node_texture_util.c +++ b/source/blender/nodes/texture/node_texture_util.c @@ -44,7 +44,7 @@ bool tex_node_poll_default(bNodeType *UNUSED(ntype), const char **r_disabled_hint) { if (!STREQ(ntree->idname, "TextureNodeTree")) { - *r_disabled_hint = "Not a texture node tree"; + *r_disabled_hint = TIP_("Not a texture node tree"); return false; } return true; diff --git a/source/blender/nodes/texture/node_texture_util.h b/source/blender/nodes/texture/node_texture_util.h index 8f63a1ad07d..84d2c5c903a 100644 --- a/source/blender/nodes/texture/node_texture_util.h +++ b/source/blender/nodes/texture/node_texture_util.h @@ -37,8 +37,7 @@ #include "DNA_scene_types.h" #include "DNA_texture_types.h" -#include "BLI_blenlib.h" -#include "BLI_math.h" +#include "BLI_math_vector.h" #include "BLI_rand.h" #include "BLI_threads.h" #include "BLI_utildefines.h" diff --git a/source/blender/nodes/texture/nodes/node_texture_common.c b/source/blender/nodes/texture/nodes/node_texture_common.c index 868c97e5850..f873ed5e457 100644 --- a/source/blender/nodes/texture/nodes/node_texture_common.c +++ b/source/blender/nodes/texture/nodes/node_texture_common.c @@ -161,7 +161,7 @@ void register_node_type_tex_group(void) /* NOTE: Cannot use #sh_node_type_base for node group, because it would map the node type * to the shared #NODE_GROUP integer type id. */ - node_type_base_custom(&ntype, "TextureNodeGroup", "Group", NODE_CLASS_GROUP, NODE_CONST_OUTPUT); + node_type_base_custom(&ntype, "TextureNodeGroup", "Group", NODE_CLASS_GROUP, 0); ntype.type = NODE_GROUP; ntype.poll = tex_node_poll_default; ntype.poll_instance = node_group_poll_instance; @@ -172,7 +172,7 @@ void register_node_type_tex_group(void) node_type_socket_templates(&ntype, NULL, NULL); node_type_size(&ntype, 140, 60, 400); - node_type_label(&ntype, node_group_label); + ntype.labelfunc = node_group_label; node_type_group_update(&ntype, node_group_update); node_type_exec(&ntype, group_initexec, group_freeexec, group_execute); diff --git a/source/blender/nodes/texture/nodes/node_texture_distance.c b/source/blender/nodes/texture/nodes/node_texture_distance.c index f7deac9ff4a..c2241858737 100644 --- a/source/blender/nodes/texture/nodes/node_texture_distance.c +++ b/source/blender/nodes/texture/nodes/node_texture_distance.c @@ -21,7 +21,6 @@ * \ingroup texnodes */ -#include "BLI_math.h" #include "NOD_texture.h" #include "node_texture_util.h" #include <math.h> diff --git a/source/blender/nodes/texture/nodes/node_texture_image.c b/source/blender/nodes/texture/nodes/node_texture_image.c index a85b963286b..9c61405ea23 100644 --- a/source/blender/nodes/texture/nodes/node_texture_image.c +++ b/source/blender/nodes/texture/nodes/node_texture_image.c @@ -113,7 +113,7 @@ void register_node_type_tex_image(void) node_type_init(&ntype, init); node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage); node_type_exec(&ntype, NULL, NULL, exec); - node_type_label(&ntype, node_image_label); + ntype.labelfunc = node_image_label; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_math.c b/source/blender/nodes/texture/nodes/node_texture_math.c index ab226a4dd38..9e37f4ee643 100644 --- a/source/blender/nodes/texture/nodes/node_texture_math.c +++ b/source/blender/nodes/texture/nodes/node_texture_math.c @@ -337,7 +337,7 @@ void register_node_type_tex_math(void) tex_node_type_base(&ntype, TEX_NODE_MATH, "Math", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, inputs, outputs); - node_type_label(&ntype, node_math_label); + ntype.labelfunc = node_math_label; node_type_storage(&ntype, "", NULL, NULL); node_type_exec(&ntype, NULL, NULL, exec); node_type_update(&ntype, node_math_update); diff --git a/source/blender/nodes/texture/nodes/node_texture_mixRgb.c b/source/blender/nodes/texture/nodes/node_texture_mixRgb.c index b1aeb269018..044875cce90 100644 --- a/source/blender/nodes/texture/nodes/node_texture_mixRgb.c +++ b/source/blender/nodes/texture/nodes/node_texture_mixRgb.c @@ -71,7 +71,7 @@ void register_node_type_tex_mix_rgb(void) tex_node_type_base(&ntype, TEX_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, 0); node_type_socket_templates(&ntype, inputs, outputs); - node_type_label(&ntype, node_blend_label); + ntype.labelfunc = node_blend_label; node_type_exec(&ntype, NULL, NULL, exec); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/texture/nodes/node_texture_output.c b/source/blender/nodes/texture/nodes/node_texture_output.c index 9145df0038b..19e24c9f82a 100644 --- a/source/blender/nodes/texture/nodes/node_texture_output.c +++ b/source/blender/nodes/texture/nodes/node_texture_output.c @@ -21,6 +21,8 @@ * \ingroup texnodes */ +#include "BLI_string.h" + #include "NOD_texture.h" #include "node_texture_util.h" |