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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/nodes')
-rw-r--r--source/blender/nodes/CMakeLists.txt270
-rw-r--r--source/blender/nodes/NOD_composite.h2
-rw-r--r--source/blender/nodes/NOD_function.h6
-rw-r--r--source/blender/nodes/NOD_geometry.h21
-rw-r--r--source/blender/nodes/NOD_geometry_exec.hh2
-rw-r--r--source/blender/nodes/NOD_node_declaration.hh181
-rw-r--r--source/blender/nodes/NOD_node_tree_ref.hh26
-rw-r--r--source/blender/nodes/NOD_shader.h1
-rw-r--r--source/blender/nodes/NOD_static_types.h42
-rw-r--r--source/blender/nodes/composite/node_composite_tree.cc (renamed from source/blender/nodes/composite/node_composite_tree.c)82
-rw-r--r--source/blender/nodes/composite/node_composite_util.cc (renamed from source/blender/nodes/composite/node_composite_util.c)7
-rw-r--r--source/blender/nodes/composite/node_composite_util.hh (renamed from source/blender/nodes/composite/node_composite_util.h)11
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_alphaOver.cc (renamed from source/blender/nodes/composite/nodes/node_composite_alphaOver.c)26
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_antialiasing.cc (renamed from source/blender/nodes/composite/nodes/node_composite_antialiasing.c)5
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc (renamed from source/blender/nodes/composite/nodes/node_composite_bilateralblur.c)6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_blur.cc (renamed from source/blender/nodes/composite/nodes/node_composite_blur.c)4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_bokehblur.cc (renamed from source/blender/nodes/composite/nodes/node_composite_bokehblur.c)2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_bokehimage.cc (renamed from source/blender/nodes/composite/nodes/node_composite_bokehimage.c)18
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_boxmask.cc (renamed from source/blender/nodes/composite/nodes/node_composite_boxmask.c)4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_brightness.cc (renamed from source/blender/nodes/composite/nodes/node_composite_brightness.c)27
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_channelMatte.cc (renamed from source/blender/nodes/composite/nodes/node_composite_channelMatte.c)4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc (renamed from source/blender/nodes/composite/nodes/node_composite_chromaMatte.c)4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorMatte.cc (renamed from source/blender/nodes/composite/nodes/node_composite_colorMatte.c)4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorSpill.cc (renamed from source/blender/nodes/composite/nodes/node_composite_colorSpill.c)4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorbalance.cc (renamed from source/blender/nodes/composite/nodes/node_composite_colorbalance.c)37
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc (renamed from source/blender/nodes/composite/nodes/node_composite_colorcorrection.c)30
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_common.cc (renamed from source/blender/nodes/composite/nodes/node_composite_common.c)12
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_composite.cc (renamed from source/blender/nodes/composite/nodes/node_composite_composite.c)23
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_cornerpin.cc (renamed from source/blender/nodes/composite/nodes/node_composite_cornerpin.c)2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_crop.cc (renamed from source/blender/nodes/composite/nodes/node_composite_crop.c)4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_curves.cc (renamed from source/blender/nodes/composite/nodes/node_composite_curves.c)43
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_defocus.cc (renamed from source/blender/nodes/composite/nodes/node_composite_defocus.c)10
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_denoise.cc (renamed from source/blender/nodes/composite/nodes/node_composite_denoise.c)4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_despeckle.cc (renamed from source/blender/nodes/composite/nodes/node_composite_despeckle.c)2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_diffMatte.cc (renamed from source/blender/nodes/composite/nodes/node_composite_diffMatte.c)4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_dilate.cc (renamed from source/blender/nodes/composite/nodes/node_composite_dilate.c)5
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_directionalblur.cc (renamed from source/blender/nodes/composite/nodes/node_composite_directionalblur.c)4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_displace.cc (renamed from source/blender/nodes/composite/nodes/node_composite_displace.c)2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc (renamed from source/blender/nodes/composite/nodes/node_composite_distanceMatte.c)4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc (renamed from source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.c)2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc (renamed from source/blender/nodes/composite/nodes/node_composite_ellipsemask.c)5
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_exposure.cc (renamed from source/blender/nodes/composite/nodes/node_composite_exposure.c)23
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_filter.cc (renamed from source/blender/nodes/composite/nodes/node_composite_filter.c)2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_flip.cc (renamed from source/blender/nodes/composite/nodes/node_composite_flip.c)2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_gamma.cc (renamed from source/blender/nodes/composite/nodes/node_composite_gamma.c)24
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_glare.cc (renamed from source/blender/nodes/composite/nodes/node_composite_glare.c)4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc (renamed from source/blender/nodes/composite/nodes/node_composite_hueSatVal.c)34
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_huecorrect.cc (renamed from source/blender/nodes/composite/nodes/node_composite_huecorrect.c)29
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_idMask.cc (renamed from source/blender/nodes/composite/nodes/node_composite_idMask.c)21
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_image.cc (renamed from source/blender/nodes/composite/nodes/node_composite_image.c)108
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_inpaint.cc (renamed from source/blender/nodes/composite/nodes/node_composite_inpaint.c)2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_invert.cc (renamed from source/blender/nodes/composite/nodes/node_composite_invert.c)19
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_keying.cc (renamed from source/blender/nodes/composite/nodes/node_composite_keying.c)7
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc (renamed from source/blender/nodes/composite/nodes/node_composite_keyingscreen.c)10
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_lensdist.cc (renamed from source/blender/nodes/composite/nodes/node_composite_lensdist.c)4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_levels.cc (renamed from source/blender/nodes/composite/nodes/node_composite_levels.c)23
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc (renamed from source/blender/nodes/composite/nodes/node_composite_lummaMatte.c)4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mapRange.cc (renamed from source/blender/nodes/composite/nodes/node_composite_mapRange.c)2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mapUV.cc (renamed from source/blender/nodes/composite/nodes/node_composite_mapUV.c)2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mapValue.cc (renamed from source/blender/nodes/composite/nodes/node_composite_mapValue.c)2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mask.cc (renamed from source/blender/nodes/composite/nodes/node_composite_mask.c)19
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_math.cc (renamed from source/blender/nodes/composite/nodes/node_composite_math.c)21
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mixrgb.cc (renamed from source/blender/nodes/composite/nodes/node_composite_mixrgb.c)26
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_movieclip.cc (renamed from source/blender/nodes/composite/nodes/node_composite_movieclip.c)31
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc (renamed from source/blender/nodes/composite/nodes/node_composite_moviedistortion.c)12
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_normal.cc (renamed from source/blender/nodes/composite/nodes/node_composite_normal.c)2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_normalize.cc (renamed from source/blender/nodes/composite/nodes/node_composite_normalize.c)2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_outputFile.cc (renamed from source/blender/nodes/composite/nodes/node_composite_outputFile.c)81
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_pixelate.cc (renamed from source/blender/nodes/composite/nodes/node_composite_pixelate.c)2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc (renamed from source/blender/nodes/composite/nodes/node_composite_planetrackdeform.c)6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_posterize.cc (renamed from source/blender/nodes/composite/nodes/node_composite_posterize.c)2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_premulkey.cc (renamed from source/blender/nodes/composite/nodes/node_composite_premulkey.c)21
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_rgb.cc (renamed from source/blender/nodes/composite/nodes/node_composite_rgb.c)17
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_rotate.cc (renamed from source/blender/nodes/composite/nodes/node_composite_rotate.c)2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_scale.cc (renamed from source/blender/nodes/composite/nodes/node_composite_scale.c)4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc (renamed from source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.c)55
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc (renamed from source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.c)53
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc (renamed from source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.c)52
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc (renamed from source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.c)52
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_setalpha.cc (renamed from source/blender/nodes/composite/nodes/node_composite_setalpha.c)26
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_splitViewer.cc (renamed from source/blender/nodes/composite/nodes/node_composite_splitViewer.c)23
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc (renamed from source/blender/nodes/composite/nodes/node_composite_stabilize2d.c)4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sunbeams.cc (renamed from source/blender/nodes/composite/nodes/node_composite_sunbeams.c)5
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_switch.cc (renamed from source/blender/nodes/composite/nodes/node_composite_switch.c)2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_switchview.cc (renamed from source/blender/nodes/composite/nodes/node_composite_switchview.c)37
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_texture.cc (renamed from source/blender/nodes/composite/nodes/node_composite_texture.c)30
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_tonemap.cc (renamed from source/blender/nodes/composite/nodes/node_composite_tonemap.c)23
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_trackpos.cc (renamed from source/blender/nodes/composite/nodes/node_composite_trackpos.c)23
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_transform.cc (renamed from source/blender/nodes/composite/nodes/node_composite_transform.c)2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_translate.cc (renamed from source/blender/nodes/composite/nodes/node_composite_translate.c)5
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_valToRgb.cc (renamed from source/blender/nodes/composite/nodes/node_composite_valToRgb.c)44
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_value.cc (renamed from source/blender/nodes/composite/nodes/node_composite_value.c)17
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_vecBlur.cc (renamed from source/blender/nodes/composite/nodes/node_composite_vecBlur.c)6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_viewer.cc (renamed from source/blender/nodes/composite/nodes/node_composite_viewer.c)24
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_zcombine.cc (renamed from source/blender/nodes/composite/nodes/node_composite_zcombine.c)32
-rw-r--r--source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc (renamed from source/blender/nodes/function/nodes/node_fn_random_float.cc)13
-rw-r--r--source/blender/nodes/function/nodes/node_fn_boolean_math.cc1
-rw-r--r--source/blender/nodes/function/nodes/node_fn_float_compare.cc1
-rw-r--r--source/blender/nodes/function/nodes/node_fn_float_to_int.cc1
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_special_characters.cc74
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_string.cc1
-rw-r--r--source/blender/nodes/function/nodes/node_fn_random_value.cc299
-rw-r--r--source/blender/nodes/function/nodes/node_fn_rotate_euler.cc138
-rw-r--r--source/blender/nodes/function/nodes/node_fn_string_length.cc1
-rw-r--r--source/blender/nodes/function/nodes/node_fn_string_substring.cc1
-rw-r--r--source/blender/nodes/function/nodes/node_fn_value_to_string.cc1
-rw-r--r--source/blender/nodes/geometry/node_geometry_tree.cc2
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.hh4
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc)0
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_clamp.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc)2
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_color_ramp.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc)0
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc)0
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_compare.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc)0
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_convert.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_attribute_convert.cc)0
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_curve_map.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_attribute_curve_map.cc)0
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_fill.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc)0
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_map_range.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc)0
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_math.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc)0
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_mix.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc)0
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_proximity.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc)2
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_randomize.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc)26
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_sample_texture.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc)0
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc)0
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_transfer.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_attribute_transfer.cc)2
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_math.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc)0
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_attribute_vector_rotate.cc)2
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_curve_endpoints.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_curve_endpoints.cc)3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_curve_reverse.cc71
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_curve_select_by_handle_type.cc)0
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_curve_set_handles.cc144
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_curve_spline_type.cc302
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc392
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_curve_to_points.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc)3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_delete_geometry.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc)0
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_edge_split.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_edge_split.cc)2
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_mesh_to_curve.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc)0
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_point_distribute.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc)1
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_point_instance.cc)0
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_point_rotate.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_point_rotate.cc)0
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_point_scale.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_point_scale.cc)0
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_point_separate.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_point_separate.cc)0
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_point_translate.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_point_translate.cc)0
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_points_to_volume.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc)0
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_raycast.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_raycast.cc)0
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_subdivision_surface.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc)2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc22
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_boolean.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_collection_info.cc73
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc64
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc19
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc47
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_length.cc1
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc67
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc43
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc98
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc72
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc70
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc55
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc43
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc594
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_index.cc22
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_normal.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_position.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc109
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc207
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_material_assign.cc29
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_material_replace.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_material_selection.cc11
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc897
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc64
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc47
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc189
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc118
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_proximity.cc235
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_separate_components.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_position.cc7
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc306
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_switch.cc198
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_triangulate.cc16
-rw-r--r--source/blender/nodes/intern/geometry_nodes_eval_log.cc19
-rw-r--r--source/blender/nodes/intern/node_common.cc (renamed from source/blender/nodes/intern/node_common.c)256
-rw-r--r--source/blender/nodes/intern/node_socket.cc2
-rw-r--r--source/blender/nodes/intern/node_tree_ref.cc103
-rw-r--r--source/blender/nodes/shader/node_shader_tree.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_brightness.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_clamp.cc1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_curves.cc140
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_hair_info.c7
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_map_range.cc1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_math.cc1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mixRgb.cc1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_noise.cc3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_valToRgb.cc1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_math.cc1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc5
-rw-r--r--source/blender/nodes/texture/node_texture_tree.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_curves.c2
210 files changed, 6044 insertions, 1834 deletions
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index e6af3ecafbc..903a30dd383 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -45,137 +45,159 @@ set(INC
set(SRC
- composite/nodes/node_composite_alphaOver.c
- composite/nodes/node_composite_antialiasing.c
- composite/nodes/node_composite_bilateralblur.c
- composite/nodes/node_composite_blur.c
- composite/nodes/node_composite_bokehblur.c
- composite/nodes/node_composite_bokehimage.c
- composite/nodes/node_composite_boxmask.c
- composite/nodes/node_composite_brightness.c
- composite/nodes/node_composite_channelMatte.c
- composite/nodes/node_composite_chromaMatte.c
- composite/nodes/node_composite_colorMatte.c
- composite/nodes/node_composite_colorSpill.c
- composite/nodes/node_composite_colorbalance.c
- composite/nodes/node_composite_colorcorrection.c
- composite/nodes/node_composite_common.c
- composite/nodes/node_composite_composite.c
- composite/nodes/node_composite_cornerpin.c
- composite/nodes/node_composite_crop.c
+ composite/nodes/node_composite_alphaOver.cc
+ composite/nodes/node_composite_antialiasing.cc
+ composite/nodes/node_composite_bilateralblur.cc
+ composite/nodes/node_composite_blur.cc
+ composite/nodes/node_composite_bokehblur.cc
+ composite/nodes/node_composite_bokehimage.cc
+ composite/nodes/node_composite_boxmask.cc
+ composite/nodes/node_composite_brightness.cc
+ composite/nodes/node_composite_channelMatte.cc
+ composite/nodes/node_composite_chromaMatte.cc
+ composite/nodes/node_composite_colorMatte.cc
+ composite/nodes/node_composite_colorSpill.cc
+ composite/nodes/node_composite_colorbalance.cc
+ composite/nodes/node_composite_colorcorrection.cc
+ composite/nodes/node_composite_common.cc
+ composite/nodes/node_composite_composite.cc
+ composite/nodes/node_composite_cornerpin.cc
+ composite/nodes/node_composite_crop.cc
composite/nodes/node_composite_cryptomatte.cc
- composite/nodes/node_composite_curves.c
- composite/nodes/node_composite_defocus.c
- composite/nodes/node_composite_denoise.c
- composite/nodes/node_composite_despeckle.c
- composite/nodes/node_composite_diffMatte.c
- composite/nodes/node_composite_dilate.c
- composite/nodes/node_composite_directionalblur.c
- composite/nodes/node_composite_displace.c
- composite/nodes/node_composite_distanceMatte.c
- composite/nodes/node_composite_doubleEdgeMask.c
- composite/nodes/node_composite_ellipsemask.c
- composite/nodes/node_composite_exposure.c
- composite/nodes/node_composite_filter.c
- composite/nodes/node_composite_flip.c
- composite/nodes/node_composite_gamma.c
- composite/nodes/node_composite_glare.c
- composite/nodes/node_composite_hueSatVal.c
- composite/nodes/node_composite_huecorrect.c
- composite/nodes/node_composite_idMask.c
- composite/nodes/node_composite_image.c
- composite/nodes/node_composite_inpaint.c
- composite/nodes/node_composite_invert.c
- composite/nodes/node_composite_keying.c
- composite/nodes/node_composite_keyingscreen.c
- composite/nodes/node_composite_lensdist.c
- composite/nodes/node_composite_levels.c
- composite/nodes/node_composite_lummaMatte.c
- composite/nodes/node_composite_mapRange.c
- composite/nodes/node_composite_mapUV.c
- composite/nodes/node_composite_mapValue.c
- composite/nodes/node_composite_mask.c
- composite/nodes/node_composite_math.c
- composite/nodes/node_composite_mixrgb.c
- composite/nodes/node_composite_movieclip.c
- composite/nodes/node_composite_moviedistortion.c
- composite/nodes/node_composite_normal.c
- composite/nodes/node_composite_normalize.c
- composite/nodes/node_composite_outputFile.c
- composite/nodes/node_composite_pixelate.c
- composite/nodes/node_composite_planetrackdeform.c
- composite/nodes/node_composite_posterize.c
- composite/nodes/node_composite_premulkey.c
- composite/nodes/node_composite_rgb.c
- composite/nodes/node_composite_rotate.c
- composite/nodes/node_composite_scale.c
- composite/nodes/node_composite_sepcombHSVA.c
- composite/nodes/node_composite_sepcombRGBA.c
- composite/nodes/node_composite_sepcombYCCA.c
- composite/nodes/node_composite_sepcombYUVA.c
- composite/nodes/node_composite_setalpha.c
- composite/nodes/node_composite_splitViewer.c
- composite/nodes/node_composite_stabilize2d.c
- composite/nodes/node_composite_sunbeams.c
- composite/nodes/node_composite_switch.c
- composite/nodes/node_composite_switchview.c
- composite/nodes/node_composite_texture.c
- composite/nodes/node_composite_tonemap.c
- composite/nodes/node_composite_trackpos.c
- composite/nodes/node_composite_transform.c
- composite/nodes/node_composite_translate.c
- composite/nodes/node_composite_valToRgb.c
- composite/nodes/node_composite_value.c
- composite/nodes/node_composite_vecBlur.c
- composite/nodes/node_composite_viewer.c
- composite/nodes/node_composite_zcombine.c
+ composite/nodes/node_composite_curves.cc
+ composite/nodes/node_composite_defocus.cc
+ composite/nodes/node_composite_denoise.cc
+ composite/nodes/node_composite_despeckle.cc
+ composite/nodes/node_composite_diffMatte.cc
+ composite/nodes/node_composite_dilate.cc
+ composite/nodes/node_composite_directionalblur.cc
+ composite/nodes/node_composite_displace.cc
+ composite/nodes/node_composite_distanceMatte.cc
+ composite/nodes/node_composite_doubleEdgeMask.cc
+ composite/nodes/node_composite_ellipsemask.cc
+ composite/nodes/node_composite_exposure.cc
+ composite/nodes/node_composite_filter.cc
+ composite/nodes/node_composite_flip.cc
+ composite/nodes/node_composite_gamma.cc
+ composite/nodes/node_composite_glare.cc
+ composite/nodes/node_composite_hueSatVal.cc
+ composite/nodes/node_composite_huecorrect.cc
+ composite/nodes/node_composite_idMask.cc
+ composite/nodes/node_composite_image.cc
+ composite/nodes/node_composite_inpaint.cc
+ composite/nodes/node_composite_invert.cc
+ composite/nodes/node_composite_keying.cc
+ composite/nodes/node_composite_keyingscreen.cc
+ composite/nodes/node_composite_lensdist.cc
+ composite/nodes/node_composite_levels.cc
+ composite/nodes/node_composite_lummaMatte.cc
+ composite/nodes/node_composite_mapRange.cc
+ composite/nodes/node_composite_mapUV.cc
+ composite/nodes/node_composite_mapValue.cc
+ composite/nodes/node_composite_mask.cc
+ composite/nodes/node_composite_math.cc
+ composite/nodes/node_composite_mixrgb.cc
+ composite/nodes/node_composite_movieclip.cc
+ composite/nodes/node_composite_moviedistortion.cc
+ composite/nodes/node_composite_normal.cc
+ composite/nodes/node_composite_normalize.cc
+ composite/nodes/node_composite_outputFile.cc
+ composite/nodes/node_composite_pixelate.cc
+ composite/nodes/node_composite_planetrackdeform.cc
+ composite/nodes/node_composite_posterize.cc
+ composite/nodes/node_composite_premulkey.cc
+ composite/nodes/node_composite_rgb.cc
+ composite/nodes/node_composite_rotate.cc
+ composite/nodes/node_composite_scale.cc
+ composite/nodes/node_composite_sepcombHSVA.cc
+ composite/nodes/node_composite_sepcombRGBA.cc
+ composite/nodes/node_composite_sepcombYCCA.cc
+ composite/nodes/node_composite_sepcombYUVA.cc
+ composite/nodes/node_composite_setalpha.cc
+ composite/nodes/node_composite_splitViewer.cc
+ composite/nodes/node_composite_stabilize2d.cc
+ composite/nodes/node_composite_sunbeams.cc
+ composite/nodes/node_composite_switch.cc
+ composite/nodes/node_composite_switchview.cc
+ composite/nodes/node_composite_texture.cc
+ composite/nodes/node_composite_tonemap.cc
+ composite/nodes/node_composite_trackpos.cc
+ composite/nodes/node_composite_transform.cc
+ composite/nodes/node_composite_translate.cc
+ composite/nodes/node_composite_valToRgb.cc
+ composite/nodes/node_composite_value.cc
+ composite/nodes/node_composite_vecBlur.cc
+ composite/nodes/node_composite_viewer.cc
+ composite/nodes/node_composite_zcombine.cc
- composite/node_composite_tree.c
- composite/node_composite_util.c
+ composite/node_composite_tree.cc
+ composite/node_composite_util.cc
+
+ function/nodes/legacy/node_fn_random_float.cc
function/nodes/node_fn_boolean_math.cc
function/nodes/node_fn_float_compare.cc
function/nodes/node_fn_float_to_int.cc
+ function/nodes/node_fn_input_special_characters.cc
function/nodes/node_fn_input_string.cc
function/nodes/node_fn_input_vector.cc
- function/nodes/node_fn_random_float.cc
+ function/nodes/node_fn_random_value.cc
+ function/nodes/node_fn_rotate_euler.cc
function/nodes/node_fn_string_length.cc
function/nodes/node_fn_string_substring.cc
function/nodes/node_fn_value_to_string.cc
function/node_function_util.cc
+ geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc
+ geometry/nodes/legacy/node_geo_attribute_clamp.cc
+ geometry/nodes/legacy/node_geo_attribute_color_ramp.cc
+ geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc
+ geometry/nodes/legacy/node_geo_attribute_compare.cc
+ geometry/nodes/legacy/node_geo_attribute_convert.cc
+ geometry/nodes/legacy/node_geo_attribute_curve_map.cc
+ geometry/nodes/legacy/node_geo_attribute_fill.cc
+ geometry/nodes/legacy/node_geo_attribute_map_range.cc
+ geometry/nodes/legacy/node_geo_attribute_math.cc
+ geometry/nodes/legacy/node_geo_attribute_mix.cc
+ geometry/nodes/legacy/node_geo_attribute_proximity.cc
+ geometry/nodes/legacy/node_geo_attribute_randomize.cc
+ geometry/nodes/legacy/node_geo_attribute_sample_texture.cc
+ geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc
+ geometry/nodes/legacy/node_geo_attribute_transfer.cc
+ geometry/nodes/legacy/node_geo_attribute_vector_math.cc
+ geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc
+ geometry/nodes/legacy/node_geo_curve_endpoints.cc
+ geometry/nodes/legacy/node_geo_curve_reverse.cc
+ geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc
+ geometry/nodes/legacy/node_geo_curve_set_handles.cc
+ geometry/nodes/legacy/node_geo_curve_spline_type.cc
+ geometry/nodes/legacy/node_geo_curve_subdivide.cc
+ geometry/nodes/legacy/node_geo_curve_to_points.cc
+ geometry/nodes/legacy/node_geo_delete_geometry.cc
+ geometry/nodes/legacy/node_geo_edge_split.cc
geometry/nodes/legacy/node_geo_material_assign.cc
+ geometry/nodes/legacy/node_geo_mesh_to_curve.cc
+ geometry/nodes/legacy/node_geo_point_distribute.cc
+ geometry/nodes/legacy/node_geo_point_instance.cc
+ geometry/nodes/legacy/node_geo_point_rotate.cc
+ geometry/nodes/legacy/node_geo_point_scale.cc
+ geometry/nodes/legacy/node_geo_point_separate.cc
+ geometry/nodes/legacy/node_geo_point_translate.cc
+ geometry/nodes/legacy/node_geo_points_to_volume.cc
+ geometry/nodes/legacy/node_geo_raycast.cc
geometry/nodes/legacy/node_geo_select_by_material.cc
+ geometry/nodes/legacy/node_geo_subdivision_surface.cc
- geometry/nodes/node_geo_align_rotation_to_vector.cc
geometry/nodes/node_geo_attribute_capture.cc
- geometry/nodes/node_geo_attribute_clamp.cc
- geometry/nodes/node_geo_attribute_color_ramp.cc
- geometry/nodes/node_geo_attribute_combine_xyz.cc
- geometry/nodes/node_geo_attribute_compare.cc
- geometry/nodes/node_geo_attribute_convert.cc
- geometry/nodes/node_geo_attribute_curve_map.cc
- geometry/nodes/node_geo_attribute_fill.cc
- geometry/nodes/node_geo_attribute_map_range.cc
- geometry/nodes/node_geo_attribute_math.cc
- geometry/nodes/node_geo_attribute_mix.cc
- geometry/nodes/node_geo_attribute_proximity.cc
- geometry/nodes/node_geo_attribute_randomize.cc
geometry/nodes/node_geo_attribute_remove.cc
- geometry/nodes/node_geo_attribute_sample_texture.cc
- geometry/nodes/node_geo_attribute_separate_xyz.cc
geometry/nodes/node_geo_attribute_statistic.cc
- geometry/nodes/node_geo_attribute_transfer.cc
- geometry/nodes/node_geo_attribute_vector_math.cc
- geometry/nodes/node_geo_attribute_vector_rotate.cc
geometry/nodes/node_geo_boolean.cc
geometry/nodes/node_geo_bounding_box.cc
geometry/nodes/node_geo_collection_info.cc
geometry/nodes/node_geo_common.cc
geometry/nodes/node_geo_convex_hull.cc
- geometry/nodes/node_geo_curve_sample.cc
- geometry/nodes/node_geo_curve_endpoints.cc
geometry/nodes/node_geo_curve_fill.cc
+ geometry/nodes/node_geo_curve_fillet.cc
geometry/nodes/node_geo_curve_length.cc
geometry/nodes/node_geo_curve_parameter.cc
geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
@@ -187,21 +209,20 @@ set(SRC
geometry/nodes/node_geo_curve_primitive_star.cc
geometry/nodes/node_geo_curve_resample.cc
geometry/nodes/node_geo_curve_reverse.cc
- geometry/nodes/node_geo_curve_select_by_handle_type.cc
+ geometry/nodes/node_geo_curve_sample.cc
geometry/nodes/node_geo_curve_set_handles.cc
geometry/nodes/node_geo_curve_spline_type.cc
geometry/nodes/node_geo_curve_subdivide.cc
- geometry/nodes/node_geo_curve_fillet.cc
geometry/nodes/node_geo_curve_to_mesh.cc
- geometry/nodes/node_geo_curve_to_points.cc
geometry/nodes/node_geo_curve_trim.cc
- geometry/nodes/node_geo_delete_geometry.cc
- geometry/nodes/node_geo_edge_split.cc
+ geometry/nodes/node_geo_distribute_points_on_faces.cc
+ geometry/nodes/node_geo_input_index.cc
geometry/nodes/node_geo_input_material.cc
geometry/nodes/node_geo_input_normal.cc
geometry/nodes/node_geo_input_position.cc
+ geometry/nodes/node_geo_input_spline_length.cc
geometry/nodes/node_geo_input_tangent.cc
- geometry/nodes/node_geo_input_index.cc
+ geometry/nodes/node_geo_instance_on_points.cc
geometry/nodes/node_geo_is_viewport.cc
geometry/nodes/node_geo_join_geometry.cc
geometry/nodes/node_geo_material_assign.cc
@@ -216,26 +237,21 @@ set(SRC
geometry/nodes/node_geo_mesh_primitive_line.cc
geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
geometry/nodes/node_geo_mesh_subdivide.cc
- geometry/nodes/node_geo_mesh_to_curve.cc
+ geometry/nodes/node_geo_mesh_to_points.cc
geometry/nodes/node_geo_object_info.cc
- geometry/nodes/node_geo_point_distribute.cc
- geometry/nodes/node_geo_point_instance.cc
- geometry/nodes/node_geo_point_rotate.cc
- geometry/nodes/node_geo_point_scale.cc
- geometry/nodes/node_geo_point_separate.cc
- geometry/nodes/node_geo_point_translate.cc
- geometry/nodes/node_geo_points_to_volume.cc
- geometry/nodes/node_geo_raycast.cc
+ geometry/nodes/node_geo_points_to_vertices.cc
+ geometry/nodes/node_geo_proximity.cc
geometry/nodes/node_geo_realize_instances.cc
geometry/nodes/node_geo_separate_components.cc
geometry/nodes/node_geo_set_position.cc
geometry/nodes/node_geo_string_join.cc
- geometry/nodes/node_geo_subdivision_surface.cc
+ geometry/nodes/node_geo_string_to_curves.cc
geometry/nodes/node_geo_switch.cc
geometry/nodes/node_geo_transform.cc
geometry/nodes/node_geo_triangulate.cc
geometry/nodes/node_geo_viewer.cc
geometry/nodes/node_geo_volume_to_mesh.cc
+
geometry/node_geometry_exec.cc
geometry/node_geometry_tree.cc
geometry/node_geometry_util.cc
@@ -362,18 +378,18 @@ set(SRC
intern/derived_node_tree.cc
intern/geometry_nodes_eval_log.cc
intern/math_functions.cc
- intern/node_common.c
+ intern/node_common.cc
+ intern/node_declaration.cc
intern/node_exec.cc
intern/node_geometry_exec.cc
intern/node_multi_function.cc
- intern/node_declaration.cc
- intern/node_socket_declarations.cc
intern/node_socket.cc
+ intern/node_socket_declarations.cc
intern/node_tree_ref.cc
intern/node_util.c
intern/type_conversions.cc
- composite/node_composite_util.h
+ composite/node_composite_util.hh
function/node_function_util.hh
shader/node_shader_util.h
geometry/node_geometry_util.hh
@@ -389,10 +405,10 @@ set(SRC
NOD_math_functions.hh
NOD_multi_function.hh
NOD_node_declaration.hh
- NOD_socket_declarations.hh
NOD_node_tree_ref.hh
NOD_shader.h
NOD_socket.h
+ NOD_socket_declarations.hh
NOD_static_types.h
NOD_texture.h
NOD_type_conversions.hh
diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h
index 2cbbd31c97a..d243577f68d 100644
--- a/source/blender/nodes/NOD_composite.h
+++ b/source/blender/nodes/NOD_composite.h
@@ -145,7 +145,7 @@ void node_cmp_rlayers_register_pass(struct bNodeTree *ntree,
struct Scene *scene,
struct ViewLayer *view_layer,
const char *name,
- int type);
+ eNodeSocketDatatype type);
const char *node_cmp_rlayers_sock_to_pass(int sock_index);
void register_node_type_cmp_custom_group(bNodeType *ntype);
diff --git a/source/blender/nodes/NOD_function.h b/source/blender/nodes/NOD_function.h
index a67458418f2..450e999bea4 100644
--- a/source/blender/nodes/NOD_function.h
+++ b/source/blender/nodes/NOD_function.h
@@ -20,12 +20,16 @@
extern "C" {
#endif
+void register_node_type_fn_legacy_random_float(void);
+
void register_node_type_fn_boolean_math(void);
void register_node_type_fn_float_compare(void);
void register_node_type_fn_float_to_int(void);
+void register_node_type_fn_input_special_characters(void);
void register_node_type_fn_input_string(void);
void register_node_type_fn_input_vector(void);
-void register_node_type_fn_random_float(void);
+void register_node_type_fn_random_value(void);
+void register_node_type_fn_rotate_euler(void);
void register_node_type_fn_string_length(void);
void register_node_type_fn_string_substring(void);
void register_node_type_fn_value_to_string(void);
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index 47bc54132eb..bb90c7b6c51 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -29,10 +29,17 @@ void register_node_tree_type_geo(void);
void register_node_type_geo_group(void);
void register_node_type_geo_custom_group(bNodeType *ntype);
+void register_node_type_geo_legacy_curve_set_handles(void);
+void register_node_type_geo_legacy_attribute_proximity(void);
+void register_node_type_geo_legacy_attribute_randomize(void);
void register_node_type_geo_legacy_material_assign(void);
void register_node_type_geo_legacy_select_by_material(void);
+void register_node_type_geo_legacy_curve_spline_type(void);
+void register_node_type_geo_legacy_curve_reverse(void);
+void register_node_type_geo_legacy_curve_subdivide(void);
void register_node_type_geo_align_rotation_to_vector(void);
+void register_node_type_geo_attribute_capture(void);
void register_node_type_geo_attribute_clamp(void);
void register_node_type_geo_attribute_color_ramp(void);
void register_node_type_geo_attribute_combine_xyz(void);
@@ -40,12 +47,9 @@ 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_fill(void);
-void register_node_type_geo_attribute_capture(void);
void register_node_type_geo_attribute_map_range(void);
void register_node_type_geo_attribute_math(void);
void register_node_type_geo_attribute_mix(void);
-void register_node_type_geo_attribute_proximity(void);
-void register_node_type_geo_attribute_randomize(void);
void register_node_type_geo_attribute_remove(void);
void register_node_type_geo_attribute_separate_xyz(void);
void register_node_type_geo_attribute_statistic(void);
@@ -58,9 +62,9 @@ void register_node_type_geo_collection_info(void);
void register_node_type_geo_convex_hull(void);
void register_node_type_geo_curve_endpoints(void);
void register_node_type_geo_curve_fill(void);
+void register_node_type_geo_curve_fillet(void);
void register_node_type_geo_curve_length(void);
void register_node_type_geo_curve_parameter(void);
-void register_node_type_geo_curve_sample(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);
@@ -70,20 +74,23 @@ void register_node_type_geo_curve_primitive_spiral(void);
void register_node_type_geo_curve_primitive_star(void);
void register_node_type_geo_curve_resample(void);
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_subdivide(void);
-void register_node_type_geo_curve_fillet(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_edge_split(void);
void register_node_type_geo_input_index(void);
void register_node_type_geo_input_material(void);
void register_node_type_geo_input_normal(void);
void register_node_type_geo_input_position(void);
+void register_node_type_geo_input_spline_length(void);
void register_node_type_geo_input_tangent(void);
+void register_node_type_geo_instance_on_points(void);
void register_node_type_geo_is_viewport(void);
void register_node_type_geo_join_geometry(void);
void register_node_type_geo_material_assign(void);
@@ -99,6 +106,7 @@ void register_node_type_geo_mesh_primitive_line(void);
void register_node_type_geo_mesh_primitive_uv_sphere(void);
void register_node_type_geo_mesh_subdivide(void);
void register_node_type_geo_mesh_to_curve(void);
+void register_node_type_geo_mesh_to_points(void);
void register_node_type_geo_object_info(void);
void register_node_type_geo_point_distribute(void);
void register_node_type_geo_point_instance(void);
@@ -106,7 +114,9 @@ void register_node_type_geo_point_rotate(void);
void register_node_type_geo_point_scale(void);
void register_node_type_geo_point_separate(void);
void register_node_type_geo_point_translate(void);
+void register_node_type_geo_points_to_vertices(void);
void register_node_type_geo_points_to_volume(void);
+void register_node_type_geo_proximity(void);
void register_node_type_geo_raycast(void);
void register_node_type_geo_realize_instances(void);
void register_node_type_geo_sample_texture(void);
@@ -114,6 +124,7 @@ void register_node_type_geo_select_by_handle_type(void);
void register_node_type_geo_separate_components(void);
void register_node_type_geo_set_position(void);
void register_node_type_geo_string_join(void);
+void register_node_type_geo_string_to_curves(void);
void register_node_type_geo_subdivision_surface(void);
void register_node_type_geo_switch(void);
void register_node_type_geo_transform(void);
diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh
index 6ce3d0f2ab5..962e1c3c48f 100644
--- a/source/blender/nodes/NOD_geometry_exec.hh
+++ b/source/blender/nodes/NOD_geometry_exec.hh
@@ -46,6 +46,8 @@ using bke::WeakAnonymousAttributeID;
using bke::WriteAttributeLookup;
using fn::CPPType;
using fn::Field;
+using fn::FieldContext;
+using fn::FieldEvaluator;
using fn::FieldInput;
using fn::FieldOperation;
using fn::GField;
diff --git a/source/blender/nodes/NOD_node_declaration.hh b/source/blender/nodes/NOD_node_declaration.hh
index 8e9e72bf4c8..07d4e05cda8 100644
--- a/source/blender/nodes/NOD_node_declaration.hh
+++ b/source/blender/nodes/NOD_node_declaration.hh
@@ -27,6 +27,109 @@ namespace blender::nodes {
class NodeDeclarationBuilder;
+enum class InputSocketFieldType {
+ /** The input is required to be a single value. */
+ None,
+ /** The input can be a field. */
+ IsSupported,
+ /** The input can be a field and is a field implicitly if nothing is connected. */
+ Implicit,
+};
+
+enum class OutputSocketFieldType {
+ /** The output is always a single value. */
+ None,
+ /** The output is always a field, independent of the inputs. */
+ FieldSource,
+ /** If any input is a field, this output will be a field as well. */
+ DependentField,
+ /** If any of a subset of inputs is a field, this out will be a field as well.
+ * The subset is defined by the vector of indices. */
+ PartiallyDependent,
+};
+
+/**
+ * Contains information about how a node output's field state depends on inputs of the same node.
+ */
+class OutputFieldDependency {
+ private:
+ OutputSocketFieldType type_ = OutputSocketFieldType::None;
+ Vector<int> linked_input_indices_;
+
+ public:
+ static OutputFieldDependency ForFieldSource()
+ {
+ OutputFieldDependency field_dependency;
+ field_dependency.type_ = OutputSocketFieldType::FieldSource;
+ return field_dependency;
+ }
+
+ static OutputFieldDependency ForDataSource()
+ {
+ OutputFieldDependency field_dependency;
+ field_dependency.type_ = OutputSocketFieldType::None;
+ return field_dependency;
+ }
+
+ static OutputFieldDependency ForPartiallyDependentField(Vector<int> indices)
+ {
+ OutputFieldDependency field_dependency;
+ if (indices.is_empty()) {
+ field_dependency.type_ = OutputSocketFieldType::None;
+ }
+ else {
+ field_dependency.type_ = OutputSocketFieldType::PartiallyDependent;
+ field_dependency.linked_input_indices_ = std::move(indices);
+ }
+ return field_dependency;
+ }
+
+ static OutputFieldDependency ForDependentField()
+ {
+ OutputFieldDependency field_dependency;
+ field_dependency.type_ = OutputSocketFieldType::DependentField;
+ return field_dependency;
+ }
+
+ OutputSocketFieldType field_type() const
+ {
+ return type_;
+ }
+
+ Span<int> linked_input_indices() const
+ {
+ return linked_input_indices_;
+ }
+
+ friend bool operator==(const OutputFieldDependency &a, const OutputFieldDependency &b)
+ {
+ return a.type_ == b.type_ && a.linked_input_indices_ == b.linked_input_indices_;
+ }
+
+ friend bool operator!=(const OutputFieldDependency &a, const OutputFieldDependency &b)
+ {
+ return !(a == b);
+ }
+};
+
+/**
+ * Information about how a node interacts with fields.
+ */
+struct FieldInferencingInterface {
+ Vector<InputSocketFieldType> inputs;
+ Vector<OutputFieldDependency> outputs;
+
+ friend bool operator==(const FieldInferencingInterface &a, const FieldInferencingInterface &b)
+ {
+ return a.inputs == b.inputs && a.outputs == b.outputs;
+ }
+
+ friend bool operator!=(const FieldInferencingInterface &a, const FieldInferencingInterface &b)
+ {
+ return !(a == b);
+ }
+};
+
/**
* Describes a single input or output socket. This is subclassed for different socket types.
*/
@@ -34,11 +137,15 @@ class SocketDeclaration {
protected:
std::string name_;
std::string identifier_;
+ std::string description_;
bool hide_label_ = false;
bool hide_value_ = false;
bool is_multi_input_ = false;
bool no_mute_links_ = false;
+ InputSocketFieldType input_field_type_ = InputSocketFieldType::None;
+ OutputFieldDependency output_field_dependency_;
+
friend NodeDeclarationBuilder;
template<typename SocketDecl> friend class SocketDeclarationBuilder;
@@ -50,8 +157,12 @@ class SocketDeclaration {
virtual bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const;
StringRefNull name() const;
+ StringRefNull description() const;
StringRefNull identifier() const;
+ InputSocketFieldType input_field_type() const;
+ const OutputFieldDependency &output_field_dependency() const;
+
protected:
void set_common_flags(bNodeSocket &socket) const;
bool matches_common_data(const bNodeSocket &socket) const;
@@ -95,11 +206,52 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
return *(Self *)this;
}
+ Self &description(std::string value = "")
+ {
+ decl_->description_ = std::move(value);
+ return *(Self *)this;
+ }
Self &no_muted_links(bool value = true)
{
decl_->no_mute_links_ = value;
return *(Self *)this;
}
+
+ /** The input socket allows passing in a field. */
+ Self &supports_field()
+ {
+ decl_->input_field_type_ = InputSocketFieldType::IsSupported;
+ return *(Self *)this;
+ }
+
+ /** The input supports a field and is a field by default when nothing is connected. */
+ Self &implicit_field()
+ {
+ this->hide_value();
+ decl_->input_field_type_ = InputSocketFieldType::Implicit;
+ return *(Self *)this;
+ }
+
+ /** The output is always a field, regardless of any inputs. */
+ Self &field_source()
+ {
+ decl_->output_field_dependency_ = OutputFieldDependency::ForFieldSource();
+ return *(Self *)this;
+ }
+
+ /** The output is a field if any of the inputs is a field. */
+ Self &dependent_field()
+ {
+ decl_->output_field_dependency_ = OutputFieldDependency::ForDependentField();
+ return *(Self *)this;
+ }
+
+ /** The output is a field if any of the inputs with indices in the given list is a field. */
+ Self &dependent_field(Vector<int> input_dependencies)
+ {
+ decl_->output_field_dependency_ = OutputFieldDependency::ForPartiallyDependentField(
+ std::move(input_dependencies));
+ }
};
using SocketDeclarationPtr = std::unique_ptr<SocketDeclaration>;
@@ -108,6 +260,7 @@ class NodeDeclaration {
private:
Vector<SocketDeclarationPtr> inputs_;
Vector<SocketDeclarationPtr> outputs_;
+ bool is_function_node_ = false;
friend NodeDeclarationBuilder;
@@ -118,6 +271,11 @@ class NodeDeclaration {
Span<SocketDeclarationPtr> inputs() const;
Span<SocketDeclarationPtr> outputs() const;
+ bool is_function_node() const
+ {
+ return is_function_node_;
+ }
+
MEM_CXX_CLASS_ALLOC_FUNCS("NodeDeclaration")
};
@@ -129,6 +287,15 @@ class NodeDeclarationBuilder {
public:
NodeDeclarationBuilder(NodeDeclaration &declaration);
+ /**
+ * All inputs support fields, and all outputs are fields if any of the inputs is a field.
+ * Calling field status definitions on each socket is unnecessary.
+ */
+ void is_function_node(bool value = true)
+ {
+ declaration_.is_function_node_ = value;
+ }
+
template<typename DeclType>
typename DeclType::Builder &add_input(StringRef name, StringRef identifier = "");
template<typename DeclType>
@@ -155,6 +322,20 @@ inline StringRefNull SocketDeclaration::identifier() const
return identifier_;
}
+inline StringRefNull SocketDeclaration::description() const
+{
+ return description_;
+}
+inline InputSocketFieldType SocketDeclaration::input_field_type() const
+{
+ return input_field_type_;
+}
+
+inline const OutputFieldDependency &SocketDeclaration::output_field_dependency() const
+{
+ return output_field_dependency_;
+}
+
/* --------------------------------------------------------------------
* NodeDeclarationBuilder inline methods.
*/
diff --git a/source/blender/nodes/NOD_node_tree_ref.hh b/source/blender/nodes/NOD_node_tree_ref.hh
index 4f2565cbbaf..1da42fb6425 100644
--- a/source/blender/nodes/NOD_node_tree_ref.hh
+++ b/source/blender/nodes/NOD_node_tree_ref.hh
@@ -182,6 +182,7 @@ class NodeRef : NonCopyable, NonMovable {
Span<const InputSocketRef *> inputs() const;
Span<const OutputSocketRef *> outputs() const;
Span<const InternalLinkRef *> internal_links() const;
+ Span<const SocketRef *> sockets(eNodeSocketInOut in_out) const;
const InputSocketRef &input(int index) const;
const OutputSocketRef &output(int index) const;
@@ -189,6 +190,10 @@ class NodeRef : NonCopyable, NonMovable {
const InputSocketRef &input_by_identifier(StringRef identifier) const;
const OutputSocketRef &output_by_identifier(StringRef identifier) const;
+ bool any_input_is_directly_linked() const;
+ bool any_output_is_directly_linked() const;
+ bool any_socket_is_directly_linked(eNodeSocketInOut in_out) const;
+
bNode *bnode() const;
bNodeTree *btree() const;
@@ -196,6 +201,7 @@ class NodeRef : NonCopyable, NonMovable {
StringRefNull idname() const;
StringRefNull name() const;
bNodeType *typeinfo() const;
+ const NodeDeclaration *declaration() const;
int id() const;
@@ -272,6 +278,13 @@ class NodeTreeRef : NonCopyable, NonMovable {
bool has_link_cycles() const;
bool has_undefined_nodes_or_sockets() const;
+ enum class ToposortDirection {
+ LeftToRight,
+ RightToLeft,
+ };
+
+ Vector<const NodeRef *> toposort(ToposortDirection direction) const;
+
bNodeTree *btree() const;
StringRefNull name() const;
@@ -496,6 +509,12 @@ inline Span<const OutputSocketRef *> NodeRef::outputs() const
return outputs_;
}
+inline Span<const SocketRef *> NodeRef::sockets(const eNodeSocketInOut in_out) const
+{
+ return in_out == SOCK_IN ? inputs_.as_span().cast<const SocketRef *>() :
+ outputs_.as_span().cast<const SocketRef *>();
+}
+
inline Span<const InternalLinkRef *> NodeRef::internal_links() const
{
return internal_links_;
@@ -553,6 +572,13 @@ inline bNodeType *NodeRef::typeinfo() const
return bnode_->typeinfo;
}
+/* Returns a pointer because not all nodes have declarations currently. */
+inline const NodeDeclaration *NodeRef::declaration() const
+{
+ nodeDeclarationEnsure(this->tree().btree(), bnode_);
+ return bnode_->declaration;
+}
+
inline int NodeRef::id() const
{
return id_;
diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h
index 2911e0fbea6..76c174201e8 100644
--- a/source/blender/nodes/NOD_shader.h
+++ b/source/blender/nodes/NOD_shader.h
@@ -49,6 +49,7 @@ void register_node_type_sh_normal(void);
void register_node_type_sh_gamma(void);
void register_node_type_sh_brightcontrast(void);
void register_node_type_sh_mapping(void);
+void register_node_type_sh_curve_float(void);
void register_node_type_sh_curve_vec(void);
void register_node_type_sh_curve_rgb(void);
void register_node_type_sh_map_range(void);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index ab673d814bb..c13ab199691 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -132,6 +132,7 @@ DefNode(ShaderNode, SH_NODE_VECTOR_DISPLACEMENT,def_sh_vector_displacement,"
DefNode(ShaderNode, SH_NODE_TEX_IES, def_sh_tex_ies, "TEX_IES", TexIES, "IES Texture", "" )
DefNode(ShaderNode, SH_NODE_TEX_WHITE_NOISE, def_sh_tex_white_noise, "TEX_WHITE_NOISE", TexWhiteNoise, "White Noise", "" )
DefNode(ShaderNode, SH_NODE_OUTPUT_AOV, def_sh_output_aov, "OUTPUT_AOV", OutputAOV, "AOV Output", "" )
+DefNode(ShaderNode, SH_NODE_CURVE_FLOAT, def_float_curve, "CURVE_FLOAT", FloatCurve, "Float Curve", "" )
DefNode(CompositorNode, CMP_NODE_VIEWER, def_cmp_viewer, "VIEWER", Viewer, "Viewer", "" )
DefNode(CompositorNode, CMP_NODE_RGB, 0, "RGB", RGB, "RGB", "" )
@@ -262,18 +263,22 @@ DefNode(TextureNode, TEX_NODE_PROC+TEX_NOISE, 0, "TEX_NO
DefNode(TextureNode, TEX_NODE_PROC+TEX_STUCCI, 0, "TEX_STUCCI", TexStucci, "Stucci", "" )
DefNode(TextureNode, TEX_NODE_PROC+TEX_DISTNOISE, 0, "TEX_DISTNOISE", TexDistNoise, "Distorted Noise", "" )
+DefNode(FunctionNode, FN_NODE_LEGACY_RANDOM_FLOAT, 0, "LEGACY_RANDOM_FLOAT", LegacyRandomFloat, "Random Float", "")
+
DefNode(FunctionNode, FN_NODE_BOOLEAN_MATH, def_boolean_math, "BOOLEAN_MATH", BooleanMath, "Boolean Math", "")
DefNode(FunctionNode, FN_NODE_FLOAT_COMPARE, def_float_compare, "FLOAT_COMPARE", FloatCompare, "Float Compare", "")
DefNode(FunctionNode, FN_NODE_FLOAT_TO_INT, def_float_to_int, "FLOAT_TO_INT", FloatToInt, "Float to Integer", "")
+DefNode(FunctionNode, FN_NODE_INPUT_SPECIAL_CHARACTERS, 0, "INPUT_SPECIAL_CHARACTERS", InputSpecialCharacters, "Special Characters", "")
DefNode(FunctionNode, FN_NODE_INPUT_STRING, def_fn_input_string, "INPUT_STRING", InputString, "String", "")
DefNode(FunctionNode, FN_NODE_INPUT_VECTOR, def_fn_input_vector, "INPUT_VECTOR", InputVector, "Vector", "")
-DefNode(FunctionNode, FN_NODE_RANDOM_FLOAT, 0, "RANDOM_FLOAT", RandomFloat, "Random Float", "")
-DefNode(FunctionNode, FN_NODE_VALUE_TO_STRING, 0, "VALUE_TO_STRING", ValueToString, "Value to String", "")
+DefNode(FunctionNode, FN_NODE_RANDOM_VALUE, def_fn_random_value, "RANDOM_VALUE", RandomValue, "Random Value", "")
+DefNode(FunctionNode, FN_NODE_ROTATE_EULER, def_fn_rotate_euler, "ROTATE_EULER", RotateEuler, "Rotate Euler", "")
DefNode(FunctionNode, FN_NODE_STRING_LENGTH, 0, "STRING_LENGTH", StringLength, "String Length", "")
DefNode(FunctionNode, FN_NODE_STRING_SUBSTRING, 0, "STRING_SUBSTRING", StringSubstring, "String Substring", "")
+DefNode(FunctionNode, FN_NODE_VALUE_TO_STRING, 0, "VALUE_TO_STRING", ValueToString, "Value to String", "")
-DefNode(GeometryNode, GEO_NODE_LECAGY_ATTRIBUTE_CLAMP, def_geo_attribute_clamp, "LEGACY_ATTRIBUTE_CLAMP", LegacyAttributeClamp, "Attribute Clamp", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_ALIGN_ROTATION_TO_VECTOR, def_geo_align_rotation_to_vector, "LEGACY_ALIGN_ROTATION_TO_VECTOR", LegacyAlignRotationToVector, "Align Rotation to Vector", "")
+DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_CLAMP, def_geo_attribute_clamp, "LEGACY_ATTRIBUTE_CLAMP", LegacyAttributeClamp, "Attribute Clamp", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_COLOR_RAMP, def_geo_attribute_color_ramp, "LEGACY_ATTRIBUTE_COLOR_RAMP", LegacyAttributeColorRamp, "Attribute Color Ramp", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_COMBINE_XYZ, def_geo_attribute_combine_xyz, "LEGACY_ATTRIBUTE_COMBINE_XYZ", LegacyAttributeCombineXYZ, "Attribute Combine XYZ", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_COMPARE, def_geo_attribute_attribute_compare, "LEGACY_ATTRIBUTE_COMPARE", LegacyAttributeCompare, "Attribute Compare", "")
@@ -283,18 +288,22 @@ DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_FILL, def_geo_attribute_fill, "L
DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_MAP_RANGE, def_geo_attribute_map_range, "LEGACY_ATTRIBUTE_MAP_RANGE", LegacyAttributeMapRange, "Attribute Map Range", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_MATH, def_geo_attribute_math, "LEGACY_ATTRIBUTE_MATH", LegacyAttributeMath, "Attribute Math", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_MIX, def_geo_attribute_mix, "LEGACY_ATTRIBUTE_MIX", LegacyAttributeMix, "Attribute Mix", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_PROXIMITY, def_geo_attribute_proximity, "LEGACY_ATTRIBUTE_PROXIMITY", LegacyAttributeProximity, "Attribute Proximity", "")
+DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_PROXIMITY, def_geo_legacy_attribute_proximity, "LEGACY_ATTRIBUTE_PROXIMITY", LegacyAttributeProximity, "Attribute Proximity", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_RANDOMIZE, def_geo_attribute_randomize, "LEGACY_ATTRIBUTE_RANDOMIZE", LegacyAttributeRandomize, "Attribute Randomize", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_SAMPLE_TEXTURE, 0, "LEGACY_ATTRIBUTE_SAMPLE_TEXTURE", LegacyAttributeSampleTexture, "Attribute Sample Texture", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_SEPARATE_XYZ, def_geo_attribute_separate_xyz, "LEGACY_ATTRIBUTE_SEPARATE_XYZ", LegacyAttributeSeparateXYZ, "Attribute Separate XYZ", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER, def_geo_attribute_transfer, "LEGACY_ATTRIBUTE_TRANSFER", LegacyAttributeTransfer, "Attribute Transfer", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_VECTOR_MATH, def_geo_attribute_vector_math, "LEGACY_ATTRIBUTE_VECTOR_MATH", LegacyAttributeVectorMath, "Attribute Vector Math", "")
+DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_VECTOR_ROTATE, def_geo_attribute_vector_rotate, "LEGACY_ATTRIBUTE_VECTOR_ROTATE", LegacyAttributeVectorRotate, "Attribute Vector Rotate", "")
+DefNode(GeometryNode, GEO_NODE_LEGACY_CURVE_ENDPOINTS, 0, "LEGACY_CURVE_ENDPOINTS", LegacyCurveEndpoints, "Curve Endpoints", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_CURVE_REVERSE, 0, "LEGACY_CURVE_REVERSE", LegacyCurveReverse, "Curve Reverse", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_CURVE_SELECT_HANDLES, def_geo_curve_select_handles, "LEGACY_CURVE_SELECT_HANDLES", LegacyCurveSelectHandles, "Select by Handle Type", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_CURVE_SET_HANDLES, def_geo_curve_set_handles, "LEGACY_CURVE_SET_HANDLES", LegacyCurveSetHandles, "Set Handle Type", "")
+DefNode(GeometryNode, GEO_NODE_LEGACY_CURVE_SET_HANDLES, def_geo_legacy_curve_set_handles, "LEGACY_CURVE_SET_HANDLES", LegacyCurveSetHandles, "Set Handle Type", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_CURVE_SPLINE_TYPE, def_geo_curve_spline_type, "LEGACY_CURVE_SPLINE_TYPE", LegacyCurveSplineType, "Set Spline Type", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_CURVE_SUBDIVIDE, def_geo_curve_subdivide, "LEGACY_CURVE_SUBDIVIDE", LegacyCurveSubdivide, "Curve Subdivide", "")
+DefNode(GeometryNode, GEO_NODE_LEGACY_CURVE_SUBDIVIDE, def_geo_legacy_curve_subdivide, "LEGACY_CURVE_SUBDIVIDE", LegacyCurveSubdivide, "Curve Subdivide", "")
+DefNode(GeometryNode, GEO_NODE_LEGACY_CURVE_TO_POINTS, def_geo_curve_to_points, "LEGACY_CURVE_TO_POINTS", LegacyCurveToPoints, "Curve to Points", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_DELETE_GEOMETRY, 0, "LEGACY_DELETE_GEOMETRY", LegacyDeleteGeometry, "Delete Geometry", "")
+DefNode(GeometryNode, GEO_NODE_LEGACY_EDGE_SPLIT, 0, "LEGACY_EDGE_SPLIT", LegacyEdgeSplit, "Edge Split", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_MATERIAL_ASSIGN, 0, "LEGACY_MATERIAL_ASSIGN", LegacyMaterialAssign, "Material Assign", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_MESH_TO_CURVE, 0, "LEGACY_MESH_TO_CURVE", LegacyMeshToCurve, "Mesh to Curve", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_POINT_DISTRIBUTE, def_geo_point_distribute, "LEGACY_POINT_DISTRIBUTE", LegacyPointDistribute, "Point Distribute", "")
@@ -306,18 +315,17 @@ DefNode(GeometryNode, GEO_NODE_LEGACY_POINT_TRANSLATE, def_geo_point_translate,
DefNode(GeometryNode, GEO_NODE_LEGACY_POINTS_TO_VOLUME, def_geo_points_to_volume, "LEGACY_POINTS_TO_VOLUME", LegacyPointsToVolume, "Points to Volume", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_RAYCAST, def_geo_raycast, "LEGACY_RAYCAST", LegacyRaycast, "Raycast", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_SELECT_BY_MATERIAL, 0, "LEGACY_SELECT_BY_MATERIAL", LegacySelectByMaterial, "Select by Material", "")
+DefNode(GeometryNode, GEO_NODE_LEGACY_SUBDIVISION_SURFACE, def_geo_subdivision_surface, "LEGACY_SUBDIVISION_SURFACE", LegacySubdivisionSurface, "Subdivision Surface", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_CAPTURE, def_geo_attribute_capture, "ATTRIBUTE_CAPTURE", AttributeCapture, "Attribute Capture", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_REMOVE, 0, "ATTRIBUTE_REMOVE", AttributeRemove, "Attribute Remove", "")
-DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_VECTOR_ROTATE, def_geo_attribute_vector_rotate, "LEGACY_ATTRIBUTE_VECTOR_ROTATE", LegacyAttributeVectorRotate, "Attribute Vector Rotate", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_STATISTIC, def_geo_attribute_statistic, "ATTRIBUTE_STATISTIC", AttributeStatistic, "Attribute Statistic", "")
DefNode(GeometryNode, GEO_NODE_BOOLEAN, def_geo_boolean, "BOOLEAN", Boolean, "Boolean", "")
DefNode(GeometryNode, GEO_NODE_BOUNDING_BOX, 0, "BOUNDING_BOX", BoundBox, "Bounding Box", "")
DefNode(GeometryNode, GEO_NODE_COLLECTION_INFO, def_geo_collection_info, "COLLECTION_INFO", CollectionInfo, "Collection Info", "")
DefNode(GeometryNode, GEO_NODE_CONVEX_HULL, 0, "CONVEX_HULL", ConvexHull, "Convex Hull", "")
-DefNode(GeometryNode, GEO_NODE_CURVE_SAMPLE, def_geo_curve_sample, "CURVE_SAMPLE", CurveSample, "Curve Sample", "")
-DefNode(GeometryNode, GEO_NODE_CURVE_ENDPOINTS, 0, "CURVE_ENDPOINTS", CurveEndpoints, "Curve Endpoints", "")
DefNode(GeometryNode, GEO_NODE_CURVE_FILL, def_geo_curve_fill, "CURVE_FILL", CurveFill, "Curve Fill", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_FILLET, def_geo_curve_fillet, "CURVE_FILLET", CurveFillet, "Curve Fillet", "")
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_PRIMITIVE_BEZIER_SEGMENT, def_geo_curve_primitive_bezier_segment, "CURVE_PRIMITIVE_BEZIER_SEGMENT", CurvePrimitiveBezierSegment, "Bezier Segment", "")
@@ -328,16 +336,21 @@ DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, def_geo_curve_prim
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_SPIRAL, 0, "CURVE_PRIMITIVE_SPIRAL", CurveSpiral, "Curve Spiral", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_STAR, 0, "CURVE_PRIMITIVE_STAR", CurveStar, "Star", "")
DefNode(GeometryNode, GEO_NODE_CURVE_RESAMPLE, def_geo_curve_resample, "CURVE_RESAMPLE", CurveResample, "Resample Curve", "")
-DefNode(GeometryNode, GEO_NODE_CURVE_FILLET, def_geo_curve_fillet, "CURVE_FILLET", CurveFillet, "Curve Fillet", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_SPLINE_TYPE, def_geo_curve_spline_type, "CURVE_SPLINE_TYPE", CurveSplineType, "Set Spline Type", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_REVERSE, 0, "CURVE_REVERSE", CurveReverse, "Curve Reverse", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_SAMPLE, def_geo_curve_sample, "CURVE_SAMPLE", CurveSample, "Curve Sample", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_SET_HANDLES, def_geo_curve_set_handles, "CURVE_SET_HANDLES", CurveSetHandles, "Set Handle Type", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_SUBDIVIDE, 0, "CURVE_SUBDIVIDE", CurveSubdivide, "Curve Subdivide", "")
DefNode(GeometryNode, GEO_NODE_CURVE_TO_MESH, 0, "CURVE_TO_MESH", CurveToMesh, "Curve to Mesh", "")
-DefNode(GeometryNode, GEO_NODE_CURVE_TO_POINTS, def_geo_curve_to_points, "CURVE_TO_POINTS", CurveToPoints, "Curve to Points", "")
DefNode(GeometryNode, GEO_NODE_CURVE_TRIM, def_geo_curve_trim, "CURVE_TRIM", CurveTrim, "Curve Trim", "")
-DefNode(GeometryNode, GEO_NODE_EDGE_SPLIT, 0, "EDGE_SPLIT", EdgeSplit, "Edge Split", "")
+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_INPUT_INDEX, 0, "INDEX", InputIndex, "Index", "")
DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL, def_geo_input_material, "INPUT_MATERIAL", InputMaterial, "Material", "")
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_SPLINE_LENGTH, 0, "SPLINE_LENGTH", SplineLength, "Spline Length", "")
DefNode(GeometryNode, GEO_NODE_INPUT_TANGENT, 0, "INPUT_TANGENT", InputTangent, "Curve Tangent", "")
+DefNode(GeometryNode, GEO_NODE_INSTANCE_ON_POINTS, 0, "INSTANCE_ON_POINTS", InstanceOnPoints, "Instance on Points", "")
DefNode(GeometryNode, GEO_NODE_IS_VIEWPORT, 0, "IS_VIEWPORT", IsViewport, "Is Viewport", "")
DefNode(GeometryNode, GEO_NODE_JOIN_GEOMETRY, 0, "JOIN_GEOMETRY", JoinGeometry, "Join Geometry", "")
DefNode(GeometryNode, GEO_NODE_MATERIAL_ASSIGN, 0, "MATERIAL_ASSIGN", MaterialAssign, "Material Assign", "")
@@ -352,12 +365,15 @@ DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, 0, "MESH_PRIMITIVE_ICO
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_LINE, def_geo_mesh_line, "MESH_PRIMITIVE_LINE", MeshLine, "Mesh Line", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, 0, "MESH_PRIMITIVE_UV_SPHERE", MeshUVSphere, "UV Sphere", "")
DefNode(GeometryNode, GEO_NODE_MESH_SUBDIVIDE, 0, "MESH_SUBDIVIDE", MeshSubdivide, "Mesh Subdivide", "")
+DefNode(GeometryNode, GEO_NODE_MESH_TO_POINTS, def_geo_mesh_to_points, "MESH_TO_POINTS", MeshToPoints, "Mesh to Points", "")
DefNode(GeometryNode, GEO_NODE_OBJECT_INFO, def_geo_object_info, "OBJECT_INFO", ObjectInfo, "Object Info", "")
+DefNode(GeometryNode, GEO_NODE_POINTS_TO_VERTICES, 0, "POINTS_TO_VERTICES", PointsToVertices, "Points to Vertices", "")
+DefNode(GeometryNode, GEO_NODE_PROXIMITY, def_geo_proximity, "PROXIMITY", Proximity, "Geometry Proximity", "")
DefNode(GeometryNode, GEO_NODE_REALIZE_INSTANCES, 0, "REALIZE_INSTANCES", RealizeInstances, "Realize Instances", "")
DefNode(GeometryNode, GEO_NODE_SEPARATE_COMPONENTS, 0, "SEPARATE_COMPONENTS", SeparateComponents, "Separate Components", "")
DefNode(GeometryNode, GEO_NODE_SET_POSITION, 0, "SET_POSITION", SetPosition, "Set Position", "")
DefNode(GeometryNode, GEO_NODE_STRING_JOIN, 0, "STRING_JOIN", StringJoin, "String Join", "")
-DefNode(GeometryNode, GEO_NODE_SUBDIVISION_SURFACE, def_geo_subdivision_surface, "SUBDIVISION_SURFACE", SubdivisionSurface, "Subdivision Surface", "")
+DefNode(GeometryNode, GEO_NODE_STRING_TO_CURVES, def_geo_string_to_curves, "STRING_TO_CURVES", StringToCurves, "String to Curves", "")
DefNode(GeometryNode, GEO_NODE_SWITCH, def_geo_switch, "SWITCH", Switch, "Switch", "")
DefNode(GeometryNode, GEO_NODE_TRANSFORM, 0, "TRANSFORM", Transform, "Transform", "")
DefNode(GeometryNode, GEO_NODE_TRIANGULATE, def_geo_triangulate, "TRIANGULATE", Triangulate, "Triangulate", "")
diff --git a/source/blender/nodes/composite/node_composite_tree.c b/source/blender/nodes/composite/node_composite_tree.cc
index cc657d6f91d..a596a85b748 100644
--- a/source/blender/nodes/composite/node_composite_tree.c
+++ b/source/blender/nodes/composite/node_composite_tree.cc
@@ -21,7 +21,7 @@
* \ingroup nodes
*/
-#include <stdio.h>
+#include <cstdio>
#include "DNA_color_types.h"
#include "DNA_node_types.h"
@@ -41,7 +41,7 @@
#include "RNA_access.h"
#include "NOD_composite.h"
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
#ifdef WITH_COMPOSITOR
# include "COM_compositor.h"
@@ -55,7 +55,7 @@ static void composite_get_from_context(const bContext *C,
{
Scene *scene = CTX_data_scene(C);
- *r_from = NULL;
+ *r_from = nullptr;
*r_id = &scene->id;
*r_ntree = scene->nodetree;
}
@@ -77,19 +77,16 @@ static void foreach_nodeclass(Scene *UNUSED(scene), void *calldata, bNodeClassCa
static void free_node_cache(bNodeTree *UNUSED(ntree), bNode *node)
{
- bNodeSocket *sock;
-
- for (sock = node->outputs.first; sock; sock = sock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
if (sock->cache) {
- sock->cache = NULL;
+ sock->cache = nullptr;
}
}
}
static void free_cache(bNodeTree *ntree)
{
- bNode *node;
- for (node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
free_node_cache(ntree, node);
}
}
@@ -98,16 +95,16 @@ static void free_cache(bNodeTree *ntree)
static void localize(bNodeTree *localtree, bNodeTree *ntree)
{
- bNode *node = ntree->nodes.first;
- bNode *local_node = localtree->nodes.first;
- while (node != NULL) {
+ bNode *node = (bNode *)ntree->nodes.first;
+ bNode *local_node = (bNode *)localtree->nodes.first;
+ while (node != nullptr) {
/* Ensure new user input gets handled ok. */
node->need_exec = 0;
local_node->original = node;
/* move over the compbufs */
- /* right after ntreeCopyTree() oldsock pointers are valid */
+ /* right after #ntreeCopyTree() `oldsock` pointers are valid */
if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
if (node->id) {
@@ -115,16 +112,16 @@ static void localize(bNodeTree *localtree, bNodeTree *ntree)
local_node->id = (ID *)node->id;
}
else {
- local_node->id = NULL;
+ local_node->id = nullptr;
}
}
}
- bNodeSocket *output_sock = node->outputs.first;
- bNodeSocket *local_output_sock = local_node->outputs.first;
- while (output_sock != NULL) {
+ bNodeSocket *output_sock = (bNodeSocket *)node->outputs.first;
+ bNodeSocket *local_output_sock = (bNodeSocket *)local_node->outputs.first;
+ while (output_sock != nullptr) {
local_output_sock->cache = output_sock->cache;
- output_sock->cache = NULL;
+ output_sock->cache = nullptr;
/* This is actually link to original: someone was just lazy enough and tried to save few
* bytes in the cost of readability. */
local_output_sock->new_sock = output_sock;
@@ -151,7 +148,7 @@ static void local_merge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree)
/* move over the compbufs and previews */
BKE_node_preview_merge_tree(ntree, localtree, true);
- for (lnode = localtree->nodes.first; lnode; lnode = lnode->next) {
+ for (lnode = (bNode *)localtree->nodes.first; lnode; lnode = lnode->next) {
if (ntreeNodeExists(ntree, lnode->new_node)) {
if (ELEM(lnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
if (lnode->id && (lnode->flag & NODE_DO_OUTPUT)) {
@@ -165,18 +162,19 @@ static void local_merge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree)
* copied back to original node */
if (lnode->storage) {
if (lnode->new_node->storage) {
- BKE_tracking_distortion_free(lnode->new_node->storage);
+ BKE_tracking_distortion_free((MovieDistortion *)lnode->new_node->storage);
}
- lnode->new_node->storage = BKE_tracking_distortion_copy(lnode->storage);
+ lnode->new_node->storage = BKE_tracking_distortion_copy(
+ (MovieDistortion *)lnode->storage);
}
}
- for (lsock = lnode->outputs.first; lsock; lsock = lsock->next) {
+ for (lsock = (bNodeSocket *)lnode->outputs.first; lsock; lsock = lsock->next) {
if (ntreeOutputExists(lnode->new_node, lsock->new_sock)) {
lsock->new_sock->cache = lsock->cache;
- lsock->cache = NULL;
- lsock->new_sock = NULL;
+ lsock->cache = nullptr;
+ lsock->new_sock = nullptr;
}
}
}
@@ -216,13 +214,13 @@ bNodeTreeType *ntreeType_Composite;
void register_node_tree_type_cmp(void)
{
- bNodeTreeType *tt = ntreeType_Composite = MEM_callocN(sizeof(bNodeTreeType),
- "compositor node tree type");
+ bNodeTreeType *tt = ntreeType_Composite = (bNodeTreeType *)MEM_callocN(
+ sizeof(bNodeTreeType), "compositor node tree type");
tt->type = NTREE_COMPOSIT;
strcpy(tt->idname, "CompositorNodeTree");
strcpy(tt->ui_name, N_("Compositor"));
- tt->ui_icon = 0; /* defined in drawnode.c */
+ tt->ui_icon = 0; /* Defined in `drawnode.c`. */
strcpy(tt->ui_description, N_("Compositing nodes"));
tt->free_cache = free_cache;
@@ -241,9 +239,6 @@ void register_node_tree_type_cmp(void)
ntreeTypeAdd(tt);
}
-extern void *COM_linker_hack; /* Quiet warning. */
-void *COM_linker_hack = NULL;
-
void ntreeCompositExecTree(Scene *scene,
bNodeTree *ntree,
RenderData *rd,
@@ -276,13 +271,11 @@ void ntreeCompositExecTree(Scene *scene,
*/
void ntreeCompositUpdateRLayers(bNodeTree *ntree)
{
- bNode *node;
-
- if (ntree == NULL) {
+ if (ntree == nullptr) {
return;
}
- for (node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == CMP_NODE_R_LAYERS) {
node_cmp_rlayers_outputs(ntree, node);
}
@@ -295,13 +288,11 @@ void ntreeCompositRegisterPass(bNodeTree *ntree,
const char *name,
eNodeSocketDatatype type)
{
- bNode *node;
-
- if (ntree == NULL) {
+ if (ntree == nullptr) {
return;
}
- for (node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == CMP_NODE_R_LAYERS) {
node_cmp_rlayers_register_pass(ntree, node, scene, view_layer, name, type);
}
@@ -317,15 +308,14 @@ void ntreeCompositTagRender(Scene *scene)
* This is still rather weak though,
* ideally render struct would store own main AND original G_MAIN. */
- for (Scene *sce_iter = G_MAIN->scenes.first; sce_iter; sce_iter = sce_iter->id.next) {
+ for (Scene *sce_iter = (Scene *)G_MAIN->scenes.first; sce_iter;
+ sce_iter = (Scene *)sce_iter->id.next) {
if (sce_iter->nodetree) {
- bNode *node;
-
- for (node = sce_iter->nodetree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &sce_iter->nodetree->nodes) {
if (node->id == (ID *)scene || node->type == CMP_NODE_COMPOSITE) {
nodeUpdate(sce_iter->nodetree, node);
}
- else if (node->type == CMP_NODE_TEXTURE) /* uses scene sizex/sizey */ {
+ else if (node->type == CMP_NODE_TEXTURE) /* uses scene size_x/size_y */ {
nodeUpdate(sce_iter->nodetree, node);
}
}
@@ -336,13 +326,11 @@ void ntreeCompositTagRender(Scene *scene)
/* XXX after render animation system gets a refresh, this call allows composite to end clean */
void ntreeCompositClearTags(bNodeTree *ntree)
{
- bNode *node;
-
- if (ntree == NULL) {
+ if (ntree == nullptr) {
return;
}
- for (node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
node->need_exec = 0;
if (node->type == NODE_GROUP) {
ntreeCompositClearTags((bNodeTree *)node->id);
diff --git a/source/blender/nodes/composite/node_composite_util.c b/source/blender/nodes/composite/node_composite_util.cc
index 6cc17d8c272..86aaec61bc3 100644
--- a/source/blender/nodes/composite/node_composite_util.c
+++ b/source/blender/nodes/composite/node_composite_util.cc
@@ -21,7 +21,7 @@
* \ingroup nodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
bool cmp_node_poll_default(bNodeType *UNUSED(ntype),
bNodeTree *ntree,
@@ -36,11 +36,10 @@ bool cmp_node_poll_default(bNodeType *UNUSED(ntype),
void cmp_node_update_default(bNodeTree *UNUSED(ntree), bNode *node)
{
- bNodeSocket *sock;
- for (sock = node->outputs.first; sock; sock = sock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
if (sock->cache) {
// free_compbuf(sock->cache);
- // sock->cache = NULL;
+ // sock->cache = nullptr;
}
}
node->need_exec = 1;
diff --git a/source/blender/nodes/composite/node_composite_util.h b/source/blender/nodes/composite/node_composite_util.hh
index 4fcccbb79f0..6fd82ffc93f 100644
--- a/source/blender/nodes/composite/node_composite_util.h
+++ b/source/blender/nodes/composite/node_composite_util.hh
@@ -47,20 +47,13 @@
/* only for forward declarations */
#include "NOD_composite.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include "NOD_socket_declarations.hh"
#define CMP_SCALE_MAX 12000
bool cmp_node_poll_default(struct bNodeType *ntype,
struct bNodeTree *ntree,
- const char **r_disabled_info);
+ const char **r_disabled_hint);
void cmp_node_update_default(struct bNodeTree *ntree, struct bNode *node);
void cmp_node_type_base(
struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/source/blender/nodes/composite/nodes/node_composite_alphaOver.c b/source/blender/nodes/composite/nodes/node_composite_alphaOver.cc
index 7a08bd51575..6210d946bc7 100644
--- a/source/blender/nodes/composite/nodes/node_composite_alphaOver.c
+++ b/source/blender/nodes/composite/nodes/node_composite_alphaOver.cc
@@ -21,19 +21,21 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.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>("Fac").default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>("Image", "Image_001").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>("Image");
+}
+
+} // namespace blender::nodes
static void node_alphaover_init(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -45,7 +47,7 @@ void register_node_type_cmp_alphaover(void)
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;
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.c b/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc
index a5906c31093..23e63b9a53b 100644
--- a/source/blender/nodes/composite/nodes/node_composite_antialiasing.c
+++ b/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc
@@ -23,7 +23,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** Anti-Aliasing (SMAA 1x) ******************** */
@@ -34,7 +34,8 @@ static bNodeSocketTemplate cmp_node_antialiasing_out[] = {{SOCK_RGBA, N_("Image"
static void node_composit_init_antialiasing(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeAntiAliasingData *data = MEM_callocN(sizeof(NodeAntiAliasingData), "node antialiasing data");
+ NodeAntiAliasingData *data = (NodeAntiAliasingData *)MEM_callocN(sizeof(NodeAntiAliasingData),
+ "node antialiasing data");
data->threshold = CMP_DEFAULT_SMAA_THRESHOLD;
data->contrast_limit = CMP_DEFAULT_SMAA_CONTRAST_LIMIT;
diff --git a/source/blender/nodes/composite/nodes/node_composite_bilateralblur.c b/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc
index 270a137280c..3e724d17a10 100644
--- a/source/blender/nodes/composite/nodes/node_composite_bilateralblur.c
+++ b/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** BILATERALBLUR ******************** */
static bNodeSocketTemplate cmp_node_bilateralblur_in[] = {
@@ -36,8 +36,8 @@ static bNodeSocketTemplate cmp_node_bilateralblur_out[] = {
static void node_composit_init_bilateralblur(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeBilateralBlurData *nbbd = MEM_callocN(sizeof(NodeBilateralBlurData),
- "node bilateral blur data");
+ NodeBilateralBlurData *nbbd = (NodeBilateralBlurData *)MEM_callocN(sizeof(NodeBilateralBlurData),
+ "node bilateral blur data");
node->storage = nbbd;
nbbd->iter = 1;
nbbd->sigma_color = 0.3;
diff --git a/source/blender/nodes/composite/nodes/node_composite_blur.c b/source/blender/nodes/composite/nodes/node_composite_blur.cc
index 92379f4552b..c5c0c21929e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_blur.c
+++ b/source/blender/nodes/composite/nodes/node_composite_blur.cc
@@ -22,7 +22,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** BLUR ******************** */
static bNodeSocketTemplate cmp_node_blur_in[] = {
@@ -33,7 +33,7 @@ static bNodeSocketTemplate cmp_node_blur_out[] = {{SOCK_RGBA, N_("Image")}, {-1,
static void node_composit_init_blur(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeBlurData *data = MEM_callocN(sizeof(NodeBlurData), "node blur data");
+ NodeBlurData *data = (NodeBlurData *)MEM_callocN(sizeof(NodeBlurData), "node blur data");
data->filtertype = R_FILTER_GAUSS;
node->storage = data;
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_bokehblur.c b/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc
index d724a83e5a2..f130a642e20 100644
--- a/source/blender/nodes/composite/nodes/node_composite_bokehblur.c
+++ b/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc
@@ -22,7 +22,7 @@
* \ingroup cmpnodes
*/
-#include "../node_composite_util.h"
+#include "../node_composite_util.hh"
/* **************** BLUR ******************** */
static bNodeSocketTemplate cmp_node_bokehblur_in[] = {
diff --git a/source/blender/nodes/composite/nodes/node_composite_bokehimage.c b/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc
index 744aba417be..3a4bf94d256 100644
--- a/source/blender/nodes/composite/nodes/node_composite_bokehimage.c
+++ b/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc
@@ -21,18 +21,22 @@
* \ingroup cmpnodes
*/
-#include "../node_composite_util.h"
+#include "../node_composite_util.hh"
/* **************** Bokeh image Tools ******************** */
-static bNodeSocketTemplate cmp_node_bokehimage_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_bokehimage_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Color>("Image");
+}
+
+} // namespace blender::nodes
static void node_composit_init_bokehimage(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeBokehImage *data = MEM_callocN(sizeof(NodeBokehImage), "NodeBokehImage");
+ NodeBokehImage *data = (NodeBokehImage *)MEM_callocN(sizeof(NodeBokehImage), "NodeBokehImage");
data->angle = 0.0f;
data->flaps = 5;
data->rounding = 0.0f;
@@ -46,7 +50,7 @@ void register_node_type_cmp_bokehimage(void)
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_BOKEHIMAGE, "Bokeh Image", NODE_CLASS_INPUT, NODE_PREVIEW);
- node_type_socket_templates(&ntype, NULL, cmp_node_bokehimage_out);
+ ntype.declare = blender::nodes::cmp_node_bokehimage_declare;
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.c b/source/blender/nodes/composite/nodes/node_composite_boxmask.cc
index e646b9a9adf..cdf96065f97 100644
--- a/source/blender/nodes/composite/nodes/node_composite_boxmask.c
+++ b/source/blender/nodes/composite/nodes/node_composite_boxmask.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "../node_composite_util.h"
+#include "../node_composite_util.hh"
/* **************** SCALAR MATH ******************** */
static bNodeSocketTemplate cmp_node_boxmask_in[] = {
@@ -34,7 +34,7 @@ static bNodeSocketTemplate cmp_node_boxmask_out[] = {
static void node_composit_init_boxmask(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeBoxMask *data = MEM_callocN(sizeof(NodeBoxMask), "NodeBoxMask");
+ NodeBoxMask *data = (NodeBoxMask *)MEM_callocN(sizeof(NodeBoxMask), "NodeBoxMask");
data->x = 0.5;
data->y = 0.5;
data->width = 0.2;
diff --git a/source/blender/nodes/composite/nodes/node_composite_brightness.c b/source/blender/nodes/composite/nodes/node_composite_brightness.cc
index 5beecb55665..ad4b09c69d0 100644
--- a/source/blender/nodes/composite/nodes/node_composite_brightness.c
+++ b/source/blender/nodes/composite/nodes/node_composite_brightness.cc
@@ -21,20 +21,21 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
-/* **************** Brigh and contrsast ******************** */
+/* **************** Bright and Contrast ******************** */
-static bNodeSocketTemplate cmp_node_brightcontrast_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Bright"), 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Contrast"), 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_brightcontrast_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_brightcontrast_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>("Bright").min(-100.0f).max(100.0f);
+ b.add_input<decl::Float>("Contrast").min(-100.0f).max(100.0f);
+ b.add_output<decl::Color>("Image");
+}
+
+} // namespace blender::nodes
static void node_composit_init_brightcontrast(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -46,7 +47,7 @@ void register_node_type_cmp_brightcontrast(void)
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, cmp_node_brightcontrast_in, cmp_node_brightcontrast_out);
+ ntype.declare = blender::nodes::cmp_node_brightcontrast_declare;
node_type_init(&ntype, node_composit_init_brightcontrast);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_channelMatte.c b/source/blender/nodes/composite/nodes/node_composite_channelMatte.cc
index 9912c10b368..e211bc45b17 100644
--- a/source/blender/nodes/composite/nodes/node_composite_channelMatte.c
+++ b/source/blender/nodes/composite/nodes/node_composite_channelMatte.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* ******************* Channel Matte Node ********************************* */
static bNodeSocketTemplate cmp_node_channel_matte_in[] = {
@@ -37,7 +37,7 @@ static bNodeSocketTemplate cmp_node_channel_matte_out[] = {
static void node_composit_init_channel_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeChroma *c = MEM_callocN(sizeof(NodeChroma), "node chroma");
+ NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node chroma");
node->storage = c;
c->t1 = 1.0f;
c->t2 = 0.0f;
diff --git a/source/blender/nodes/composite/nodes/node_composite_chromaMatte.c b/source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc
index 705566df35a..990778160df 100644
--- a/source/blender/nodes/composite/nodes/node_composite_chromaMatte.c
+++ b/source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* ******************* Chroma Key ********************************************************** */
static bNodeSocketTemplate cmp_node_chroma_in[] = {
@@ -38,7 +38,7 @@ static bNodeSocketTemplate cmp_node_chroma_out[] = {
static void node_composit_init_chroma_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeChroma *c = MEM_callocN(sizeof(NodeChroma), "node chroma");
+ NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node chroma");
node->storage = c;
c->t1 = DEG2RADF(30.0f);
c->t2 = DEG2RADF(10.0f);
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorMatte.c b/source/blender/nodes/composite/nodes/node_composite_colorMatte.cc
index f5cf7bcbf22..fc9a0075b14 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorMatte.c
+++ b/source/blender/nodes/composite/nodes/node_composite_colorMatte.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* ******************* Color Key ********************************************************** */
static bNodeSocketTemplate cmp_node_color_in[] = {
@@ -38,7 +38,7 @@ static bNodeSocketTemplate cmp_node_color_out[] = {
static void node_composit_init_color_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeChroma *c = MEM_callocN(sizeof(NodeChroma), "node color");
+ NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node color");
node->storage = c;
c->t1 = 0.01f;
c->t2 = 0.1f;
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorSpill.c b/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc
index 8ff4bcdced3..7bdc2e8289e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorSpill.c
+++ b/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* ******************* Color Spill Suppression ********************************* */
static bNodeSocketTemplate cmp_node_color_spill_in[] = {
@@ -37,7 +37,7 @@ static bNodeSocketTemplate cmp_node_color_spill_out[] = {
static void node_composit_init_color_spill(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeColorspill *ncs = MEM_callocN(sizeof(NodeColorspill), "node colorspill");
+ NodeColorspill *ncs = (NodeColorspill *)MEM_callocN(sizeof(NodeColorspill), "node colorspill");
node->storage = ncs;
node->custom1 = 2; /* green channel */
node->custom2 = 0; /* simple limit algorithm */
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorbalance.c b/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc
index 0525229697a..440e37fe741 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorbalance.c
+++ b/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc
@@ -21,19 +21,20 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* ******************* Color Balance ********************************* */
-static bNodeSocketTemplate cmp_node_colorbalance_in[] = {
- {SOCK_FLOAT, N_("Fac"), 1.0f, 0.0f, 0.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_colorbalance_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_colorbalance_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>("Fac").default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>("Image");
+}
+
+} // namespace blender::nodes
/* 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
@@ -43,10 +44,9 @@ static bNodeSocketTemplate cmp_node_colorbalance_out[] = {
void ntreeCompositColorBalanceSyncFromLGG(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeColorBalance *n = node->storage;
- int c;
+ NodeColorBalance *n = (NodeColorBalance *)node->storage;
- for (c = 0; c < 3; c++) {
+ for (int c = 0; c < 3; c++) {
n->slope[c] = (2.0f - n->lift[c]) * n->gain[c];
n->offset[c] = (n->lift[c] - 1.0f) * n->gain[c];
n->power[c] = (n->gamma[c] != 0.0f) ? 1.0f / n->gamma[c] : 1000000.0f;
@@ -55,10 +55,9 @@ void ntreeCompositColorBalanceSyncFromLGG(bNodeTree *UNUSED(ntree), bNode *node)
void ntreeCompositColorBalanceSyncFromCDL(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeColorBalance *n = node->storage;
- int c;
+ NodeColorBalance *n = (NodeColorBalance *)node->storage;
- for (c = 0; c < 3; c++) {
+ for (int c = 0; c < 3; c++) {
float d = n->slope[c] + n->offset[c];
n->lift[c] = (d != 0.0f ? n->slope[c] + 2.0f * n->offset[c] / d : 0.0f);
n->gain[c] = d;
@@ -68,7 +67,8 @@ void ntreeCompositColorBalanceSyncFromCDL(bNodeTree *UNUSED(ntree), bNode *node)
static void node_composit_init_colorbalance(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeColorBalance *n = node->storage = MEM_callocN(sizeof(NodeColorBalance), "node colorbalance");
+ NodeColorBalance *n = (NodeColorBalance *)MEM_callocN(sizeof(NodeColorBalance),
+ "node colorbalance");
n->lift[0] = n->lift[1] = n->lift[2] = 1.0f;
n->gamma[0] = n->gamma[1] = n->gamma[2] = 1.0f;
@@ -77,6 +77,7 @@ static void node_composit_init_colorbalance(bNodeTree *UNUSED(ntree), bNode *nod
n->slope[0] = n->slope[1] = n->slope[2] = 1.0f;
n->offset[0] = n->offset[1] = n->offset[2] = 0.0f;
n->power[0] = n->power[1] = n->power[2] = 1.0f;
+ node->storage = n;
}
void register_node_type_cmp_colorbalance(void)
@@ -84,7 +85,7 @@ void register_node_type_cmp_colorbalance(void)
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_COLORBALANCE, "Color Balance", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, cmp_node_colorbalance_in, cmp_node_colorbalance_out);
+ ntype.declare = blender::nodes::cmp_node_colorbalance_declare;
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.c b/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc
index 45d39f8be8d..0682c66f1e8 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorcorrection.c
+++ b/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc
@@ -21,24 +21,25 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
-/* ******************* Color Balance ********************************* */
-static bNodeSocketTemplate cmp_node_colorcorrection_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Mask"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
+/* ******************* Color Correction ********************************* */
-static bNodeSocketTemplate cmp_node_colorcorrection_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_colorcorrection_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>("Mask").default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>("Image");
+}
+
+} // namespace blender::nodes
static void node_composit_init_colorcorrection(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeColorCorrection *n = node->storage = MEM_callocN(sizeof(NodeColorCorrection),
- "node colorcorrection");
+ NodeColorCorrection *n = (NodeColorCorrection *)MEM_callocN(sizeof(NodeColorCorrection),
+ "node colorcorrection");
n->startmidtones = 0.2f;
n->endmidtones = 0.7f;
n->master.contrast = 1.0f;
@@ -62,6 +63,7 @@ static void node_composit_init_colorcorrection(bNodeTree *UNUSED(ntree), bNode *
n->highlights.lift = 0.0f;
n->highlights.saturation = 1.0f;
node->custom1 = 7; // red + green + blue enabled
+ node->storage = n;
}
void register_node_type_cmp_colorcorrection(void)
@@ -69,7 +71,7 @@ void register_node_type_cmp_colorcorrection(void)
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_COLORCORRECTION, "Color Correction", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, cmp_node_colorcorrection_in, cmp_node_colorcorrection_out);
+ ntype.declare = blender::nodes::cmp_node_colorcorrection_declare;
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.c b/source/blender/nodes/composite/nodes/node_composite_common.cc
index 61abc80fe93..fecf6795ef7 100644
--- a/source/blender/nodes/composite/nodes/node_composite_common.c
+++ b/source/blender/nodes/composite/nodes/node_composite_common.cc
@@ -26,7 +26,7 @@
#include "NOD_common.h"
#include "node_common.h"
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
#include "BKE_node.h"
@@ -46,10 +46,10 @@ void register_node_type_cmp_group(void)
ntype.insert_link = node_insert_link_default;
ntype.update_internal_links = node_update_internal_links_default;
ntype.rna_ext.srna = RNA_struct_find("CompositorNodeGroup");
- BLI_assert(ntype.rna_ext.srna != NULL);
+ BLI_assert(ntype.rna_ext.srna != nullptr);
RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype);
- node_type_socket_templates(&ntype, NULL, NULL);
+ node_type_socket_templates(&ntype, nullptr, nullptr);
node_type_size(&ntype, 140, 60, 400);
node_type_label(&ntype, node_group_label);
node_type_group_update(&ntype, node_group_update);
@@ -60,13 +60,13 @@ void register_node_type_cmp_group(void)
void register_node_type_cmp_custom_group(bNodeType *ntype)
{
/* These methods can be overridden but need a default implementation otherwise. */
- if (ntype->poll == NULL) {
+ if (ntype->poll == nullptr) {
ntype->poll = cmp_node_poll_default;
}
- if (ntype->insert_link == NULL) {
+ if (ntype->insert_link == nullptr) {
ntype->insert_link = node_insert_link_default;
}
- if (ntype->update_internal_links == NULL) {
+ if (ntype->update_internal_links == nullptr) {
ntype->update_internal_links = node_update_internal_links_default;
}
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_composite.c b/source/blender/nodes/composite/nodes/node_composite_composite.cc
index dee2ce6b3ec..170fecb251c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_composite.c
+++ b/source/blender/nodes/composite/nodes/node_composite_composite.cc
@@ -21,25 +21,30 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** COMPOSITE ******************** */
-static bNodeSocketTemplate cmp_node_composite_in[] = {
- {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Alpha"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Z"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_composite_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>("Image").default_value({0.0f, 0.0f, 0.0f, 1.0f});
+ b.add_input<decl::Float>("Alpha").default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>("Z").default_value(1.0f).min(0.0f).max(1.0f);
+}
+
+} // namespace blender::nodes
void register_node_type_cmp_composite(void)
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_COMPOSITE, "Composite", NODE_CLASS_OUTPUT, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_composite_in, NULL);
+ ntype.declare = blender::nodes::cmp_node_composite_declare;
/* Do not allow muting for this node. */
- node_type_internal_links(&ntype, NULL);
+ node_type_internal_links(&ntype, nullptr);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_cornerpin.c b/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc
index 135120c45aa..b5ca1fb015e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_cornerpin.c
+++ b/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#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},
diff --git a/source/blender/nodes/composite/nodes/node_composite_crop.c b/source/blender/nodes/composite/nodes/node_composite_crop.cc
index 868df5367c4..f07dba8a74b 100644
--- a/source/blender/nodes/composite/nodes/node_composite_crop.c
+++ b/source/blender/nodes/composite/nodes/node_composite_crop.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** Crop ******************** */
@@ -36,7 +36,7 @@ static bNodeSocketTemplate cmp_node_crop_out[] = {
static void node_composit_init_crop(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTwoXYs *nxy = MEM_callocN(sizeof(NodeTwoXYs), "node xy data");
+ NodeTwoXYs *nxy = (NodeTwoXYs *)MEM_callocN(sizeof(NodeTwoXYs), "node xy data");
node->storage = nxy;
nxy->x1 = 0;
nxy->x2 = 0;
diff --git a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
index 51dd73a86af..6657267b016 100644
--- a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
#include "BLI_assert.h"
#include "BLI_dynstr.h"
diff --git a/source/blender/nodes/composite/nodes/node_composite_curves.c b/source/blender/nodes/composite/nodes/node_composite_curves.cc
index 470540d3337..88d96e1ca4a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_curves.c
+++ b/source/blender/nodes/composite/nodes/node_composite_curves.cc
@@ -21,16 +21,20 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** CURVE Time ******************** */
-/* custom1 = sfra, custom2 = efra */
-static bNodeSocketTemplate cmp_node_time_out[] = {
- {SOCK_FLOAT, N_("Fac")},
- {-1, ""},
-};
+namespace blender::nodes {
+static void cmp_node_time_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Float>("Fac");
+}
+
+} // namespace blender::nodes
+
+/* custom1 = start_frame, custom2 = end_frame */
static void node_composit_init_curves_time(bNodeTree *UNUSED(ntree), bNode *node)
{
node->custom1 = 1;
@@ -43,7 +47,7 @@ void register_node_type_cmp_curve_time(void)
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_TIME, "Time", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, cmp_node_time_out);
+ ntype.declare = blender::nodes::cmp_node_time_declare;
node_type_size(&ntype, 140, 100, 320);
node_type_init(&ntype, node_composit_init_curves_time);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
@@ -81,18 +85,19 @@ void register_node_type_cmp_curve_vec(void)
}
/* **************** CURVE RGB ******************** */
-static bNodeSocketTemplate cmp_node_curve_rgb_in[] = {
- {SOCK_FLOAT, N_("Fac"), 1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_FACTOR},
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_RGBA, N_("Black Level"), 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_RGBA, N_("White Level"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_curve_rgb_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_rgbcurves_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>("Fac").default_value(1.0f).min(-1.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>("Black Level").default_value({0.0f, 0.0f, 0.0f, 1.0f});
+ b.add_input<decl::Color>("White Level").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>("Image");
+}
+
+} // namespace blender::nodes
static void node_composit_init_curve_rgb(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -104,7 +109,7 @@ void register_node_type_cmp_curve_rgb(void)
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, cmp_node_curve_rgb_in, cmp_node_curve_rgb_out);
+ ntype.declare = blender::nodes::cmp_node_rgbcurves_declare;
node_type_size(&ntype, 200, 140, 320);
node_type_init(&ntype, node_composit_init_curve_rgb);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
diff --git a/source/blender/nodes/composite/nodes/node_composite_defocus.c b/source/blender/nodes/composite/nodes/node_composite_defocus.cc
index 3803f450f49..1103aff4366 100644
--- a/source/blender/nodes/composite/nodes/node_composite_defocus.c
+++ b/source/blender/nodes/composite/nodes/node_composite_defocus.cc
@@ -21,11 +21,11 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
-#include <limits.h>
+#include <climits>
-/* ************ qdn: Defocus node ****************** */
+/* ************ 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},
@@ -38,8 +38,8 @@ static bNodeSocketTemplate cmp_node_defocus_out[] = {
static void node_composit_init_defocus(bNodeTree *UNUSED(ntree), bNode *node)
{
- /* qdn: defocus node */
- NodeDefocus *nbd = MEM_callocN(sizeof(NodeDefocus), "node defocus data");
+ /* defocus node */
+ NodeDefocus *nbd = (NodeDefocus *)MEM_callocN(sizeof(NodeDefocus), "node defocus data");
nbd->bktype = 0;
nbd->rotation = 0.0f;
nbd->preview = 1;
diff --git a/source/blender/nodes/composite/nodes/node_composite_denoise.c b/source/blender/nodes/composite/nodes/node_composite_denoise.cc
index e2c7c7b995f..ec085794462 100644
--- a/source/blender/nodes/composite/nodes/node_composite_denoise.c
+++ b/source/blender/nodes/composite/nodes/node_composite_denoise.cc
@@ -23,7 +23,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.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},
@@ -34,7 +34,7 @@ static bNodeSocketTemplate cmp_node_denoise_out[] = {{SOCK_RGBA, N_("Image")}, {
static void node_composit_init_denonise(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeDenoise *ndg = MEM_callocN(sizeof(NodeDenoise), "node denoise data");
+ NodeDenoise *ndg = (NodeDenoise *)MEM_callocN(sizeof(NodeDenoise), "node denoise data");
ndg->hdr = true;
ndg->prefilter = CMP_NODE_DENOISE_PREFILTER_ACCURATE;
node->storage = ndg;
diff --git a/source/blender/nodes/composite/nodes/node_composite_despeckle.c b/source/blender/nodes/composite/nodes/node_composite_despeckle.cc
index 18567ee2006..52d91dabeb1 100644
--- a/source/blender/nodes/composite/nodes/node_composite_despeckle.c
+++ b/source/blender/nodes/composite/nodes/node_composite_despeckle.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** FILTER ******************** */
static bNodeSocketTemplate cmp_node_despeckle_in[] = {
diff --git a/source/blender/nodes/composite/nodes/node_composite_diffMatte.c b/source/blender/nodes/composite/nodes/node_composite_diffMatte.cc
index 7871a9e8b04..1e1a48381b7 100644
--- a/source/blender/nodes/composite/nodes/node_composite_diffMatte.c
+++ b/source/blender/nodes/composite/nodes/node_composite_diffMatte.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* ******************* channel Difference Matte ********************************* */
static bNodeSocketTemplate cmp_node_diff_matte_in[] = {
@@ -38,7 +38,7 @@ static bNodeSocketTemplate cmp_node_diff_matte_out[] = {
static void node_composit_init_diff_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeChroma *c = MEM_callocN(sizeof(NodeChroma), "node chroma");
+ NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node chroma");
node->storage = c;
c->t1 = 0.1f;
c->t2 = 0.1f;
diff --git a/source/blender/nodes/composite/nodes/node_composite_dilate.c b/source/blender/nodes/composite/nodes/node_composite_dilate.cc
index 12f1f229258..57884a299da 100644
--- a/source/blender/nodes/composite/nodes/node_composite_dilate.c
+++ b/source/blender/nodes/composite/nodes/node_composite_dilate.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** Dilate/Erode ******************** */
@@ -31,7 +31,8 @@ static bNodeSocketTemplate cmp_node_dilateerode_out[] = {{SOCK_FLOAT, N_("Mask")
static void node_composit_init_dilateerode(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeDilateErode *data = MEM_callocN(sizeof(NodeDilateErode), "NodeDilateErode");
+ NodeDilateErode *data = (NodeDilateErode *)MEM_callocN(sizeof(NodeDilateErode),
+ "NodeDilateErode");
data->falloff = PROP_SMOOTH;
node->storage = data;
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_directionalblur.c b/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc
index 6dd60526edf..d9f82ba5009 100644
--- a/source/blender/nodes/composite/nodes/node_composite_directionalblur.c
+++ b/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.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, ""}};
@@ -30,7 +30,7 @@ static bNodeSocketTemplate cmp_node_dblur_out[] = {{SOCK_RGBA, N_("Image")}, {-1
static void node_composit_init_dblur(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeDBlurData *ndbd = MEM_callocN(sizeof(NodeDBlurData), "node dblur data");
+ NodeDBlurData *ndbd = (NodeDBlurData *)MEM_callocN(sizeof(NodeDBlurData), "node dblur data");
node->storage = ndbd;
ndbd->iter = 1;
ndbd->center_x = 0.5;
diff --git a/source/blender/nodes/composite/nodes/node_composite_displace.c b/source/blender/nodes/composite/nodes/node_composite_displace.cc
index 819a4f29b3a..b1ed7f05794 100644
--- a/source/blender/nodes/composite/nodes/node_composite_displace.c
+++ b/source/blender/nodes/composite/nodes/node_composite_displace.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** Displace ******************** */
diff --git a/source/blender/nodes/composite/nodes/node_composite_distanceMatte.c b/source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc
index 3e659fe662b..3f8767ecd08 100644
--- a/source/blender/nodes/composite/nodes/node_composite_distanceMatte.c
+++ b/source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* ******************* channel Distance Matte ********************************* */
static bNodeSocketTemplate cmp_node_distance_matte_in[] = {
@@ -38,7 +38,7 @@ static bNodeSocketTemplate cmp_node_distance_matte_out[] = {
static void node_composit_init_distance_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeChroma *c = MEM_callocN(sizeof(NodeChroma), "node chroma");
+ NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node chroma");
node->storage = c;
c->channel = 1;
c->t1 = 0.1f;
diff --git a/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.c b/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc
index 6f68b187775..7c9a48efc2d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.c
+++ b/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc
@@ -20,7 +20,7 @@
/** \file
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** Double Edge Mask ******************** */
static bNodeSocketTemplate cmp_node_doubleedgemask_in[] = {
diff --git a/source/blender/nodes/composite/nodes/node_composite_ellipsemask.c b/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc
index d5e1d519a1c..67196fb0d35 100644
--- a/source/blender/nodes/composite/nodes/node_composite_ellipsemask.c
+++ b/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "../node_composite_util.h"
+#include "../node_composite_util.hh"
/* **************** SCALAR MATH ******************** */
static bNodeSocketTemplate cmp_node_ellipsemask_in[] = {
@@ -34,7 +34,8 @@ static bNodeSocketTemplate cmp_node_ellipsemask_out[] = {
static void node_composit_init_ellipsemask(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeEllipseMask *data = MEM_callocN(sizeof(NodeEllipseMask), "NodeEllipseMask");
+ NodeEllipseMask *data = (NodeEllipseMask *)MEM_callocN(sizeof(NodeEllipseMask),
+ "NodeEllipseMask");
data->x = 0.5;
data->y = 0.5;
data->width = 0.2;
diff --git a/source/blender/nodes/composite/nodes/node_composite_exposure.c b/source/blender/nodes/composite/nodes/node_composite_exposure.cc
index bd27e4a3d76..fd959376afe 100644
--- a/source/blender/nodes/composite/nodes/node_composite_exposure.c
+++ b/source/blender/nodes/composite/nodes/node_composite_exposure.cc
@@ -21,26 +21,27 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** Exposure ******************** */
-static bNodeSocketTemplate cmp_node_exposure_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Exposure"), 0.0f, 0.0f, 0.0f, 0.0f, -10.0f, 10.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_exposure_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_exposure_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>("Exposure").min(-10.0f).max(10.0f);
+ b.add_output<decl::Color>("Image");
+}
+
+} // namespace blender::nodes
void register_node_type_cmp_exposure(void)
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_EXPOSURE, "Exposure", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, cmp_node_exposure_in, cmp_node_exposure_out);
+ ntype.declare = blender::nodes::cmp_node_exposure_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_filter.c b/source/blender/nodes/composite/nodes/node_composite_filter.cc
index d0ad090ece4..f07619877f4 100644
--- a/source/blender/nodes/composite/nodes/node_composite_filter.c
+++ b/source/blender/nodes/composite/nodes/node_composite_filter.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** FILTER ******************** */
static bNodeSocketTemplate cmp_node_filter_in[] = {
diff --git a/source/blender/nodes/composite/nodes/node_composite_flip.c b/source/blender/nodes/composite/nodes/node_composite_flip.cc
index 91a91bb5f5f..42aa3141f5c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_flip.c
+++ b/source/blender/nodes/composite/nodes/node_composite_flip.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** Flip ******************** */
static bNodeSocketTemplate cmp_node_flip_in[] = {
diff --git a/source/blender/nodes/composite/nodes/node_composite_gamma.c b/source/blender/nodes/composite/nodes/node_composite_gamma.cc
index ddcaf691fd2..a29a001688a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_gamma.c
+++ b/source/blender/nodes/composite/nodes/node_composite_gamma.cc
@@ -21,26 +21,28 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** Gamma Tools ******************** */
-static bNodeSocketTemplate cmp_node_gamma_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Gamma"), 1.0f, 0.0f, 0.0f, 0.0f, 0.001f, 10.0f, PROP_UNSIGNED},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_gamma_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_gamma_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>("Gamma").default_value(1.0f).min(0.001f).max(10.0f).subtype(
+ PROP_UNSIGNED);
+ b.add_output<decl::Color>("Image");
+}
+
+} // namespace blender::nodes
void register_node_type_cmp_gamma(void)
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, cmp_node_gamma_in, cmp_node_gamma_out);
+ ntype.declare = blender::nodes::cmp_node_gamma_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_glare.c b/source/blender/nodes/composite/nodes/node_composite_glare.cc
index a792fcc86cd..8a2fd1e1584 100644
--- a/source/blender/nodes/composite/nodes/node_composite_glare.c
+++ b/source/blender/nodes/composite/nodes/node_composite_glare.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
static bNodeSocketTemplate cmp_node_glare_in[] = {
{SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
@@ -34,7 +34,7 @@ static bNodeSocketTemplate cmp_node_glare_out[] = {
static void node_composit_init_glare(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGlare *ndg = MEM_callocN(sizeof(NodeGlare), "node glare data");
+ NodeGlare *ndg = (NodeGlare *)MEM_callocN(sizeof(NodeGlare), "node glare data");
ndg->quality = 1;
ndg->type = 2;
ndg->iter = 3;
diff --git a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.c b/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc
index 494b6136a6e..07746918a94 100644
--- a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.c
+++ b/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc
@@ -21,28 +21,34 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** Hue Saturation ******************** */
-static bNodeSocketTemplate cmp_node_hue_sat_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Hue"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Saturation"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Value"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Fac"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_hue_sat_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_huesatval_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>("Hue").default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Float>("Saturation")
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(2.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>("Value").default_value(1.0f).min(0.0f).max(2.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Float>("Fac").default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_output<decl::Color>("Image");
+}
+
+} // namespace blender::nodes
void register_node_type_cmp_hue_sat(void)
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, cmp_node_hue_sat_in, cmp_node_hue_sat_out);
+ ntype.declare = blender::nodes::cmp_node_huesatval_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_huecorrect.c b/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc
index 6a5c918d9ae..39014896a7b 100644
--- a/source/blender/nodes/composite/nodes/node_composite_huecorrect.c
+++ b/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc
@@ -21,27 +21,28 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
-static bNodeSocketTemplate cmp_node_huecorrect_in[] = {
- {SOCK_FLOAT, N_("Fac"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
+namespace blender::nodes {
-static bNodeSocketTemplate cmp_node_huecorrect_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+static void cmp_node_huecorrect_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>("Fac").default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>("Image");
+}
+
+} // namespace blender::nodes
static void node_composit_init_huecorrect(bNodeTree *UNUSED(ntree), bNode *node)
{
- CurveMapping *cumapping = node->storage = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- int c;
+ node->storage = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+
+ CurveMapping *cumapping = (CurveMapping *)node->storage;
cumapping->preset = CURVE_PRESET_MID9;
- for (c = 0; c < 3; c++) {
+ for (int c = 0; c < 3; c++) {
CurveMap *cuma = &cumapping->cm[c];
BKE_curvemap_reset(cuma, &cumapping->clipr, cumapping->preset, CURVEMAP_SLOPE_POSITIVE);
}
@@ -55,7 +56,7 @@ void register_node_type_cmp_huecorrect(void)
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_HUECORRECT, "Hue Correct", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, cmp_node_huecorrect_in, cmp_node_huecorrect_out);
+ ntype.declare = blender::nodes::cmp_node_huecorrect_declare;
node_type_size(&ntype, 320, 140, 500);
node_type_init(&ntype, node_composit_init_huecorrect);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
diff --git a/source/blender/nodes/composite/nodes/node_composite_idMask.c b/source/blender/nodes/composite/nodes/node_composite_idMask.cc
index 84563e7560b..de011dd6274 100644
--- a/source/blender/nodes/composite/nodes/node_composite_idMask.c
+++ b/source/blender/nodes/composite/nodes/node_composite_idMask.cc
@@ -21,25 +21,26 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** ID Mask ******************** */
-static bNodeSocketTemplate cmp_node_idmask_in[] = {
- {SOCK_FLOAT, N_("ID value"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_idmask_out[] = {
- {SOCK_FLOAT, N_("Alpha")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_idmask_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>("ID value").default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Float>("Alpha");
+}
+
+} // namespace blender::nodes
void register_node_type_cmp_idmask(void)
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_ID_MASK, "ID Mask", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_idmask_in, cmp_node_idmask_out);
+ ntype.declare = blender::nodes::cmp_node_idmask_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.cc
index a56dfea9dbf..3cef3a7625f 100644
--- a/source/blender/nodes/composite/nodes/node_composite_image.c
+++ b/source/blender/nodes/composite/nodes/node_composite_image.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
#include "BLI_linklist.h"
#include "BLI_utildefines.h"
@@ -84,16 +84,17 @@ static void cmp_node_image_add_pass_output(bNodeTree *ntree,
LinkNodePair *available_sockets,
int *prev_index)
{
- bNodeSocket *sock = BLI_findstring(&node->outputs, name, offsetof(bNodeSocket, name));
+ bNodeSocket *sock = (bNodeSocket *)BLI_findstring(
+ &node->outputs, name, offsetof(bNodeSocket, name));
/* Replace if types don't match. */
if (sock && sock->type != type) {
nodeRemoveSocket(ntree, node, sock);
- sock = NULL;
+ sock = nullptr;
}
/* Create socket if it doesn't exist yet. */
- if (sock == NULL) {
+ if (sock == nullptr) {
if (rres_index >= 0) {
sock = node_add_socket_from_template(
ntree, node, &cmp_node_rlayers_out[rres_index], SOCK_OUT);
@@ -102,18 +103,19 @@ static void cmp_node_image_add_pass_output(bNodeTree *ntree,
sock = nodeAddStaticSocket(ntree, node, SOCK_OUT, type, PROP_NONE, name, name);
}
/* extra socket info */
- NodeImageLayer *sockdata = MEM_callocN(sizeof(NodeImageLayer), "node image layer");
+ NodeImageLayer *sockdata = (NodeImageLayer *)MEM_callocN(sizeof(NodeImageLayer),
+ "node image layer");
sock->storage = sockdata;
}
- NodeImageLayer *sockdata = sock->storage;
+ NodeImageLayer *sockdata = (NodeImageLayer *)sock->storage;
if (sockdata) {
BLI_strncpy(sockdata->pass_name, passname, sizeof(sockdata->pass_name));
}
/* Reorder sockets according to order that passes are added. */
const int after_index = (*prev_index)++;
- bNodeSocket *after_sock = BLI_findlink(&node->outputs, after_index);
+ bNodeSocket *after_sock = (bNodeSocket *)BLI_findlink(&node->outputs, after_index);
BLI_remlink(&node->outputs, sock);
BLI_insertlinkafter(&node->outputs, after_sock, sock);
@@ -128,8 +130,8 @@ static void cmp_node_image_create_outputs(bNodeTree *ntree,
ImBuf *ibuf;
int prev_index = -1;
if (ima) {
- ImageUser *iuser = node->storage;
- ImageUser load_iuser = {NULL};
+ ImageUser *iuser = (ImageUser *)node->storage;
+ ImageUser load_iuser = {nullptr};
int offset = BKE_image_sequence_guess_offset(ima);
/* It is possible that image user in this node is not
@@ -138,21 +140,19 @@ static void cmp_node_image_create_outputs(bNodeTree *ntree,
*
* So we manually construct image user to be sure first
* image from sequence (that one which is set as filename
- * for image datablock) is used for sockets detection
- */
+ * for image data-block) is used for sockets detection. */
load_iuser.ok = 1;
load_iuser.framenr = offset;
/* make sure ima->type is correct */
- ibuf = BKE_image_acquire_ibuf(ima, &load_iuser, NULL);
+ ibuf = BKE_image_acquire_ibuf(ima, &load_iuser, nullptr);
if (ima->rr) {
- RenderLayer *rl = BLI_findlink(&ima->rr->layers, iuser->layer);
+ RenderLayer *rl = (RenderLayer *)BLI_findlink(&ima->rr->layers, iuser->layer);
if (rl) {
- RenderPass *rpass;
- for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
- int type;
+ LISTBASE_FOREACH (RenderPass *, rpass, &rl->passes) {
+ eNodeSocketDatatype type;
if (rpass->channels == 1) {
type = SOCK_FLOAT;
}
@@ -182,7 +182,7 @@ static void cmp_node_image_create_outputs(bNodeTree *ntree,
&prev_index);
}
}
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ BKE_image_release_ibuf(ima, ibuf, nullptr);
return;
}
}
@@ -219,14 +219,14 @@ static void cmp_node_image_create_outputs(bNodeTree *ntree,
available_sockets,
&prev_index);
}
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ BKE_image_release_ibuf(ima, ibuf, nullptr);
}
}
-typedef struct RLayerUpdateData {
+struct RLayerUpdateData {
LinkNodePair *available_sockets;
int prev_index;
-} RLayerUpdateData;
+};
void node_cmp_rlayers_register_pass(bNodeTree *ntree,
bNode *node,
@@ -235,13 +235,13 @@ void node_cmp_rlayers_register_pass(bNodeTree *ntree,
const char *name,
eNodeSocketDatatype type)
{
- RLayerUpdateData *data = node->storage;
+ RLayerUpdateData *data = (RLayerUpdateData *)node->storage;
- if (scene == NULL || view_layer == NULL || data == NULL || node->id != (ID *)scene) {
+ if (scene == nullptr || view_layer == nullptr || data == nullptr || node->id != (ID *)scene) {
return;
}
- ViewLayer *node_view_layer = BLI_findlink(&scene->view_layers, node->custom1);
+ ViewLayer *node_view_layer = (ViewLayer *)BLI_findlink(&scene->view_layers, node->custom1);
if (node_view_layer != view_layer) {
return;
}
@@ -281,7 +281,7 @@ static void cmp_node_rlayer_create_outputs_cb(void *UNUSED(userdata),
* unless we want to register that for every other temp Main we could generate??? */
ntreeCompositRegisterPass(scene->nodetree, scene, view_layer, name, type);
- for (Scene *sce = G_MAIN->scenes.first; sce; sce = sce->id.next) {
+ for (Scene *sce = (Scene *)G_MAIN->scenes.first; sce; sce = (Scene *)sce->id.next) {
if (sce->nodetree && sce != scene) {
ntreeCompositRegisterPass(sce->nodetree, scene, view_layer, name, type);
}
@@ -297,16 +297,17 @@ static void cmp_node_rlayer_create_outputs(bNodeTree *ntree,
if (scene) {
RenderEngineType *engine_type = RE_engines_find(scene->r.engine);
if (engine_type && engine_type->update_render_passes) {
- ViewLayer *view_layer = BLI_findlink(&scene->view_layers, node->custom1);
+ ViewLayer *view_layer = (ViewLayer *)BLI_findlink(&scene->view_layers, node->custom1);
if (view_layer) {
- RLayerUpdateData *data = MEM_mallocN(sizeof(RLayerUpdateData), "render layer update data");
+ RLayerUpdateData *data = (RLayerUpdateData *)MEM_mallocN(sizeof(RLayerUpdateData),
+ "render layer update data");
data->available_sockets = available_sockets;
data->prev_index = -1;
node->storage = data;
RenderEngine *engine = RE_engine_create(engine_type);
RE_engine_update_render_passes(
- engine, scene, view_layer, cmp_node_rlayer_create_outputs_cb, NULL);
+ engine, scene, view_layer, cmp_node_rlayer_create_outputs_cb, nullptr);
RE_engine_free(engine);
if ((scene->r.mode & R_EDGE_FRS) &&
@@ -315,7 +316,7 @@ static void cmp_node_rlayer_create_outputs(bNodeTree *ntree,
}
MEM_freeN(data);
- node->storage = NULL;
+ node->storage = nullptr;
return;
}
@@ -348,8 +349,7 @@ static void cmp_node_rlayer_create_outputs(bNodeTree *ntree,
static void cmp_node_image_verify_outputs(bNodeTree *ntree, bNode *node, bool rlayer)
{
bNodeSocket *sock, *sock_next;
- LinkNodePair available_sockets = {NULL, NULL};
- int sock_index;
+ LinkNodePair available_sockets = {nullptr, nullptr};
/* XXX make callback */
if (rlayer) {
@@ -369,15 +369,15 @@ static void cmp_node_image_verify_outputs(bNodeTree *ntree, bNode *node, bool rl
* the first 31 passes to belong to a specific pass type.
* So, we keep those 31 always allocated before the others as well,
* even if they have no links attached. */
- sock_index = 0;
- for (sock = node->outputs.first; sock; sock = sock_next, sock_index++) {
+ int sock_index = 0;
+ for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock_next, sock_index++) {
sock_next = sock->next;
if (BLI_linklist_index(available_sockets.list, sock) >= 0) {
sock->flag &= ~(SOCK_UNAVAIL | SOCK_HIDDEN);
}
else {
bNodeLink *link;
- for (link = ntree->links.first; link; link = link->next) {
+ for (link = (bNodeLink *)ntree->links.first; link; link = link->next) {
if (link->fromsock == sock) {
break;
}
@@ -392,7 +392,7 @@ static void cmp_node_image_verify_outputs(bNodeTree *ntree, bNode *node, bool rl
}
}
- BLI_linklist_free(available_sockets.list, NULL);
+ BLI_linklist_free(available_sockets.list, nullptr);
}
static void cmp_node_image_update(bNodeTree *ntree, bNode *node)
@@ -407,7 +407,7 @@ static void cmp_node_image_update(bNodeTree *ntree, bNode *node)
static void node_composit_init_image(bNodeTree *ntree, bNode *node)
{
- ImageUser *iuser = MEM_callocN(sizeof(ImageUser), "node image user");
+ ImageUser *iuser = (ImageUser *)MEM_callocN(sizeof(ImageUser), "node image user");
node->storage = iuser;
iuser->frames = 1;
iuser->sfra = 1;
@@ -420,10 +420,8 @@ static void node_composit_init_image(bNodeTree *ntree, bNode *node)
static void node_composit_free_image(bNode *node)
{
- bNodeSocket *sock;
-
/* free extra socket info */
- for (sock = node->outputs.first; sock; sock = sock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
MEM_freeN(sock->storage);
}
@@ -436,9 +434,9 @@ static void node_composit_copy_image(bNodeTree *UNUSED(dest_ntree),
{
dest_node->storage = MEM_dupallocN(src_node->storage);
- const bNodeSocket *src_output_sock = src_node->outputs.first;
- bNodeSocket *dest_output_sock = dest_node->outputs.first;
- while (dest_output_sock != NULL) {
+ const bNodeSocket *src_output_sock = (bNodeSocket *)src_node->outputs.first;
+ bNodeSocket *dest_output_sock = (bNodeSocket *)dest_node->outputs.first;
+ while (dest_output_sock != nullptr) {
dest_output_sock->storage = MEM_dupallocN(src_output_sock->storage);
src_output_sock = src_output_sock->next;
@@ -469,7 +467,7 @@ void node_cmp_rlayers_outputs(bNodeTree *ntree, bNode *node)
const char *node_cmp_rlayers_sock_to_pass(int sock_index)
{
if (sock_index >= NUM_LEGACY_SOCKETS) {
- return NULL;
+ return nullptr;
}
const char *name = cmp_node_rlayers_out[sock_index].name;
/* Exception for alpha, which is derived from Combined. */
@@ -479,14 +477,16 @@ const char *node_cmp_rlayers_sock_to_pass(int sock_index)
static void node_composit_init_rlayers(const bContext *C, PointerRNA *ptr)
{
Scene *scene = CTX_data_scene(C);
- bNode *node = ptr->data;
+ bNode *node = (bNode *)ptr->data;
int sock_index = 0;
node->id = &scene->id;
id_us_plus(node->id);
- for (bNodeSocket *sock = node->outputs.first; sock; sock = sock->next, sock_index++) {
- NodeImageLayer *sockdata = MEM_callocN(sizeof(NodeImageLayer), "node image layer");
+ for (bNodeSocket *sock = (bNodeSocket *)node->outputs.first; sock;
+ sock = sock->next, sock_index++) {
+ NodeImageLayer *sockdata = (NodeImageLayer *)MEM_callocN(sizeof(NodeImageLayer),
+ "node image layer");
sock->storage = sockdata;
BLI_strncpy(sockdata->pass_name,
@@ -510,13 +510,13 @@ static bool node_composit_poll_rlayers(bNodeType *UNUSED(ntype),
* Render layers node can only be used in local scene->nodetree,
* since it directly links to the scene.
*/
- for (scene = G.main->scenes.first; scene; scene = scene->id.next) {
+ for (scene = (Scene *)G.main->scenes.first; scene; scene = (Scene *)scene->id.next) {
if (scene->nodetree == ntree) {
break;
}
}
- if (scene == NULL) {
+ if (scene == nullptr) {
*r_disabled_hint = "The node tree must be the compositing node tree of any scene in the file";
return false;
}
@@ -525,10 +525,8 @@ static bool node_composit_poll_rlayers(bNodeType *UNUSED(ntype),
static void node_composit_free_rlayers(bNode *node)
{
- bNodeSocket *sock;
-
/* free extra socket info */
- for (sock = node->outputs.first; sock; sock = sock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
if (sock->storage) {
MEM_freeN(sock->storage);
}
@@ -540,9 +538,9 @@ static void node_composit_copy_rlayers(bNodeTree *UNUSED(dest_ntree),
const bNode *src_node)
{
/* copy extra socket info */
- const bNodeSocket *src_output_sock = src_node->outputs.first;
- bNodeSocket *dest_output_sock = dest_node->outputs.first;
- while (dest_output_sock != NULL) {
+ const bNodeSocket *src_output_sock = (bNodeSocket *)src_node->outputs.first;
+ bNodeSocket *dest_output_sock = (bNodeSocket *)dest_node->outputs.first;
+ while (dest_output_sock != nullptr) {
dest_output_sock->storage = MEM_dupallocN(src_output_sock->storage);
src_output_sock = src_output_sock->next;
@@ -562,10 +560,10 @@ void register_node_type_cmp_rlayers(void)
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_R_LAYERS, "Render Layers", NODE_CLASS_INPUT, NODE_PREVIEW);
- node_type_socket_templates(&ntype, NULL, cmp_node_rlayers_out);
+ node_type_socket_templates(&ntype, nullptr, cmp_node_rlayers_out);
ntype.initfunc_api = node_composit_init_rlayers;
ntype.poll = node_composit_poll_rlayers;
- node_type_storage(&ntype, NULL, node_composit_free_rlayers, node_composit_copy_rlayers);
+ node_type_storage(&ntype, nullptr, node_composit_free_rlayers, node_composit_copy_rlayers);
node_type_update(&ntype, cmp_node_rlayers_update);
node_type_init(&ntype, node_cmp_rlayers_outputs);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
diff --git a/source/blender/nodes/composite/nodes/node_composite_inpaint.c b/source/blender/nodes/composite/nodes/node_composite_inpaint.cc
index 6c02bca9b39..d0ff97a2ca0 100644
--- a/source/blender/nodes/composite/nodes/node_composite_inpaint.c
+++ b/source/blender/nodes/composite/nodes/node_composite_inpaint.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** Inpaint/ ******************** */
diff --git a/source/blender/nodes/composite/nodes/node_composite_invert.c b/source/blender/nodes/composite/nodes/node_composite_invert.cc
index d229261f208..57b7ed36ccd 100644
--- a/source/blender/nodes/composite/nodes/node_composite_invert.c
+++ b/source/blender/nodes/composite/nodes/node_composite_invert.cc
@@ -21,15 +21,20 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** INVERT ******************** */
-static bNodeSocketTemplate cmp_node_invert_in[] = {
- {SOCK_FLOAT, N_("Fac"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_RGBA, N_("Color"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_invert_out[] = {{SOCK_RGBA, N_("Color")}, {-1, ""}};
+namespace blender::nodes {
+
+static void cmp_node_invert_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>("Fac").default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>("Color").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>("Color");
+}
+
+} // namespace blender::nodes
static void node_composit_init_invert(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -42,7 +47,7 @@ void register_node_type_cmp_invert(void)
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, cmp_node_invert_in, cmp_node_invert_out);
+ ntype.declare = blender::nodes::cmp_node_invert_declare;
node_type_init(&ntype, node_composit_init_invert);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_keying.c b/source/blender/nodes/composite/nodes/node_composite_keying.cc
index 73e86a21ebe..d5547161069 100644
--- a/source/blender/nodes/composite/nodes/node_composite_keying.c
+++ b/source/blender/nodes/composite/nodes/node_composite_keying.cc
@@ -27,7 +27,7 @@
#include "BLI_math_base.h"
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** Translate ******************** */
@@ -48,9 +48,7 @@ static bNodeSocketTemplate cmp_node_keying_out[] = {
static void node_composit_init_keying(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeKeyingData *data;
-
- data = MEM_callocN(sizeof(NodeKeyingData), "node keying data");
+ NodeKeyingData *data = (NodeKeyingData *)MEM_callocN(sizeof(NodeKeyingData), "node keying data");
data->screen_balance = 0.5f;
data->despill_balance = 0.5f;
@@ -59,7 +57,6 @@ static void node_composit_init_keying(bNodeTree *UNUSED(ntree), bNode *node)
data->edge_kernel_tolerance = 0.1f;
data->clip_black = 0.0f;
data->clip_white = 1.0f;
-
node->storage = data;
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_keyingscreen.c b/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc
index e5e97cd72e4..c976a92b92d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_keyingscreen.c
+++ b/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc
@@ -26,7 +26,7 @@
#include "BLI_math_base.h"
#include "BLI_math_color.h"
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** Translate ******************** */
@@ -37,10 +37,8 @@ static bNodeSocketTemplate cmp_node_keyingscreen_out[] = {
static void node_composit_init_keyingscreen(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeKeyingScreenData *data;
-
- data = MEM_callocN(sizeof(NodeKeyingScreenData), "node keyingscreen data");
-
+ NodeKeyingScreenData *data = (NodeKeyingScreenData *)MEM_callocN(sizeof(NodeKeyingScreenData),
+ "node keyingscreen data");
node->storage = data;
}
@@ -49,7 +47,7 @@ void register_node_type_cmp_keyingscreen(void)
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_KEYINGSCREEN, "Keying Screen", NODE_CLASS_MATTE, 0);
- node_type_socket_templates(&ntype, NULL, cmp_node_keyingscreen_out);
+ node_type_socket_templates(&ntype, nullptr, cmp_node_keyingscreen_out);
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.c b/source/blender/nodes/composite/nodes/node_composite_lensdist.cc
index ce8c8c00e24..2a8dc035792 100644
--- a/source/blender/nodes/composite/nodes/node_composite_lensdist.c
+++ b/source/blender/nodes/composite/nodes/node_composite_lensdist.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
static bNodeSocketTemplate cmp_node_lensdist_in[] = {
{SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
@@ -36,7 +36,7 @@ static bNodeSocketTemplate cmp_node_lensdist_out[] = {
static void node_composit_init_lensdist(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeLensDist *nld = MEM_callocN(sizeof(NodeLensDist), "node lensdist data");
+ NodeLensDist *nld = (NodeLensDist *)MEM_callocN(sizeof(NodeLensDist), "node lensdist data");
nld->jit = nld->proj = nld->fit = 0;
node->storage = nld;
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_levels.c b/source/blender/nodes/composite/nodes/node_composite_levels.cc
index 7c70ccf412a..aaab8dcc874 100644
--- a/source/blender/nodes/composite/nodes/node_composite_levels.c
+++ b/source/blender/nodes/composite/nodes/node_composite_levels.cc
@@ -21,19 +21,20 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** LEVELS ******************** */
-static bNodeSocketTemplate cmp_node_view_levels_in[] = {
- {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_view_levels_out[] = {
- {SOCK_FLOAT, N_("Mean")},
- {SOCK_FLOAT, N_("Std Dev")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_levels_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>("Image").default_value({0.0f, 0.0f, 0.0f, 1.0f});
+ b.add_output<decl::Float>("Mean");
+ b.add_output<decl::Float>("Std Dev");
+}
+
+} // namespace blender::nodes
static void node_composit_init_view_levels(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -45,7 +46,7 @@ void register_node_type_cmp_view_levels(void)
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_VIEW_LEVELS, "Levels", NODE_CLASS_OUTPUT, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_view_levels_in, cmp_node_view_levels_out);
+ ntype.declare = blender::nodes::cmp_node_levels_declare;
node_type_init(&ntype, node_composit_init_view_levels);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_lummaMatte.c b/source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc
index cb0f59c2f4a..600406d22b9 100644
--- a/source/blender/nodes/composite/nodes/node_composite_lummaMatte.c
+++ b/source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* ******************* Luma Matte Node ********************************* */
static bNodeSocketTemplate cmp_node_luma_matte_in[] = {
@@ -37,7 +37,7 @@ static bNodeSocketTemplate cmp_node_luma_matte_out[] = {
static void node_composit_init_luma_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeChroma *c = MEM_callocN(sizeof(NodeChroma), "node chroma");
+ NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node chroma");
node->storage = c;
c->t1 = 1.0f;
c->t2 = 0.0f;
diff --git a/source/blender/nodes/composite/nodes/node_composite_mapRange.c b/source/blender/nodes/composite/nodes/node_composite_mapRange.cc
index cd95e73ba5c..808ad538e55 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mapRange.c
+++ b/source/blender/nodes/composite/nodes/node_composite_mapRange.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** MAP VALUE ******************** */
static bNodeSocketTemplate cmp_node_map_range_in[] = {
diff --git a/source/blender/nodes/composite/nodes/node_composite_mapUV.c b/source/blender/nodes/composite/nodes/node_composite_mapUV.cc
index e88a303e449..99032bd042e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mapUV.c
+++ b/source/blender/nodes/composite/nodes/node_composite_mapUV.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** Map UV ******************** */
diff --git a/source/blender/nodes/composite/nodes/node_composite_mapValue.c b/source/blender/nodes/composite/nodes/node_composite_mapValue.cc
index c93807c3801..25c00c2ba13 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mapValue.c
+++ b/source/blender/nodes/composite/nodes/node_composite_mapValue.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** MAP VALUE ******************** */
static bNodeSocketTemplate cmp_node_map_value_in[] = {
diff --git a/source/blender/nodes/composite/nodes/node_composite_mask.c b/source/blender/nodes/composite/nodes/node_composite_mask.cc
index e6a5df6c24b..8b415bb8b63 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mask.c
+++ b/source/blender/nodes/composite/nodes/node_composite_mask.cc
@@ -23,15 +23,22 @@
#include "DNA_mask_types.h"
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
-/* **************** Translate ******************** */
+/* **************** Mask ******************** */
-static bNodeSocketTemplate cmp_node_mask_out[] = {{SOCK_FLOAT, "Mask"}, {-1, ""}};
+namespace blender::nodes {
+
+static void cmp_node_mask_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Float>("Mask");
+}
+
+} // namespace blender::nodes
static void node_composit_init_mask(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeMask *data = MEM_callocN(sizeof(NodeMask), "NodeMask");
+ NodeMask *data = (NodeMask *)MEM_callocN(sizeof(NodeMask), "NodeMask");
data->size_x = data->size_y = 256;
node->storage = data;
@@ -41,7 +48,7 @@ static void node_composit_init_mask(bNodeTree *UNUSED(ntree), bNode *node)
static void node_mask_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
{
- if (node->id != NULL) {
+ if (node->id != nullptr) {
BLI_strncpy(label, node->id->name + 2, maxlen);
}
else {
@@ -54,7 +61,7 @@ void register_node_type_cmp_mask(void)
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_MASK, "Mask", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, cmp_node_mask_out);
+ ntype.declare = blender::nodes::cmp_node_mask_declare;
node_type_init(&ntype, node_composit_init_mask);
node_type_label(&ntype, node_mask_label);
diff --git a/source/blender/nodes/composite/nodes/node_composite_math.c b/source/blender/nodes/composite/nodes/node_composite_math.cc
index 2191c6bcdc3..a9859425e28 100644
--- a/source/blender/nodes/composite/nodes/node_composite_math.c
+++ b/source/blender/nodes/composite/nodes/node_composite_math.cc
@@ -21,23 +21,28 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#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 {
+
+static void cmp_node_math_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>("Value").default_value(0.5f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>("Value", "Value_001").default_value(0.5f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>("Value", "Value_002").default_value(0.5f).min(-10000.0f).max(10000.0f);
+ b.add_output<decl::Float>("Value");
+}
+
+} // namespace blender::nodes
void register_node_type_cmp_math(void)
{
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);
+ ntype.declare = blender::nodes::cmp_node_math_declare;
node_type_label(&ntype, node_math_label);
node_type_update(&ntype, node_math_update);
diff --git a/source/blender/nodes/composite/nodes/node_composite_mixrgb.c b/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc
index 9d3751c7da3..4f2a9c2717c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mixrgb.c
+++ b/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc
@@ -21,19 +21,21 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** 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>("Fac").default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>("Image", "Image_001").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>("Image");
+}
+
+} // namespace blender::nodes
/* custom1 = mix type */
void register_node_type_cmp_mix_rgb(void)
@@ -41,7 +43,7 @@ void register_node_type_cmp_mix_rgb(void)
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);
+ ntype.declare = blender::nodes::cmp_node_mixrgb_declare;
node_type_label(&ntype, node_blend_label);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_movieclip.c b/source/blender/nodes/composite/nodes/node_composite_movieclip.cc
index 4f5aef05425..ae91212f811 100644
--- a/source/blender/nodes/composite/nodes/node_composite_movieclip.c
+++ b/source/blender/nodes/composite/nodes/node_composite_movieclip.cc
@@ -21,26 +21,31 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
#include "BKE_context.h"
#include "BKE_lib_id.h"
-static bNodeSocketTemplate cmp_node_movieclip_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Alpha")},
- {SOCK_FLOAT, N_("Offset X")},
- {SOCK_FLOAT, N_("Offset Y")},
- {SOCK_FLOAT, N_("Scale")},
- {SOCK_FLOAT, N_("Angle")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_movieclip_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Color>("Image");
+ b.add_output<decl::Float>("Alpha");
+ b.add_output<decl::Float>("Offset X");
+ b.add_output<decl::Float>("Offset Y");
+ b.add_output<decl::Float>("Scale");
+ b.add_output<decl::Float>("Angle");
+}
+
+} // namespace blender::nodes
static void init(const bContext *C, PointerRNA *ptr)
{
- bNode *node = ptr->data;
+ bNode *node = (bNode *)ptr->data;
Scene *scene = CTX_data_scene(C);
- MovieClipUser *user = MEM_callocN(sizeof(MovieClipUser), "node movie clip user");
+ MovieClipUser *user = (MovieClipUser *)MEM_callocN(sizeof(MovieClipUser),
+ "node movie clip user");
node->id = (ID *)scene->clip;
id_us_plus(node->id);
@@ -53,7 +58,7 @@ void register_node_type_cmp_movieclip(void)
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_MOVIECLIP, "Movie Clip", NODE_CLASS_INPUT, NODE_PREVIEW);
- node_type_socket_templates(&ntype, NULL, cmp_node_movieclip_out);
+ ntype.declare = blender::nodes::cmp_node_movieclip_declare;
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.c b/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc
index 7e30d004b45..2bac30cc152 100644
--- a/source/blender/nodes/composite/nodes/node_composite_moviedistortion.c
+++ b/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
#include "BKE_context.h"
#include "BKE_lib_id.h"
@@ -50,7 +50,7 @@ static void label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen
static void init(const bContext *C, PointerRNA *ptr)
{
- bNode *node = ptr->data;
+ bNode *node = (bNode *)ptr->data;
Scene *scene = CTX_data_scene(C);
node->id = (ID *)scene->clip;
@@ -60,16 +60,16 @@ static void init(const bContext *C, PointerRNA *ptr)
static void storage_free(bNode *node)
{
if (node->storage) {
- BKE_tracking_distortion_free(node->storage);
+ BKE_tracking_distortion_free((MovieDistortion *)node->storage);
}
- node->storage = NULL;
+ node->storage = nullptr;
}
static void storage_copy(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const bNode *src_node)
{
if (src_node->storage) {
- dest_node->storage = BKE_tracking_distortion_copy(src_node->storage);
+ dest_node->storage = BKE_tracking_distortion_copy((MovieDistortion *)src_node->storage);
}
}
@@ -82,7 +82,7 @@ void register_node_type_cmp_moviedistortion(void)
node_type_label(&ntype, label);
ntype.initfunc_api = init;
- node_type_storage(&ntype, NULL, storage_free, storage_copy);
+ node_type_storage(&ntype, nullptr, storage_free, storage_copy);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_normal.c b/source/blender/nodes/composite/nodes/node_composite_normal.cc
index 91300e66339..7531025daa5 100644
--- a/source/blender/nodes/composite/nodes/node_composite_normal.c
+++ b/source/blender/nodes/composite/nodes/node_composite_normal.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** NORMAL ******************** */
static bNodeSocketTemplate cmp_node_normal_in[] = {
diff --git a/source/blender/nodes/composite/nodes/node_composite_normalize.c b/source/blender/nodes/composite/nodes/node_composite_normalize.cc
index 26f2abc745f..7cc54e4eed6 100644
--- a/source/blender/nodes/composite/nodes/node_composite_normalize.c
+++ b/source/blender/nodes/composite/nodes/node_composite_normalize.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** NORMALIZE single channel, useful for Z buffer ******************** */
static bNodeSocketTemplate cmp_node_normalize_in[] = {
diff --git a/source/blender/nodes/composite/nodes/node_composite_outputFile.c b/source/blender/nodes/composite/nodes/node_composite_outputFile.cc
index c10edd8d5ad..a372d2f7419 100644
--- a/source/blender/nodes/composite/nodes/node_composite_outputFile.c
+++ b/source/blender/nodes/composite/nodes/node_composite_outputFile.cc
@@ -23,13 +23,13 @@
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
-#include <string.h>
+#include <cstring>
#include "BKE_context.h"
#include "RNA_access.h"
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
#include "intern/openexr/openexr_multi.h"
@@ -38,14 +38,15 @@
/* find unique path */
static bool unique_path_unique_check(void *arg, const char *name)
{
- struct {
+ struct Args {
ListBase *lb;
bNodeSocket *sock;
- } *data = arg;
- bNodeSocket *sock;
- for (sock = data->lb->first; sock; sock = sock->next) {
+ };
+ Args *data = (Args *)arg;
+
+ LISTBASE_FOREACH (bNodeSocket *, sock, data->lb) {
if (sock != data->sock) {
- NodeImageMultiFileSocket *sockdata = sock->storage;
+ NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)sock->storage;
if (STREQ(sockdata->path, name)) {
return true;
}
@@ -67,11 +68,11 @@ void ntreeCompositOutputFileUniquePath(ListBase *list,
data.sock = sock;
/* See if we are given an empty string */
- if (ELEM(NULL, sock, defname)) {
+ if (ELEM(nullptr, sock, defname)) {
return;
}
- sockdata = sock->storage;
+ sockdata = (NodeImageMultiFileSocket *)sock->storage;
BLI_uniquename_cb(
unique_path_unique_check, &data, defname, delim, sockdata->path, sizeof(sockdata->path));
}
@@ -79,14 +80,15 @@ void ntreeCompositOutputFileUniquePath(ListBase *list,
/* find unique EXR layer */
static bool unique_layer_unique_check(void *arg, const char *name)
{
- struct {
+ struct Args {
ListBase *lb;
bNodeSocket *sock;
- } *data = arg;
- bNodeSocket *sock;
- for (sock = data->lb->first; sock; sock = sock->next) {
+ };
+ Args *data = (Args *)arg;
+
+ LISTBASE_FOREACH (bNodeSocket *, sock, data->lb) {
if (sock != data->sock) {
- NodeImageMultiFileSocket *sockdata = sock->storage;
+ NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)sock->storage;
if (STREQ(sockdata->layer, name)) {
return true;
}
@@ -99,7 +101,6 @@ void ntreeCompositOutputFileUniqueLayer(ListBase *list,
const char defname[],
char delim)
{
- NodeImageMultiFileSocket *sockdata;
struct {
ListBase *lb;
bNodeSocket *sock;
@@ -108,11 +109,11 @@ void ntreeCompositOutputFileUniqueLayer(ListBase *list,
data.sock = sock;
/* See if we are given an empty string */
- if (ELEM(NULL, sock, defname)) {
+ if (ELEM(nullptr, sock, defname)) {
return;
}
- sockdata = sock->storage;
+ NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)sock->storage;
BLI_uniquename_cb(
unique_layer_unique_check, &data, defname, delim, sockdata->layer, sizeof(sockdata->layer));
}
@@ -122,12 +123,13 @@ bNodeSocket *ntreeCompositOutputFileAddSocket(bNodeTree *ntree,
const char *name,
ImageFormatData *im_format)
{
- NodeImageMultiFile *nimf = node->storage;
- bNodeSocket *sock = nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, NULL, name);
+ NodeImageMultiFile *nimf = (NodeImageMultiFile *)node->storage;
+ bNodeSocket *sock = nodeAddStaticSocket(
+ ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, nullptr, name);
/* create format data for the input socket */
- NodeImageMultiFileSocket *sockdata = MEM_callocN(sizeof(NodeImageMultiFileSocket),
- "socket image format");
+ NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)MEM_callocN(
+ sizeof(NodeImageMultiFileSocket), "socket image format");
sock->storage = sockdata;
BLI_strncpy_utf8(sockdata->path, name, sizeof(sockdata->path));
@@ -155,8 +157,8 @@ bNodeSocket *ntreeCompositOutputFileAddSocket(bNodeTree *ntree,
int ntreeCompositOutputFileRemoveActiveSocket(bNodeTree *ntree, bNode *node)
{
- NodeImageMultiFile *nimf = node->storage;
- bNodeSocket *sock = BLI_findlink(&node->inputs, nimf->active_input);
+ NodeImageMultiFile *nimf = (NodeImageMultiFile *)node->storage;
+ bNodeSocket *sock = (bNodeSocket *)BLI_findlink(&node->inputs, nimf->active_input);
int totinputs = BLI_listbase_count(&node->inputs);
if (!sock) {
@@ -176,14 +178,14 @@ int ntreeCompositOutputFileRemoveActiveSocket(bNodeTree *ntree, bNode *node)
void ntreeCompositOutputFileSetPath(bNode *node, bNodeSocket *sock, const char *name)
{
- NodeImageMultiFileSocket *sockdata = sock->storage;
+ NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)sock->storage;
BLI_strncpy_utf8(sockdata->path, name, sizeof(sockdata->path));
ntreeCompositOutputFileUniquePath(&node->inputs, sock, name, '_');
}
void ntreeCompositOutputFileSetLayer(bNode *node, bNodeSocket *sock, const char *name)
{
- NodeImageMultiFileSocket *sockdata = sock->storage;
+ NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)sock->storage;
BLI_strncpy_utf8(sockdata->layer, name, sizeof(sockdata->layer));
ntreeCompositOutputFileUniqueLayer(&node->inputs, sock, name, '_');
}
@@ -193,9 +195,10 @@ static void init_output_file(const bContext *C, PointerRNA *ptr)
{
Scene *scene = CTX_data_scene(C);
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNode *node = ptr->data;
- NodeImageMultiFile *nimf = MEM_callocN(sizeof(NodeImageMultiFile), "node image multi file");
- ImageFormatData *format = NULL;
+ bNode *node = (bNode *)ptr->data;
+ NodeImageMultiFile *nimf = (NodeImageMultiFile *)MEM_callocN(sizeof(NodeImageMultiFile),
+ "node image multi file");
+ ImageFormatData *format = nullptr;
node->storage = nimf;
if (scene) {
@@ -219,10 +222,8 @@ static void init_output_file(const bContext *C, PointerRNA *ptr)
static void free_output_file(bNode *node)
{
- bNodeSocket *sock;
-
/* free storage data in sockets */
- for (sock = node->inputs.first; sock; sock = sock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
MEM_freeN(sock->storage);
}
@@ -238,37 +239,35 @@ static void copy_output_file(bNodeTree *UNUSED(dest_ntree),
dest_node->storage = MEM_dupallocN(src_node->storage);
/* duplicate storage data in sockets */
- for (src_sock = src_node->inputs.first, dest_sock = dest_node->inputs.first;
+ for (src_sock = (bNodeSocket *)src_node->inputs.first,
+ dest_sock = (bNodeSocket *)dest_node->inputs.first;
src_sock && dest_sock;
- src_sock = src_sock->next, dest_sock = dest_sock->next) {
+ src_sock = src_sock->next, dest_sock = (bNodeSocket *)dest_sock->next) {
dest_sock->storage = MEM_dupallocN(src_sock->storage);
}
}
static void update_output_file(bNodeTree *ntree, bNode *node)
{
- bNodeSocket *sock, *sock_next;
PointerRNA ptr;
/* XXX fix for T36706: remove invalid sockets added with bpy API.
* This is not ideal, but prevents crashes from missing storage.
* FileOutput node needs a redesign to support this properly.
*/
- for (sock = node->inputs.first; sock; sock = sock_next) {
- sock_next = sock->next;
- if (sock->storage == NULL) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ if (sock->storage == nullptr) {
nodeRemoveSocket(ntree, node, sock);
}
}
- for (sock = node->outputs.first; sock; sock = sock_next) {
- sock_next = sock->next;
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
nodeRemoveSocket(ntree, node, sock);
}
cmp_node_update_default(ntree, node);
/* automatically update the socket type based on linked input */
- for (sock = node->inputs.first; sock; sock = sock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
if (sock->link) {
RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
RNA_enum_set(&ptr, "type", sock->link->fromsock->type);
@@ -281,7 +280,7 @@ void register_node_type_cmp_output_file(void)
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_OUTPUT_FILE, "File Output", NODE_CLASS_OUTPUT, NODE_PREVIEW);
- node_type_socket_templates(&ntype, NULL, NULL);
+ node_type_socket_templates(&ntype, nullptr, nullptr);
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.c b/source/blender/nodes/composite/nodes/node_composite_pixelate.cc
index 6e8a28df76f..19975c21a0b 100644
--- a/source/blender/nodes/composite/nodes/node_composite_pixelate.c
+++ b/source/blender/nodes/composite/nodes/node_composite_pixelate.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** Pixelate ******************** */
diff --git a/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.c b/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc
index ab5db41e5b5..e122b710b7b 100644
--- a/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.c
+++ b/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.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, ""}};
@@ -34,8 +34,8 @@ static bNodeSocketTemplate cmp_node_planetrackdeform_out[] = {
static void init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodePlaneTrackDeformData *data = MEM_callocN(sizeof(NodePlaneTrackDeformData),
- "node plane track deform data");
+ NodePlaneTrackDeformData *data = (NodePlaneTrackDeformData *)MEM_callocN(
+ sizeof(NodePlaneTrackDeformData), "node plane track deform data");
data->motion_blur_samples = 16;
data->motion_blur_shutter = 0.5f;
node->storage = data;
diff --git a/source/blender/nodes/composite/nodes/node_composite_posterize.c b/source/blender/nodes/composite/nodes/node_composite_posterize.cc
index 5093e581cdc..45a98e68b4b 100644
--- a/source/blender/nodes/composite/nodes/node_composite_posterize.c
+++ b/source/blender/nodes/composite/nodes/node_composite_posterize.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** Posterize ******************** */
diff --git a/source/blender/nodes/composite/nodes/node_composite_premulkey.c b/source/blender/nodes/composite/nodes/node_composite_premulkey.cc
index be76bbf01cf..e557854c611 100644
--- a/source/blender/nodes/composite/nodes/node_composite_premulkey.c
+++ b/source/blender/nodes/composite/nodes/node_composite_premulkey.cc
@@ -21,25 +21,26 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** Premul and Key Alpha Convert ******************** */
-static bNodeSocketTemplate cmp_node_premulkey_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_premulkey_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_premulkey_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>("Image");
+}
+
+} // namespace blender::nodes
void register_node_type_cmp_premulkey(void)
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_PREMULKEY, "Alpha Convert", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_premulkey_in, cmp_node_premulkey_out);
+ ntype.declare = blender::nodes::cmp_node_premulkey_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_rgb.c b/source/blender/nodes/composite/nodes/node_composite_rgb.cc
index dae63f7a702..332e56e26b1 100644
--- a/source/blender/nodes/composite/nodes/node_composite_rgb.c
+++ b/source/blender/nodes/composite/nodes/node_composite_rgb.cc
@@ -21,20 +21,25 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** RGB ******************** */
-static bNodeSocketTemplate cmp_node_rgb_out[] = {
- {SOCK_RGBA, N_("RGBA"), 0.5f, 0.5f, 0.5f, 1.0f},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_rgb_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Color>("RGBA").default_value({0.5f, 0.5f, 0.5f, 1.0f});
+}
+
+} // namespace blender::nodes
void register_node_type_cmp_rgb(void)
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_RGB, "RGB", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, cmp_node_rgb_out);
+ ntype.declare = blender::nodes::cmp_node_rgb_declare;
node_type_size_preset(&ntype, NODE_SIZE_SMALL);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_rotate.c b/source/blender/nodes/composite/nodes/node_composite_rotate.cc
index 7dd39d5eaa1..d28b35ec9fb 100644
--- a/source/blender/nodes/composite/nodes/node_composite_rotate.c
+++ b/source/blender/nodes/composite/nodes/node_composite_rotate.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** Rotate ******************** */
diff --git a/source/blender/nodes/composite/nodes/node_composite_scale.c b/source/blender/nodes/composite/nodes/node_composite_scale.cc
index 963832de03a..3972fc0d949 100644
--- a/source/blender/nodes/composite/nodes/node_composite_scale.c
+++ b/source/blender/nodes/composite/nodes/node_composite_scale.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** Scale ******************** */
@@ -38,7 +38,7 @@ static void node_composite_update_scale(bNodeTree *UNUSED(ntree), bNode *node)
bool use_xy_scale = ELEM(node->custom1, CMP_SCALE_RELATIVE, CMP_SCALE_ABSOLUTE);
/* Only show X/Y scale factor inputs for modes using them! */
- for (sock = node->inputs.first; sock; sock = sock->next) {
+ for (sock = (bNodeSocket *)node->inputs.first; sock; sock = sock->next) {
if (STR_ELEM(sock->name, "X", "Y")) {
if (use_xy_scale) {
sock->flag &= ~SOCK_UNAVAIL;
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.c b/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc
index 001b197e23a..aa719a99b36 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.c
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc
@@ -21,50 +21,53 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** SEPARATE HSVA ******************** */
-static bNodeSocketTemplate cmp_node_sephsva_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_sephsva_out[] = {
- {SOCK_FLOAT, N_("H")},
- {SOCK_FLOAT, N_("S")},
- {SOCK_FLOAT, N_("V")},
- {SOCK_FLOAT, N_("A")},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_sephsva_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Float>("H");
+ b.add_output<decl::Float>("S");
+ b.add_output<decl::Float>("V");
+ b.add_output<decl::Float>("A");
+}
+
+} // namespace blender::nodes
void register_node_type_cmp_sephsva(void)
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_SEPHSVA, "Separate HSVA", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_sephsva_in, cmp_node_sephsva_out);
-
+ ntype.declare = blender::nodes::cmp_node_sephsva_declare;
nodeRegisterType(&ntype);
}
/* **************** COMBINE HSVA ******************** */
-static bNodeSocketTemplate cmp_node_combhsva_in[] = {
- {SOCK_FLOAT, N_("H"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("S"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("V"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("A"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_combhsva_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_combhsva_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>("H").min(0.0f).max(1.0f);
+ b.add_input<decl::Float>("S").min(0.0f).max(1.0f);
+ b.add_input<decl::Float>("V").min(0.0f).max(1.0f);
+ b.add_input<decl::Float>("A").default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>("Image");
+}
+
+} // namespace blender::nodes
void register_node_type_cmp_combhsva(void)
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_COMBHSVA, "Combine HSVA", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_combhsva_in, cmp_node_combhsva_out);
+ ntype.declare = blender::nodes::cmp_node_combhsva_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.c b/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc
index e08f27db254..b29af1359f5 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.c
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc
@@ -21,50 +21,53 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** SEPARATE RGBA ******************** */
-static bNodeSocketTemplate cmp_node_seprgba_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_seprgba_out[] = {
- {SOCK_FLOAT, N_("R")},
- {SOCK_FLOAT, N_("G")},
- {SOCK_FLOAT, N_("B")},
- {SOCK_FLOAT, N_("A")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_seprgba_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Float>("R");
+ b.add_output<decl::Float>("G");
+ b.add_output<decl::Float>("B");
+ b.add_output<decl::Float>("A");
+}
+
+} // namespace blender::nodes
void register_node_type_cmp_seprgba(void)
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_SEPRGBA, "Separate RGBA", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_seprgba_in, cmp_node_seprgba_out);
+ ntype.declare = blender::nodes::cmp_node_seprgba_declare;
nodeRegisterType(&ntype);
}
/* **************** COMBINE RGBA ******************** */
-static bNodeSocketTemplate cmp_node_combrgba_in[] = {
- {SOCK_FLOAT, N_("R"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("G"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("B"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("A"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_combrgba_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_combrgba_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>("R").min(0.0f).max(1.0f);
+ b.add_input<decl::Float>("G").min(0.0f).max(1.0f);
+ b.add_input<decl::Float>("B").min(0.0f).max(1.0f);
+ b.add_input<decl::Float>("A").default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>("Image");
+}
+
+} // namespace blender::nodes
void register_node_type_cmp_combrgba(void)
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_COMBRGBA, "Combine RGBA", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_combrgba_in, cmp_node_combrgba_out);
+ ntype.declare = blender::nodes::cmp_node_combrgba_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.c b/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc
index b3884296600..526d6b4eb5b 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.c
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc
@@ -21,18 +21,22 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** SEPARATE YCCA ******************** */
-static bNodeSocketTemplate cmp_node_sepycca_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, {-1, ""}};
-static bNodeSocketTemplate cmp_node_sepycca_out[] = {
- {SOCK_FLOAT, N_("Y")},
- {SOCK_FLOAT, N_("Cb")},
- {SOCK_FLOAT, N_("Cr")},
- {SOCK_FLOAT, N_("A")},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_sepycca_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Float>("Y");
+ b.add_output<decl::Float>("Cb");
+ b.add_output<decl::Float>("Cr");
+ b.add_output<decl::Float>("A");
+}
+
+} // namespace blender::nodes
static void node_composit_init_mode_sepycca(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -44,24 +48,26 @@ void register_node_type_cmp_sepycca(void)
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_SEPYCCA, "Separate YCbCrA", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_sepycca_in, cmp_node_sepycca_out);
+ ntype.declare = blender::nodes::cmp_node_sepycca_declare;
node_type_init(&ntype, node_composit_init_mode_sepycca);
nodeRegisterType(&ntype);
}
/* **************** COMBINE YCCA ******************** */
-static bNodeSocketTemplate cmp_node_combycca_in[] = {
- {SOCK_FLOAT, N_("Y"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Cb"), 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Cr"), 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("A"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_combycca_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_combycca_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>("Y").min(0.0f).max(1.0f);
+ b.add_input<decl::Float>("Cb").default_value(0.5f).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>("Cr").default_value(0.5f).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>("A").default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>("Image");
+}
+
+} // namespace blender::nodes
static void node_composit_init_mode_combycca(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -73,7 +79,7 @@ void register_node_type_cmp_combycca(void)
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_COMBYCCA, "Combine YCbCrA", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_combycca_in, cmp_node_combycca_out);
+ ntype.declare = blender::nodes::cmp_node_combycca_declare;
node_type_init(&ntype, node_composit_init_mode_combycca);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.c b/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc
index 4da79ec7981..4619b0c97f1 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.c
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc
@@ -21,48 +21,54 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** SEPARATE YUVA ******************** */
-static bNodeSocketTemplate cmp_node_sepyuva_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, {-1, ""}};
-static bNodeSocketTemplate cmp_node_sepyuva_out[] = {
- {SOCK_FLOAT, N_("Y")},
- {SOCK_FLOAT, N_("U")},
- {SOCK_FLOAT, N_("V")},
- {SOCK_FLOAT, N_("A")},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_sepyuva_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Float>("Y");
+ b.add_output<decl::Float>("U");
+ b.add_output<decl::Float>("V");
+ b.add_output<decl::Float>("A");
+}
+
+} // namespace blender::nodes
void register_node_type_cmp_sepyuva(void)
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_SEPYUVA, "Separate YUVA", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_sepyuva_in, cmp_node_sepyuva_out);
+ ntype.declare = blender::nodes::cmp_node_sepyuva_declare;
nodeRegisterType(&ntype);
}
/* **************** COMBINE YUVA ******************** */
-static bNodeSocketTemplate cmp_node_combyuva_in[] = {
- {SOCK_FLOAT, N_("Y"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("U"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("V"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("A"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_combyuva_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_combyuva_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>("Y").min(0.0f).max(1.0f);
+ b.add_input<decl::Float>("U").min(0.0f).max(1.0f);
+ b.add_input<decl::Float>("V").min(0.0f).max(1.0f);
+ b.add_input<decl::Float>("A").default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>("Image");
+}
+
+} // namespace blender::nodes
void register_node_type_cmp_combyuva(void)
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_COMBYUVA, "Combine YUVA", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_combyuva_in, cmp_node_combyuva_out);
+ ntype.declare = blender::nodes::cmp_node_combyuva_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_setalpha.c b/source/blender/nodes/composite/nodes/node_composite_setalpha.cc
index 1b44cc011e9..07a7ffcb426 100644
--- a/source/blender/nodes/composite/nodes/node_composite_setalpha.c
+++ b/source/blender/nodes/composite/nodes/node_composite_setalpha.cc
@@ -21,22 +21,24 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** SET ALPHA ******************** */
-static bNodeSocketTemplate cmp_node_setalpha_in[] = {
- {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Alpha"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_setalpha_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_setalpha_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>("Alpha").default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>("Image");
+}
+
+} // namespace blender::nodes
static void node_composit_init_setalpha(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeSetAlpha *settings = MEM_callocN(sizeof(NodeSetAlpha), __func__);
+ NodeSetAlpha *settings = (NodeSetAlpha *)MEM_callocN(sizeof(NodeSetAlpha), __func__);
node->storage = settings;
settings->mode = CMP_NODE_SETALPHA_MODE_APPLY;
}
@@ -46,7 +48,7 @@ void register_node_type_cmp_setalpha(void)
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_SETALPHA, "Set Alpha", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_setalpha_in, cmp_node_setalpha_out);
+ ntype.declare = blender::nodes::cmp_node_setalpha_declare;
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.c b/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc
index 8afb3fd4841..f64abe87116 100644
--- a/source/blender/nodes/composite/nodes/node_composite_splitViewer.c
+++ b/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc
@@ -21,21 +21,26 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
#include "BKE_global.h"
#include "BKE_image.h"
/* **************** 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_splitviewer_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>("Image");
+ b.add_input<decl::Color>("Image", "Image_001");
+}
+
+} // namespace blender::nodes
static void node_composit_init_splitviewer(bNodeTree *UNUSED(ntree), bNode *node)
{
- ImageUser *iuser = MEM_callocN(sizeof(ImageUser), "node image user");
+ ImageUser *iuser = (ImageUser *)MEM_callocN(sizeof(ImageUser), "node image user");
node->storage = iuser;
iuser->sfra = 1;
iuser->ok = 1;
@@ -50,12 +55,12 @@ void register_node_type_cmp_splitviewer(void)
cmp_node_type_base(
&ntype, CMP_NODE_SPLITVIEWER, "Split Viewer", NODE_CLASS_OUTPUT, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_splitviewer_in, NULL);
+ ntype.declare = blender::nodes::cmp_node_splitviewer_declare;
node_type_init(&ntype, node_composit_init_splitviewer);
node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage);
/* Do not allow muting for this node. */
- node_type_internal_links(&ntype, NULL);
+ node_type_internal_links(&ntype, nullptr);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_stabilize2d.c b/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc
index b89f245c542..e5ce2e8ceb9 100644
--- a/source/blender/nodes/composite/nodes/node_composite_stabilize2d.c
+++ b/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
#include "BKE_context.h"
#include "BKE_lib_id.h"
@@ -40,7 +40,7 @@ static bNodeSocketTemplate cmp_node_stabilize2d_out[] = {
static void init(const bContext *C, PointerRNA *ptr)
{
- bNode *node = ptr->data;
+ bNode *node = (bNode *)ptr->data;
Scene *scene = CTX_data_scene(C);
node->id = (ID *)scene->clip;
diff --git a/source/blender/nodes/composite/nodes/node_composite_sunbeams.c b/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc
index 84ab2d30d34..73907d2e27f 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sunbeams.c
+++ b/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
static bNodeSocketTemplate inputs[] = {
{SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
@@ -34,11 +34,10 @@ static bNodeSocketTemplate outputs[] = {
static void init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeSunBeams *data = MEM_callocN(sizeof(NodeSunBeams), "sun beams node");
+ NodeSunBeams *data = (NodeSunBeams *)MEM_callocN(sizeof(NodeSunBeams), "sun beams node");
data->source[0] = 0.5f;
data->source[1] = 0.5f;
-
node->storage = data;
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_switch.c b/source/blender/nodes/composite/nodes/node_composite_switch.cc
index efbb3390e06..71226a6da0b 100644
--- a/source/blender/nodes/composite/nodes/node_composite_switch.c
+++ b/source/blender/nodes/composite/nodes/node_composite_switch.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "../node_composite_util.h"
+#include "../node_composite_util.hh"
/* **************** MIX RGB ******************** */
static bNodeSocketTemplate cmp_node_switch_in[] = {
diff --git a/source/blender/nodes/composite/nodes/node_composite_switchview.c b/source/blender/nodes/composite/nodes/node_composite_switchview.cc
index b09d5119bc4..a61712f7f8d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_switchview.c
+++ b/source/blender/nodes/composite/nodes/node_composite_switchview.cc
@@ -25,7 +25,7 @@
#include "BKE_context.h"
#include "BKE_lib_id.h"
-#include "../node_composite_util.h"
+#include "../node_composite_util.hh"
/* **************** SWITCH VIEW ******************** */
static bNodeSocketTemplate cmp_node_switch_view_out[] = {
@@ -37,26 +37,23 @@ static bNodeSocket *ntreeCompositSwitchViewAddSocket(bNodeTree *ntree,
bNode *node,
const char *name)
{
- bNodeSocket *sock = nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, NULL, name);
+ bNodeSocket *sock = nodeAddStaticSocket(
+ ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, nullptr, name);
return sock;
}
static void cmp_node_switch_view_sanitycheck(bNodeTree *ntree, bNode *node)
{
- bNodeSocket *sock;
-
if (!BLI_listbase_is_empty(&node->inputs)) {
return;
}
- sock = ntreeCompositSwitchViewAddSocket(ntree, node, "No View");
+ bNodeSocket *sock = ntreeCompositSwitchViewAddSocket(ntree, node, "No View");
sock->flag |= SOCK_HIDDEN;
}
static void cmp_node_switch_view_update(bNodeTree *ntree, bNode *node)
{
- bNodeSocket *sock;
- SceneRenderView *srv;
Scene *scene = (Scene *)node->id;
/* only update when called from the operator button */
@@ -64,7 +61,7 @@ static void cmp_node_switch_view_update(bNodeTree *ntree, bNode *node)
return;
}
- if (scene == NULL) {
+ if (scene == nullptr) {
nodeRemoveAllSockets(ntree, node);
/* make sure there is always one socket */
cmp_node_switch_view_sanitycheck(ntree, node);
@@ -72,11 +69,12 @@ static void cmp_node_switch_view_update(bNodeTree *ntree, bNode *node)
}
/* remove the views that were removed */
- sock = node->inputs.last;
+ bNodeSocket *sock = (bNodeSocket *)node->inputs.last;
while (sock) {
- srv = BLI_findstring(&scene->r.views, sock->name, offsetof(SceneRenderView, name));
+ SceneRenderView *srv = (SceneRenderView *)BLI_findstring(
+ &scene->r.views, sock->name, offsetof(SceneRenderView, name));
- if (srv == NULL) {
+ if (srv == nullptr) {
bNodeSocket *sock_del = sock;
sock = sock->prev;
nodeRemoveSocket(ntree, node, sock_del);
@@ -94,10 +92,10 @@ static void cmp_node_switch_view_update(bNodeTree *ntree, bNode *node)
}
/* add the new views */
- for (srv = scene->r.views.first; srv; srv = srv->next) {
- sock = BLI_findstring(&node->inputs, srv->name, offsetof(bNodeSocket, name));
+ LISTBASE_FOREACH (SceneRenderView *, srv, &scene->r.views) {
+ sock = (bNodeSocket *)BLI_findstring(&node->inputs, srv->name, offsetof(bNodeSocket, name));
- if (sock == NULL) {
+ if (sock == nullptr) {
sock = ntreeCompositSwitchViewAddSocket(ntree, node, srv->name);
}
@@ -117,10 +115,7 @@ static void init_switch_view(const bContext *C, PointerRNA *ptr)
{
Scene *scene = CTX_data_scene(C);
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNode *node = ptr->data;
- SceneRenderView *srv;
- bNodeSocket *sock;
- int nr;
+ bNode *node = (bNode *)ptr->data;
/* store scene for updates */
node->id = (ID *)scene;
@@ -129,8 +124,8 @@ static void init_switch_view(const bContext *C, PointerRNA *ptr)
if (scene) {
RenderData *rd = &scene->r;
- for (nr = 0, srv = rd->views.first; srv; srv = srv->next, nr++) {
- sock = ntreeCompositSwitchViewAddSocket(ntree, node, srv->name);
+ LISTBASE_FOREACH (SceneRenderView *, srv, &rd->views) {
+ bNodeSocket *sock = ntreeCompositSwitchViewAddSocket(ntree, node, srv->name);
if (srv->viewflag & SCE_VIEW_DISABLE) {
sock->flag |= SOCK_HIDDEN;
@@ -147,7 +142,7 @@ void register_node_type_cmp_switch_view(void)
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_SWITCH_VIEW, "Switch View", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, NULL, cmp_node_switch_view_out);
+ node_type_socket_templates(&ntype, nullptr, cmp_node_switch_view_out);
ntype.initfunc_api = init_switch_view;
diff --git a/source/blender/nodes/composite/nodes/node_composite_texture.c b/source/blender/nodes/composite/nodes/node_composite_texture.cc
index 50be05fe5a6..eff008b4b41 100644
--- a/source/blender/nodes/composite/nodes/node_composite_texture.c
+++ b/source/blender/nodes/composite/nodes/node_composite_texture.cc
@@ -21,26 +21,32 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** TEXTURE ******************** */
-static bNodeSocketTemplate cmp_node_texture_in[] = {
- {SOCK_VECTOR, N_("Offset"), 0.0f, 0.0f, 0.0f, 0.0f, -2.0f, 2.0f, PROP_TRANSLATION},
- {SOCK_VECTOR, N_("Scale"), 1.0f, 1.0f, 1.0f, 1.0f, -10.0f, 10.0f, PROP_XYZ},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_texture_out[] = {
- {SOCK_FLOAT, N_("Value")},
- {SOCK_RGBA, N_("Color")},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_texture_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Vector>("Offset").min(-2.0f).max(2.0f).subtype(PROP_TRANSLATION);
+ b.add_input<decl::Vector>("Scale")
+ .default_value({1.0f, 1.0f, 1.0f})
+ .min(-10.0f)
+ .max(10.0f)
+ .subtype(PROP_XYZ);
+ b.add_output<decl::Float>("Value");
+ b.add_output<decl::Color>("Color");
+}
+
+} // namespace blender::nodes
void register_node_type_cmp_texture(void)
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_TEXTURE, "Texture", NODE_CLASS_INPUT, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_texture_in, cmp_node_texture_out);
+ ntype.declare = blender::nodes::cmp_node_texture_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_tonemap.c b/source/blender/nodes/composite/nodes/node_composite_tonemap.cc
index 5fc86c997f5..85fd240ce2e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_tonemap.c
+++ b/source/blender/nodes/composite/nodes/node_composite_tonemap.cc
@@ -21,20 +21,21 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
-static bNodeSocketTemplate cmp_node_tonemap_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_tonemap_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_tonemap_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>("Image");
+}
+
+} // namespace blender::nodes
static void node_composit_init_tonemap(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTonemap *ntm = MEM_callocN(sizeof(NodeTonemap), "node tonemap data");
+ NodeTonemap *ntm = (NodeTonemap *)MEM_callocN(sizeof(NodeTonemap), "node tonemap data");
ntm->type = 1;
ntm->key = 0.18;
ntm->offset = 1;
@@ -53,7 +54,7 @@ void register_node_type_cmp_tonemap(void)
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_TONEMAP, "Tonemap", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, cmp_node_tonemap_in, cmp_node_tonemap_out);
+ ntype.declare = blender::nodes::cmp_node_tonemap_declare;
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.c b/source/blender/nodes/composite/nodes/node_composite_trackpos.cc
index d59ce9b8b7a..cb5c9468daa 100644
--- a/source/blender/nodes/composite/nodes/node_composite_trackpos.c
+++ b/source/blender/nodes/composite/nodes/node_composite_trackpos.cc
@@ -21,18 +21,23 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
-static bNodeSocketTemplate cmp_node_trackpos_out[] = {
- {SOCK_FLOAT, N_("X")},
- {SOCK_FLOAT, N_("Y")},
- {SOCK_VECTOR, N_("Speed"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_VELOCITY},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_trackpos_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Float>("X");
+ b.add_output<decl::Float>("Y");
+ b.add_output<decl::Vector>("Speed").subtype(PROP_VELOCITY);
+}
+
+} // namespace blender::nodes
static void init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTrackPosData *data = MEM_callocN(sizeof(NodeTrackPosData), "node track position data");
+ NodeTrackPosData *data = (NodeTrackPosData *)MEM_callocN(sizeof(NodeTrackPosData),
+ "node track position data");
node->storage = data;
}
@@ -42,7 +47,7 @@ void register_node_type_cmp_trackpos(void)
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_TRACKPOS, "Track Position", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, cmp_node_trackpos_out);
+ ntype.declare = blender::nodes::cmp_node_trackpos_declare;
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.c b/source/blender/nodes/composite/nodes/node_composite_transform.cc
index be526c1059c..1695101cdbf 100644
--- a/source/blender/nodes/composite/nodes/node_composite_transform.c
+++ b/source/blender/nodes/composite/nodes/node_composite_transform.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** Transform ******************** */
diff --git a/source/blender/nodes/composite/nodes/node_composite_translate.c b/source/blender/nodes/composite/nodes/node_composite_translate.cc
index 43337ec6f7e..0ee8a41a5ea 100644
--- a/source/blender/nodes/composite/nodes/node_composite_translate.c
+++ b/source/blender/nodes/composite/nodes/node_composite_translate.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** Translate ******************** */
@@ -38,7 +38,8 @@ static bNodeSocketTemplate cmp_node_translate_out[] = {
static void node_composit_init_translate(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTranslateData *data = MEM_callocN(sizeof(NodeTranslateData), "node translate data");
+ NodeTranslateData *data = (NodeTranslateData *)MEM_callocN(sizeof(NodeTranslateData),
+ "node translate data");
node->storage = data;
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_valToRgb.c b/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc
index ed6dbfa2bf3..ba98ee12f30 100644
--- a/source/blender/nodes/composite/nodes/node_composite_valToRgb.c
+++ b/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc
@@ -21,18 +21,20 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** VALTORGB ******************** */
-static bNodeSocketTemplate cmp_node_valtorgb_in[] = {
- {SOCK_FLOAT, N_("Fac"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_valtorgb_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Alpha")},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_valtorgb_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>("Fac").default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_output<decl::Color>("Image");
+ b.add_output<decl::Color>("Alpha");
+}
+
+} // namespace blender::nodes
static void node_composit_init_valtorgb(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -44,7 +46,7 @@ void register_node_type_cmp_valtorgb(void)
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_valtorgb_in, cmp_node_valtorgb_out);
+ ntype.declare = blender::nodes::cmp_node_valtorgb_declare;
node_type_size(&ntype, 240, 200, 320);
node_type_init(&ntype, node_composit_init_valtorgb);
node_type_storage(&ntype, "ColorBand", node_free_standard_storage, node_copy_standard_storage);
@@ -53,21 +55,23 @@ void register_node_type_cmp_valtorgb(void)
}
/* **************** RGBTOBW ******************** */
-static bNodeSocketTemplate cmp_node_rgbtobw_in[] = {
- {SOCK_RGBA, N_("Image"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_rgbtobw_out[] = {
- {SOCK_FLOAT, N_("Val"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_rgbtobw_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>("Image").default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_output<decl::Color>("Val");
+}
+
+} // namespace blender::nodes
void register_node_type_cmp_rgbtobw(void)
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_rgbtobw_in, cmp_node_rgbtobw_out);
+ ntype.declare = blender::nodes::cmp_node_rgbtobw_declare;
node_type_size_preset(&ntype, NODE_SIZE_SMALL);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_value.c b/source/blender/nodes/composite/nodes/node_composite_value.cc
index 2ede2cb8c83..5459801bcc7 100644
--- a/source/blender/nodes/composite/nodes/node_composite_value.c
+++ b/source/blender/nodes/composite/nodes/node_composite_value.cc
@@ -21,20 +21,25 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** VALUE ******************** */
-static bNodeSocketTemplate cmp_node_value_out[] = {
- {SOCK_FLOAT, N_("Value"), 0.5f, 0, 0, 0, -FLT_MAX, FLT_MAX, PROP_NONE},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_value_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Float>("Value").default_value(0.5f);
+}
+
+} // namespace blender::nodes
void register_node_type_cmp_value(void)
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_VALUE, "Value", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, cmp_node_value_out);
+ ntype.declare = blender::nodes::cmp_node_value_declare;
node_type_size_preset(&ntype, NODE_SIZE_SMALL);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_vecBlur.c b/source/blender/nodes/composite/nodes/node_composite_vecBlur.cc
index 7005ea42afe..ce6ba659609 100644
--- a/source/blender/nodes/composite/nodes/node_composite_vecBlur.c
+++ b/source/blender/nodes/composite/nodes/node_composite_vecBlur.cc
@@ -21,7 +21,7 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
/* **************** VECTOR BLUR ******************** */
static bNodeSocketTemplate cmp_node_vecblur_in[] = {
@@ -33,13 +33,13 @@ static bNodeSocketTemplate cmp_node_vecblur_out[] = {{SOCK_RGBA, N_("Image")}, {
static void node_composit_init_vecblur(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeBlurData *nbd = MEM_callocN(sizeof(NodeBlurData), "node blur data");
+ NodeBlurData *nbd = (NodeBlurData *)MEM_callocN(sizeof(NodeBlurData), "node blur data");
node->storage = nbd;
nbd->samples = 32;
nbd->fac = 1.0f;
}
-/* custom1: iterations, custom2: maxspeed (0 = nolimit) */
+/* custom1: iterations, custom2: max_speed (0 = no_limit). */
void register_node_type_cmp_vecblur(void)
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_viewer.c b/source/blender/nodes/composite/nodes/node_composite_viewer.cc
index b5f74d5c937..7234d4d8eb2 100644
--- a/source/blender/nodes/composite/nodes/node_composite_viewer.c
+++ b/source/blender/nodes/composite/nodes/node_composite_viewer.cc
@@ -21,21 +21,27 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.h"
+#include "node_composite_util.hh"
#include "BKE_global.h"
#include "BKE_image.h"
/* **************** VIEWER ******************** */
-static bNodeSocketTemplate cmp_node_viewer_in[] = {
- {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Alpha"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Z"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""}};
+
+namespace blender::nodes {
+
+static void cmp_node_viewer_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>("Image").default_value({0.0f, 0.0f, 0.0f, 1.0f});
+ b.add_input<decl::Float>("Alpha").default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>("Z").default_value(1.0f).min(0.0f).max(1.0f);
+}
+
+} // namespace blender::nodes
static void node_composit_init_viewer(bNodeTree *UNUSED(ntree), bNode *node)
{
- ImageUser *iuser = MEM_callocN(sizeof(ImageUser), "node image user");
+ ImageUser *iuser = (ImageUser *)MEM_callocN(sizeof(ImageUser), "node image user");
node->storage = iuser;
iuser->sfra = 1;
iuser->ok = 1;
@@ -50,11 +56,11 @@ void register_node_type_cmp_viewer(void)
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_viewer_in, NULL);
+ ntype.declare = blender::nodes::cmp_node_viewer_declare;
node_type_init(&ntype, node_composit_init_viewer);
node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage);
- node_type_internal_links(&ntype, NULL);
+ node_type_internal_links(&ntype, nullptr);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_zcombine.c b/source/blender/nodes/composite/nodes/node_composite_zcombine.cc
index 5041b16c303..79e4d449159 100644
--- a/source/blender/nodes/composite/nodes/node_composite_zcombine.c
+++ b/source/blender/nodes/composite/nodes/node_composite_zcombine.cc
@@ -21,29 +21,31 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.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, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_zcombine_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>("Z").default_value(1.0f).min(0.0f).max(10000.0f);
+ b.add_input<decl::Color>("Image", "Image_001").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>("Z", "Z_001").default_value(1.0f).min(0.0f).max(10000.0f);
+ b.add_output<decl::Color>("Image");
+ b.add_output<decl::Float>("Z");
+}
+
+} // namespace blender::nodes
+
+/* lazy coder NOTE: node->custom2 is abused to send signal. */
void register_node_type_cmp_zcombine(void)
{
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;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_random_float.cc b/source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc
index 1bd39aacdca..7f6f554ba93 100644
--- a/source/blender/nodes/function/nodes/node_fn_random_float.cc
+++ b/source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc
@@ -20,8 +20,9 @@
namespace blender::nodes {
-static void fn_node_random_float_declare(NodeDeclarationBuilder &b)
+static void fn_node_legacy_random_float_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::Float>("Min").min(-10000.0f).max(10000.0f);
b.add_input<decl::Float>("Max").default_value(1.0f).min(-10000.0f).max(10000.0f);
b.add_input<decl::Int>("Seed").min(-10000).max(10000);
@@ -67,19 +68,19 @@ class RandomFloatFunction : public blender::fn::MultiFunction {
}
};
-static void fn_node_random_float_build_multi_function(
+static void fn_node_legacy_random_float_build_multi_function(
blender::nodes::NodeMultiFunctionBuilder &builder)
{
static RandomFloatFunction fn;
builder.set_matching_fn(fn);
}
-void register_node_type_fn_random_float()
+void register_node_type_fn_legacy_random_float()
{
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_RANDOM_FLOAT, "Random Float", 0, 0);
- ntype.declare = blender::nodes::fn_node_random_float_declare;
- ntype.build_multi_function = fn_node_random_float_build_multi_function;
+ fn_node_type_base(&ntype, FN_NODE_LEGACY_RANDOM_FLOAT, "Random Float", 0, 0);
+ ntype.declare = blender::nodes::fn_node_legacy_random_float_declare;
+ ntype.build_multi_function = fn_node_legacy_random_float_build_multi_function;
nodeRegisterType(&ntype);
}
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 b71ee092de6..d10490bb2ee 100644
--- a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
+++ b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
@@ -28,6 +28,7 @@ namespace blender::nodes {
static void fn_node_boolean_math_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::Bool>("Boolean", "Boolean");
b.add_input<decl::Bool>("Boolean", "Boolean_001");
b.add_output<decl::Bool>("Boolean");
diff --git a/source/blender/nodes/function/nodes/node_fn_float_compare.cc b/source/blender/nodes/function/nodes/node_fn_float_compare.cc
index 4f4830afabc..9736c52e895 100644
--- a/source/blender/nodes/function/nodes/node_fn_float_compare.cc
+++ b/source/blender/nodes/function/nodes/node_fn_float_compare.cc
@@ -30,6 +30,7 @@ namespace blender::nodes {
static void fn_node_float_compare_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::Float>("A").min(-10000.0f).max(10000.0f);
b.add_input<decl::Float>("B").min(-10000.0f).max(10000.0f);
b.add_input<decl::Float>("Epsilon").default_value(0.001f).min(-10000.0f).max(10000.0f);
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 e59c78d2c04..8bb5dafff8a 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
@@ -29,6 +29,7 @@ namespace blender::nodes {
static void fn_node_float_to_int_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::Float>("Float");
b.add_output<decl::Int>("Integer");
};
diff --git a/source/blender/nodes/function/nodes/node_fn_input_special_characters.cc b/source/blender/nodes/function/nodes/node_fn_input_special_characters.cc
new file mode 100644
index 00000000000..11c64d3f694
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_input_special_characters.cc
@@ -0,0 +1,74 @@
+/*
+ * 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_function_util.hh"
+
+namespace blender::nodes {
+
+static void fn_node_input_special_characters_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::String>("Line Break");
+ b.add_output<decl::String>("Tab");
+};
+
+class MF_SpecialCharacters : public fn::MultiFunction {
+ public:
+ MF_SpecialCharacters()
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"Special Characters"};
+ signature.single_output<std::string>("Line Break");
+ signature.single_output<std::string>("Tab");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ MutableSpan<std::string> lb = params.uninitialized_single_output<std::string>(0, "Line Break");
+ MutableSpan<std::string> tab = params.uninitialized_single_output<std::string>(1, "Tab");
+
+ for (const int i : mask) {
+ new (&lb[i]) std::string("\n");
+ new (&tab[i]) std::string("\t");
+ }
+ }
+};
+
+static void fn_node_input_special_characters_build_multi_function(
+ NodeMultiFunctionBuilder &builder)
+{
+ static MF_SpecialCharacters special_characters_fn;
+ builder.set_matching_fn(special_characters_fn);
+}
+
+} // namespace blender::nodes
+
+void register_node_type_fn_input_special_characters()
+{
+ static bNodeType ntype;
+
+ fn_node_type_base(
+ &ntype, FN_NODE_INPUT_SPECIAL_CHARACTERS, "Special Characters", NODE_CLASS_INPUT, 0);
+ ntype.declare = blender::nodes::fn_node_input_special_characters_declare;
+ ntype.build_multi_function =
+ blender::nodes::fn_node_input_special_characters_build_multi_function;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/function/nodes/node_fn_input_string.cc b/source/blender/nodes/function/nodes/node_fn_input_string.cc
index 4a8e898fb9b..704ae9d900c 100644
--- a/source/blender/nodes/function/nodes/node_fn_input_string.cc
+++ b/source/blender/nodes/function/nodes/node_fn_input_string.cc
@@ -23,6 +23,7 @@ namespace blender::nodes {
static void fn_node_input_string_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_output<decl::String>("String");
};
diff --git a/source/blender/nodes/function/nodes/node_fn_random_value.cc b/source/blender/nodes/function/nodes/node_fn_random_value.cc
new file mode 100644
index 00000000000..53ca77aab0c
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_random_value.cc
@@ -0,0 +1,299 @@
+/*
+ * 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_hash.h"
+#include "BLI_noise.hh"
+
+#include "node_function_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes {
+
+static void fn_node_random_value_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Vector>("Min").supports_field();
+ b.add_input<decl::Vector>("Max").default_value({1.0f, 1.0f, 1.0f}).supports_field();
+ b.add_input<decl::Float>("Min", "Min_001").supports_field();
+ b.add_input<decl::Float>("Max", "Max_001").default_value(1.0f).supports_field();
+ b.add_input<decl::Int>("Min", "Min_002").min(-100000).max(100000).supports_field();
+ b.add_input<decl::Int>("Max", "Max_002")
+ .default_value(100)
+ .min(-100000)
+ .max(100000)
+ .supports_field();
+ b.add_input<decl::Float>("Probability")
+ .min(0.0f)
+ .max(1.0f)
+ .default_value(0.5f)
+ .subtype(PROP_FACTOR)
+ .supports_field();
+ b.add_input<decl::Int>("ID").implicit_field();
+ b.add_input<decl::Int>("Seed").default_value(0).min(-10000).max(10000).supports_field();
+
+ b.add_output<decl::Vector>("Value").dependent_field();
+ b.add_output<decl::Float>("Value", "Value_001").dependent_field();
+ b.add_output<decl::Int>("Value", "Value_002").dependent_field();
+ b.add_output<decl::Bool>("Value", "Value_003").dependent_field();
+}
+
+static void fn_node_random_value_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
+}
+
+static void fn_node_random_value_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeRandomValue *data = (NodeRandomValue *)MEM_callocN(sizeof(NodeRandomValue), __func__);
+ data->data_type = CD_PROP_FLOAT;
+ node->storage = data;
+}
+
+static void fn_node_random_value_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ const NodeRandomValue &storage = *(const NodeRandomValue *)node->storage;
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+
+ bNodeSocket *sock_min_vector = (bNodeSocket *)node->inputs.first;
+ bNodeSocket *sock_max_vector = sock_min_vector->next;
+ bNodeSocket *sock_min_float = sock_max_vector->next;
+ bNodeSocket *sock_max_float = sock_min_float->next;
+ bNodeSocket *sock_min_int = sock_max_float->next;
+ bNodeSocket *sock_max_int = sock_min_int->next;
+ bNodeSocket *sock_probability = sock_max_int->next;
+
+ bNodeSocket *sock_out_vector = (bNodeSocket *)node->outputs.first;
+ bNodeSocket *sock_out_float = sock_out_vector->next;
+ bNodeSocket *sock_out_int = sock_out_float->next;
+ bNodeSocket *sock_out_bool = sock_out_int->next;
+
+ nodeSetSocketAvailability(sock_min_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(sock_max_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(sock_min_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(sock_max_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(sock_min_int, data_type == CD_PROP_INT32);
+ nodeSetSocketAvailability(sock_max_int, data_type == CD_PROP_INT32);
+ nodeSetSocketAvailability(sock_probability, data_type == CD_PROP_BOOL);
+
+ nodeSetSocketAvailability(sock_out_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(sock_out_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(sock_out_int, data_type == CD_PROP_INT32);
+ nodeSetSocketAvailability(sock_out_bool, data_type == CD_PROP_BOOL);
+}
+
+class RandomVectorFunction : public fn::MultiFunction {
+ public:
+ RandomVectorFunction()
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"Random Value"};
+ signature.single_input<float3>("Min");
+ signature.single_input<float3>("Max");
+ signature.single_input<int>("ID");
+ signature.single_input<int>("Seed");
+ signature.single_output<float3>("Value");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<float3> &min_values = params.readonly_single_input<float3>(0, "Min");
+ const VArray<float3> &max_values = params.readonly_single_input<float3>(1, "Max");
+ const VArray<int> &ids = params.readonly_single_input<int>(2, "ID");
+ const VArray<int> &seeds = params.readonly_single_input<int>(3, "Seed");
+ MutableSpan<float3> values = params.uninitialized_single_output<float3>(4, "Value");
+
+ for (int64_t i : mask) {
+ const float3 min_value = min_values[i];
+ const float3 max_value = max_values[i];
+ const int seed = seeds[i];
+ const int id = ids[i];
+
+ const float x = noise::hash_to_float(seed, id, 0);
+ const float y = noise::hash_to_float(seed, id, 1);
+ const float z = noise::hash_to_float(seed, id, 2);
+
+ values[i] = float3(x, y, z) * (max_value - min_value) + min_value;
+ }
+ }
+};
+
+class RandomFloatFunction : public fn::MultiFunction {
+ public:
+ RandomFloatFunction()
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"Random Value"};
+ signature.single_input<float>("Min");
+ signature.single_input<float>("Max");
+ signature.single_input<int>("ID");
+ signature.single_input<int>("Seed");
+ signature.single_output<float>("Value");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<float> &min_values = params.readonly_single_input<float>(0, "Min");
+ const VArray<float> &max_values = params.readonly_single_input<float>(1, "Max");
+ const VArray<int> &ids = params.readonly_single_input<int>(2, "ID");
+ const VArray<int> &seeds = params.readonly_single_input<int>(3, "Seed");
+ MutableSpan<float> values = params.uninitialized_single_output<float>(4, "Value");
+
+ for (int64_t i : mask) {
+ const float min_value = min_values[i];
+ const float max_value = max_values[i];
+ const int seed = seeds[i];
+ const int id = ids[i];
+
+ const float value = noise::hash_to_float(seed, id);
+ values[i] = value * (max_value - min_value) + min_value;
+ }
+ }
+};
+
+class RandomIntFunction : public fn::MultiFunction {
+ public:
+ RandomIntFunction()
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"Random Value"};
+ signature.single_input<int>("Min");
+ signature.single_input<int>("Max");
+ signature.single_input<int>("ID");
+ signature.single_input<int>("Seed");
+ signature.single_output<int>("Value");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<int> &min_values = params.readonly_single_input<int>(0, "Min");
+ const VArray<int> &max_values = params.readonly_single_input<int>(1, "Max");
+ const VArray<int> &ids = params.readonly_single_input<int>(2, "ID");
+ const VArray<int> &seeds = params.readonly_single_input<int>(3, "Seed");
+ MutableSpan<int> values = params.uninitialized_single_output<int>(4, "Value");
+
+ for (int64_t i : mask) {
+ const float min_value = min_values[i];
+ const float max_value = max_values[i];
+ 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);
+ }
+ }
+};
+
+class RandomBoolFunction : public fn::MultiFunction {
+ public:
+ RandomBoolFunction()
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"Random Value"};
+ signature.single_input<float>("Probability");
+ signature.single_input<int>("ID");
+ signature.single_input<int>("Seed");
+ signature.single_output<bool>("Value");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<float> &probabilities = params.readonly_single_input<float>(0, "Probability");
+ const VArray<int> &ids = params.readonly_single_input<int>(1, "ID");
+ const VArray<int> &seeds = params.readonly_single_input<int>(2, "Seed");
+ MutableSpan<bool> values = params.uninitialized_single_output<bool>(3, "Value");
+
+ for (int64_t i : mask) {
+ const int seed = seeds[i];
+ const int id = ids[i];
+ const float probability = probabilities[i];
+ values[i] = noise::hash_to_float(id, seed) <= probability;
+ }
+ }
+};
+
+static void fn_node_random_value_build_multi_function(NodeMultiFunctionBuilder &builder)
+{
+ const NodeRandomValue &storage = *(const NodeRandomValue *)builder.node().storage;
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+
+ switch (data_type) {
+ case CD_PROP_FLOAT3: {
+ static RandomVectorFunction fn;
+ builder.set_matching_fn(fn);
+ break;
+ }
+ case CD_PROP_FLOAT: {
+ static RandomFloatFunction fn;
+ builder.set_matching_fn(fn);
+ break;
+ }
+ case CD_PROP_INT32: {
+ static RandomIntFunction fn;
+ builder.set_matching_fn(fn);
+ break;
+ }
+ case CD_PROP_BOOL: {
+ static RandomBoolFunction fn;
+ builder.set_matching_fn(fn);
+ break;
+ }
+ default: {
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+}
+
+} // namespace blender::nodes
+
+void register_node_type_fn_random_value()
+{
+ static bNodeType ntype;
+ fn_node_type_base(&ntype, FN_NODE_RANDOM_VALUE, "Random Value", NODE_CLASS_CONVERTER, 0);
+ node_type_init(&ntype, blender::nodes::fn_node_random_value_init);
+ node_type_update(&ntype, blender::nodes::fn_node_random_value_update);
+ 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;
+ node_type_storage(
+ &ntype, "NodeRandomValue", node_free_standard_storage, node_copy_standard_storage);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc
new file mode 100644
index 00000000000..cbae1648663
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc
@@ -0,0 +1,138 @@
+/*
+ * 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_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_rotate_euler_declare(NodeDeclarationBuilder &b)
+{
+ b.is_function_node();
+ b.add_input<decl::Vector>("Rotation").subtype(PROP_EULER).hide_value();
+ b.add_input<decl::Vector>("Rotate By").subtype(PROP_EULER);
+ b.add_input<decl::Vector>("Axis").default_value({0.0, 0.0, 1.0}).subtype(PROP_XYZ);
+ b.add_input<decl::Float>("Angle").subtype(PROP_ANGLE);
+ b.add_output<decl::Vector>("Rotation");
+};
+
+static void fn_node_rotate_euler_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *rotate_by_socket = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 1));
+ bNodeSocket *axis_socket = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 2));
+ bNodeSocket *angle_socket = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 3));
+
+ nodeSetSocketAvailability(rotate_by_socket,
+ ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_EULER));
+ nodeSetSocketAvailability(axis_socket,
+ ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE));
+ nodeSetSocketAvailability(angle_socket,
+ ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE));
+}
+
+static void fn_node_rotate_euler_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "type", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "space", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+}
+
+static const fn::MultiFunction *get_multi_function(bNode &bnode)
+{
+ static fn::CustomMF_SI_SI_SO<float3, float3, float3> obj_euler_rot{
+ "Rotate Euler by Euler/Object", [](const float3 &input, const float3 &rotation) {
+ float input_mat[3][3];
+ eul_to_mat3(input_mat, input);
+ float rot_mat[3][3];
+ eul_to_mat3(rot_mat, rotation);
+ float mat_res[3][3];
+ mul_m3_m3m3(mat_res, rot_mat, input_mat);
+ float3 result;
+ mat3_to_eul(result, mat_res);
+ return result;
+ }};
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> obj_AA_rot{
+ "Rotate Euler by AxisAngle/Object",
+ [](const float3 &input, const float3 &axis, float angle) {
+ float input_mat[3][3];
+ eul_to_mat3(input_mat, input);
+ float rot_mat[3][3];
+ axis_angle_to_mat3(rot_mat, axis, angle);
+ float mat_res[3][3];
+ mul_m3_m3m3(mat_res, rot_mat, input_mat);
+ float3 result;
+ mat3_to_eul(result, mat_res);
+ return result;
+ }};
+ static fn::CustomMF_SI_SI_SO<float3, float3, float3> point_euler_rot{
+ "Rotate Euler by Euler/Point", [](const float3 &input, const float3 &rotation) {
+ float input_mat[3][3];
+ eul_to_mat3(input_mat, input);
+ float rot_mat[3][3];
+ eul_to_mat3(rot_mat, rotation);
+ float mat_res[3][3];
+ mul_m3_m3m3(mat_res, input_mat, rot_mat);
+ float3 result;
+ mat3_to_eul(result, mat_res);
+ return result;
+ }};
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> point_AA_rot{
+ "Rotate Euler by AxisAngle/Point", [](const float3 &input, const float3 &axis, float angle) {
+ float input_mat[3][3];
+ eul_to_mat3(input_mat, input);
+ float rot_mat[3][3];
+ axis_angle_to_mat3(rot_mat, axis, angle);
+ float mat_res[3][3];
+ mul_m3_m3m3(mat_res, input_mat, rot_mat);
+ float3 result;
+ mat3_to_eul(result, mat_res);
+ return result;
+ }};
+ short type = bnode.custom1;
+ short space = bnode.custom2;
+ if (type == FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE) {
+ return space == FN_NODE_ROTATE_EULER_SPACE_OBJECT ? &obj_AA_rot : &point_AA_rot;
+ }
+ if (type == FN_NODE_ROTATE_EULER_TYPE_EULER) {
+ return space == FN_NODE_ROTATE_EULER_SPACE_OBJECT ? &obj_euler_rot : &point_euler_rot;
+ }
+ BLI_assert_unreachable();
+ return nullptr;
+}
+
+static void fn_node_rotate_euler_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_rotate_euler()
+{
+ static bNodeType ntype;
+ fn_node_type_base(&ntype, FN_NODE_ROTATE_EULER, "Rotate Euler", NODE_CLASS_CONVERTER, 0);
+ ntype.declare = blender::nodes::fn_node_rotate_euler_declare;
+ ntype.draw_buttons = blender::nodes::fn_node_rotate_euler_layout;
+ node_type_update(&ntype, blender::nodes::fn_node_rotate_euler_update);
+ ntype.build_multi_function = blender::nodes::fn_node_rotate_euler_build_multi_function;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/function/nodes/node_fn_string_length.cc b/source/blender/nodes/function/nodes/node_fn_string_length.cc
index a0f85dfd2bf..89038629c3c 100644
--- a/source/blender/nodes/function/nodes/node_fn_string_length.cc
+++ b/source/blender/nodes/function/nodes/node_fn_string_length.cc
@@ -24,6 +24,7 @@ namespace blender::nodes {
static void fn_node_string_length_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::String>("String");
b.add_output<decl::Int>("Length");
};
diff --git a/source/blender/nodes/function/nodes/node_fn_string_substring.cc b/source/blender/nodes/function/nodes/node_fn_string_substring.cc
index 55a01093ae9..b91171923d6 100644
--- a/source/blender/nodes/function/nodes/node_fn_string_substring.cc
+++ b/source/blender/nodes/function/nodes/node_fn_string_substring.cc
@@ -22,6 +22,7 @@ namespace blender::nodes {
static void fn_node_string_substring_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::String>("String");
b.add_input<decl::Int>("Position");
b.add_input<decl::Int>("Length").min(0);
diff --git a/source/blender/nodes/function/nodes/node_fn_value_to_string.cc b/source/blender/nodes/function/nodes/node_fn_value_to_string.cc
index c1e6373cb6d..56206af2eb2 100644
--- a/source/blender/nodes/function/nodes/node_fn_value_to_string.cc
+++ b/source/blender/nodes/function/nodes/node_fn_value_to_string.cc
@@ -21,6 +21,7 @@ namespace blender::nodes {
static void fn_node_value_to_string_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::Float>("Value");
b.add_input<decl::Int>("Decimals").min(0);
b.add_output<decl::String>("String");
diff --git a/source/blender/nodes/geometry/node_geometry_tree.cc b/source/blender/nodes/geometry/node_geometry_tree.cc
index d6b23c38ee4..20b610a4db9 100644
--- a/source/blender/nodes/geometry/node_geometry_tree.cc
+++ b/source/blender/nodes/geometry/node_geometry_tree.cc
@@ -119,7 +119,7 @@ void register_node_tree_type_geo(void)
tt->type = NTREE_GEOMETRY;
strcpy(tt->idname, "GeometryNodeTree");
strcpy(tt->ui_name, N_("Geometry Node Editor"));
- tt->ui_icon = 0; /* defined in drawnode.c */
+ tt->ui_icon = 0; /* Defined in `drawnode.c`. */
strcpy(tt->ui_description, N_("Geometry nodes"));
tt->rna_ext.srna = &RNA_GeometryNodeTree;
tt->update = geometry_node_tree_update;
diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh
index 015ac0de002..5896b5bd6cc 100644
--- a/source/blender/nodes/geometry/node_geometry_util.hh
+++ b/source/blender/nodes/geometry/node_geometry_util.hh
@@ -65,7 +65,9 @@ Mesh *create_grid_mesh(const int verts_x,
Mesh *create_cylinder_or_cone_mesh(const float radius_top,
const float radius_bottom,
const float depth,
- const int verts_num,
+ const int circle_segments,
+ const int side_segments,
+ const int fill_segments,
const GeometryNodeMeshCircleFillType fill_type);
Mesh *create_cuboid_mesh(float3 size, int verts_x, int verts_y, int verts_z);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc
index d0bb906e8af..d0bb906e8af 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_clamp.cc
index 97070184609..2e931a2da98 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_clamp.cc
@@ -269,7 +269,7 @@ void register_node_type_geo_attribute_clamp()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LECAGY_ATTRIBUTE_CLAMP, "Attribute Clamp", NODE_CLASS_ATTRIBUTE, 0);
+ &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;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_color_ramp.cc
index aa054af3acd..aa054af3acd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_color_ramp.cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc
index 569d5a824ca..569d5a824ca 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_compare.cc
index 0b9708dae14..0b9708dae14 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_compare.cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_convert.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_convert.cc
index a2382aa9d25..a2382aa9d25 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_convert.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_convert.cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_curve_map.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_curve_map.cc
index b9621b4ae92..b9621b4ae92 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_curve_map.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_curve_map.cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_fill.cc
index 3c50ae5c837..3c50ae5c837 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_fill.cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_map_range.cc
index 0ea3bbe1e45..0ea3bbe1e45 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_map_range.cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_math.cc
index efa09215b45..efa09215b45 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_math.cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_mix.cc
index 74e05cb997d..74e05cb997d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_mix.cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_proximity.cc
index 0cf411343cf..6120118f611 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_proximity.cc
@@ -232,7 +232,7 @@ static void geo_node_attribute_proximity_exec(GeoNodeExecParams params)
} // namespace blender::nodes
-void register_node_type_geo_attribute_proximity()
+void register_node_type_geo_legacy_attribute_proximity()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_randomize.cc
index 60b9910399c..2e6ba456725 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_randomize.cc
@@ -25,7 +25,7 @@
namespace blender::nodes {
-static void geo_node_attribute_randomize_declare(NodeDeclarationBuilder &b)
+static void geo_node_legacy_attribute_randomize_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::String>("Attribute");
@@ -39,15 +39,15 @@ static void geo_node_attribute_randomize_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>("Geometry");
}
-static void geo_node_attribute_random_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void geo_node_legacy_attribute_random_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_randomize_init(bNodeTree *UNUSED(tree), bNode *node)
+static void geo_node_legacy_attribute_randomize_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeAttributeRandomize *data = (NodeAttributeRandomize *)MEM_callocN(
sizeof(NodeAttributeRandomize), __func__);
@@ -57,7 +57,7 @@ static void geo_node_attribute_randomize_init(bNodeTree *UNUSED(tree), bNode *no
node->storage = data;
}
-static void geo_node_attribute_randomize_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void geo_node_legacy_attribute_randomize_update(bNodeTree *UNUSED(ntree), bNode *node)
{
bNodeSocket *sock_min_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 2);
bNodeSocket *sock_max_vector = sock_min_vector->next;
@@ -280,7 +280,7 @@ static void randomize_attribute_on_component(GeometryComponent &component,
attribute.save();
}
-static void geo_node_random_attribute_exec(GeoNodeExecParams params)
+static void geo_node_legacy_random_attribute_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
const std::string attribute_name = params.get_input<std::string>("Attribute");
@@ -326,18 +326,18 @@ static void geo_node_random_attribute_exec(GeoNodeExecParams params)
} // namespace blender::nodes
-void register_node_type_geo_attribute_randomize()
+void register_node_type_geo_legacy_attribute_randomize()
{
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_attribute_randomize_init);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_randomize_update);
+ node_type_init(&ntype, blender::nodes::geo_node_legacy_attribute_randomize_init);
+ node_type_update(&ntype, blender::nodes::geo_node_legacy_attribute_randomize_update);
- ntype.declare = blender::nodes::geo_node_attribute_randomize_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_random_attribute_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_random_layout;
+ 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;
node_type_storage(
&ntype, "NodeAttributeRandomize", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_sample_texture.cc
index 52f97475941..52f97475941 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_sample_texture.cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc
index de0090406c6..de0090406c6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_transfer.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_transfer.cc
index 874350cd714..f187ee39b94 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_transfer.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_transfer.cc
@@ -404,7 +404,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]) {
- /* Pointcloud 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);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_math.cc
index 59903050f88..59903050f88 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_math.cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_rotate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc
index adaa4de3029..0c515fa63fb 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_rotate.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc
@@ -332,7 +332,7 @@ void register_node_type_geo_attribute_vector_rotate()
static bNodeType ntype;
geo_node_type_base(&ntype,
- GEO_NODE_ATTRIBUTE_VECTOR_ROTATE,
+ GEO_NODE_LEGACY_ATTRIBUTE_VECTOR_ROTATE,
"Attribute Vector Rotate",
NODE_CLASS_ATTRIBUTE,
0);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoints.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_endpoints.cc
index 7853c5aa04a..65d22eca39c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoints.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_endpoints.cc
@@ -212,7 +212,8 @@ void register_node_type_geo_curve_endpoints()
{
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_ENDPOINTS, "Curve Endpoints", NODE_CLASS_GEOMETRY, 0);
+ 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;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_reverse.cc
new file mode 100644
index 00000000000..d1c81333c30
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_reverse.cc
@@ -0,0 +1,71 @@
+/*
+ * 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 "BKE_spline.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes {
+
+static void geo_node_curve_reverse_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>("Curve");
+ b.add_input<decl::String>("Selection");
+ b.add_output<decl::Geometry>("Curve");
+}
+
+static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
+ geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ if (!geometry_set.has_curve()) {
+ params.set_output("Curve", geometry_set);
+ return;
+ }
+
+ /* Retrieve data for write access so we can avoid new allocations for the reversed data. */
+ CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
+ CurveEval &curve = *curve_component.get_for_write();
+ MutableSpan<SplinePtr> splines = curve.splines();
+
+ const std::string selection_name = params.extract_input<std::string>("Selection");
+ GVArray_Typed<bool> selection = curve_component.attribute_get_for_read(
+ selection_name, ATTR_DOMAIN_CURVE, true);
+
+ threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
+ for (const int i : range) {
+ if (selection[i]) {
+ splines[i]->reverse();
+ }
+ }
+ });
+
+ params.set_output("Curve", geometry_set);
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_legacy_curve_reverse()
+{
+ 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;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_select_by_handle_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc
index dfcae2e65b0..dfcae2e65b0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_select_by_handle_type.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_set_handles.cc
new file mode 100644
index 00000000000..339029336d9
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_set_handles.cc
@@ -0,0 +1,144 @@
+/*
+ * 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_spline.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes {
+
+static void geo_node_curve_set_handles_decalre(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>("Curve");
+ b.add_input<decl::String>("Selection");
+ b.add_output<decl::Geometry>("Curve");
+}
+
+static void geo_node_curve_set_handles_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)
+{
+ NodeGeometryCurveSetHandles *data = (NodeGeometryCurveSetHandles *)MEM_callocN(
+ sizeof(NodeGeometryCurveSetHandles), __func__);
+
+ data->handle_type = GEO_NODE_CURVE_HANDLE_AUTO;
+ data->mode = GEO_NODE_CURVE_HANDLE_LEFT | GEO_NODE_CURVE_HANDLE_RIGHT;
+ node->storage = data;
+}
+
+static BezierSpline::HandleType handle_type_from_input_type(GeometryNodeCurveHandleType type)
+{
+ switch (type) {
+ case GEO_NODE_CURVE_HANDLE_AUTO:
+ return BezierSpline::HandleType::Auto;
+ case GEO_NODE_CURVE_HANDLE_ALIGN:
+ return BezierSpline::HandleType::Align;
+ case GEO_NODE_CURVE_HANDLE_FREE:
+ return BezierSpline::HandleType::Free;
+ case GEO_NODE_CURVE_HANDLE_VECTOR:
+ return BezierSpline::HandleType::Vector;
+ }
+ BLI_assert_unreachable();
+ return BezierSpline::HandleType::Auto;
+}
+
+static void geo_node_curve_set_handles_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;
+
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
+ geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ if (!geometry_set.has_curve()) {
+ params.set_output("Curve", geometry_set);
+ return;
+ }
+
+ /* Retrieve data for write access so we can avoid new allocations for the handles data. */
+ CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
+ CurveEval &curve = *curve_component.get_for_write();
+ MutableSpan<SplinePtr> splines = curve.splines();
+
+ const std::string selection_name = params.extract_input<std::string>("Selection");
+ GVArray_Typed<bool> selection = curve_component.attribute_get_for_read(
+ selection_name, ATTR_DOMAIN_POINT, true);
+
+ const BezierSpline::HandleType new_handle_type = handle_type_from_input_type(type);
+ int point_index = 0;
+ bool has_bezier_spline = false;
+ for (SplinePtr &spline : splines) {
+ if (spline->type() != Spline::Type::Bezier) {
+ point_index += spline->positions().size();
+ continue;
+ }
+
+ BezierSpline &bezier_spline = static_cast<BezierSpline &>(*spline);
+ if (ELEM(new_handle_type, BezierSpline::HandleType::Free, BezierSpline::HandleType::Align)) {
+ /* In this case the automatically calculated handle types need to be "baked", because
+ * they're possibly changing from a type that is calculated automatically to a type that
+ * is positioned manually. */
+ bezier_spline.ensure_auto_handles();
+ }
+ has_bezier_spline = true;
+ for (int i_point : IndexRange(bezier_spline.size())) {
+ if (selection[point_index]) {
+ if (mode & GEO_NODE_CURVE_HANDLE_LEFT) {
+ bezier_spline.handle_types_left()[i_point] = new_handle_type;
+ }
+ if (mode & GEO_NODE_CURVE_HANDLE_RIGHT) {
+ bezier_spline.handle_types_right()[i_point] = new_handle_type;
+ }
+ }
+ point_index++;
+ }
+ bezier_spline.mark_cache_invalid();
+ }
+
+ if (!has_bezier_spline) {
+ params.error_message_add(NodeWarningType::Info, TIP_("No Bezier splines in input curve"));
+ }
+
+ params.set_output("Curve", geometry_set);
+}
+} // namespace blender::nodes
+
+void register_node_type_geo_legacy_curve_set_handles()
+{
+ 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);
+ node_type_storage(&ntype,
+ "NodeGeometryCurveSetHandles",
+ node_free_standard_storage,
+ node_copy_standard_storage);
+ ntype.draw_buttons = blender::nodes::geo_node_curve_set_handles_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_curve_spline_type.cc
new file mode 100644
index 00000000000..44522e990d9
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_spline_type.cc
@@ -0,0 +1,302 @@
+/*
+ * 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_spline.hh"
+
+#include "BLI_task.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes {
+
+static void geo_node_legacy_curve_spline_type_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>("Curve");
+ b.add_input<decl::String>("Selection");
+ b.add_output<decl::Geometry>("Curve");
+}
+
+static void geo_node_legacy_curve_spline_type_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)
+{
+ NodeGeometryCurveSplineType *data = (NodeGeometryCurveSplineType *)MEM_callocN(
+ sizeof(NodeGeometryCurveSplineType), __func__);
+
+ data->spline_type = GEO_NODE_SPLINE_TYPE_POLY;
+ node->storage = data;
+}
+
+template<class T>
+static void scale_input_assign(const Span<T> input,
+ const int scale,
+ const int offset,
+ const MutableSpan<T> r_output)
+{
+ for (const int i : IndexRange(r_output.size())) {
+ r_output[i] = input[i * scale + offset];
+ }
+}
+
+template<class T>
+static void scale_output_assign(const Span<T> input,
+ const int scale,
+ const int offset,
+ const MutableSpan<T> &r_output)
+{
+ for (const int i : IndexRange(input.size())) {
+ r_output[i * scale + offset] = input[i];
+ }
+}
+
+template<typename CopyFn>
+static void copy_attributes(const Spline &input_spline, Spline &output_spline, CopyFn copy_fn)
+{
+ input_spline.attributes.foreach_attribute(
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ std::optional<GSpan> src = input_spline.attributes.get_for_read(attribute_id);
+ BLI_assert(src);
+ if (!output_spline.attributes.create(attribute_id, meta_data.data_type)) {
+ BLI_assert_unreachable();
+ return false;
+ }
+ std::optional<GMutableSpan> dst = output_spline.attributes.get_for_write(attribute_id);
+ if (!dst) {
+ BLI_assert_unreachable();
+ return false;
+ }
+
+ copy_fn(*src, *dst);
+
+ return true;
+ },
+ ATTR_DOMAIN_POINT);
+}
+
+static SplinePtr convert_to_poly_spline(const Spline &input)
+{
+ std::unique_ptr<PolySpline> output = std::make_unique<PolySpline>();
+ output->resize(input.positions().size());
+ output->positions().copy_from(input.positions());
+ output->radii().copy_from(input.radii());
+ output->tilts().copy_from(input.tilts());
+ Spline::copy_base_settings(input, *output);
+ output->attributes = input.attributes;
+ return output;
+}
+
+static SplinePtr poly_to_nurbs(const Spline &input)
+{
+ std::unique_ptr<NURBSpline> output = std::make_unique<NURBSpline>();
+ output->resize(input.positions().size());
+ output->positions().copy_from(input.positions());
+ output->radii().copy_from(input.radii());
+ output->tilts().copy_from(input.tilts());
+ output->weights().fill(1.0f);
+ output->set_resolution(12);
+ output->set_order(4);
+ Spline::copy_base_settings(input, *output);
+ output->knots_mode = NURBSpline::KnotsMode::Bezier;
+ output->attributes = input.attributes;
+ return output;
+}
+
+static SplinePtr bezier_to_nurbs(const Spline &input)
+{
+ const BezierSpline &bezier_spline = static_cast<const BezierSpline &>(input);
+ std::unique_ptr<NURBSpline> output = std::make_unique<NURBSpline>();
+ output->resize(input.size() * 3);
+
+ scale_output_assign(bezier_spline.handle_positions_left(), 3, 0, output->positions());
+ scale_output_assign(input.radii(), 3, 0, output->radii());
+ scale_output_assign(input.tilts(), 3, 0, output->tilts());
+
+ scale_output_assign(bezier_spline.positions(), 3, 1, output->positions());
+ scale_output_assign(input.radii(), 3, 1, output->radii());
+ scale_output_assign(input.tilts(), 3, 1, output->tilts());
+
+ scale_output_assign(bezier_spline.handle_positions_right(), 3, 2, output->positions());
+ scale_output_assign(input.radii(), 3, 2, output->radii());
+ scale_output_assign(input.tilts(), 3, 2, output->tilts());
+
+ Spline::copy_base_settings(input, *output);
+ output->weights().fill(1.0f);
+ output->set_resolution(12);
+ output->set_order(4);
+ output->set_cyclic(input.is_cyclic());
+ output->knots_mode = NURBSpline::KnotsMode::Bezier;
+ output->attributes.reallocate(output->size());
+ copy_attributes(input, *output, [](GSpan src, GMutableSpan dst) {
+ attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ scale_output_assign<T>(src.typed<T>(), 3, 0, dst.typed<T>());
+ scale_output_assign<T>(src.typed<T>(), 3, 1, dst.typed<T>());
+ scale_output_assign<T>(src.typed<T>(), 3, 2, dst.typed<T>());
+ });
+ });
+ return output;
+}
+
+static SplinePtr poly_to_bezier(const Spline &input)
+{
+ std::unique_ptr<BezierSpline> output = std::make_unique<BezierSpline>();
+ output->resize(input.size());
+ output->positions().copy_from(input.positions());
+ output->radii().copy_from(input.radii());
+ output->tilts().copy_from(input.tilts());
+ output->handle_types_left().fill(BezierSpline::HandleType::Vector);
+ output->handle_types_right().fill(BezierSpline::HandleType::Vector);
+ output->set_resolution(12);
+ Spline::copy_base_settings(input, *output);
+ output->attributes = input.attributes;
+ return output;
+}
+
+static SplinePtr nurbs_to_bezier(const Spline &input)
+{
+ const NURBSpline &nurbs_spline = static_cast<const NURBSpline &>(input);
+ std::unique_ptr<BezierSpline> output = std::make_unique<BezierSpline>();
+ output->resize(input.size() / 3);
+ scale_input_assign<float3>(input.positions(), 3, 1, output->positions());
+ scale_input_assign<float3>(input.positions(), 3, 0, output->handle_positions_left());
+ scale_input_assign<float3>(input.positions(), 3, 2, output->handle_positions_right());
+ scale_input_assign<float>(input.radii(), 3, 2, output->radii());
+ scale_input_assign<float>(input.tilts(), 3, 2, output->tilts());
+ output->handle_types_left().fill(BezierSpline::HandleType::Align);
+ output->handle_types_right().fill(BezierSpline::HandleType::Align);
+ output->set_resolution(nurbs_spline.resolution());
+ Spline::copy_base_settings(input, *output);
+ output->attributes.reallocate(output->size());
+ copy_attributes(input, *output, [](GSpan src, GMutableSpan dst) {
+ attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ scale_input_assign<T>(src.typed<T>(), 3, 1, dst.typed<T>());
+ });
+ });
+ return output;
+}
+
+static SplinePtr convert_to_bezier(const Spline &input, GeoNodeExecParams params)
+{
+ switch (input.type()) {
+ case Spline::Type::Bezier:
+ return input.copy();
+ case Spline::Type::Poly:
+ return poly_to_bezier(input);
+ case Spline::Type::NURBS:
+ if (input.size() < 6) {
+ params.error_message_add(
+ NodeWarningType::Info,
+ TIP_("NURBS must have minimum of 6 points for Bezier Conversion"));
+ return input.copy();
+ }
+ else {
+ if (input.size() % 3 != 0) {
+ params.error_message_add(NodeWarningType::Info,
+ TIP_("NURBS must have multiples of 3 points for full Bezier "
+ "conversion, curve truncated"));
+ }
+ return nurbs_to_bezier(input);
+ }
+ }
+ BLI_assert_unreachable();
+ return {};
+}
+
+static SplinePtr convert_to_nurbs(const Spline &input)
+{
+ switch (input.type()) {
+ case Spline::Type::NURBS:
+ return input.copy();
+ case Spline::Type::Bezier:
+ return bezier_to_nurbs(input);
+ case Spline::Type::Poly:
+ return poly_to_nurbs(input);
+ }
+ BLI_assert_unreachable();
+ return {};
+}
+
+static void geo_node_legacy_curve_spline_type_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);
+ if (!geometry_set.has_curve()) {
+ params.set_output("Curve", geometry_set);
+ return;
+ }
+
+ const CurveComponent *curve_component = geometry_set.get_component_for_read<CurveComponent>();
+ const CurveEval &curve = *curve_component->get_for_read();
+
+ const std::string selection_name = params.extract_input<std::string>("Selection");
+ GVArray_Typed<bool> selection = curve_component->attribute_get_for_read(
+ selection_name, ATTR_DOMAIN_CURVE, true);
+
+ 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;
+ }
+ }
+ else {
+ new_curve->add_spline(curve.splines()[i]->copy());
+ }
+ }
+
+ new_curve->attributes = curve.attributes;
+ params.set_output("Curve", GeometrySet::create_with_curve(new_curve.release()));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_legacy_curve_spline_type()
+{
+ 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);
+ 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;
+
+ 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_curve_subdivide.cc
new file mode 100644
index 00000000000..f32a68bc042
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc
@@ -0,0 +1,392 @@
+/*
+ * 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 "BLI_timeit.hh"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_spline.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+using blender::fn::GVArray_For_GSpan;
+using blender::fn::GVArray_For_Span;
+using blender::fn::GVArray_Typed;
+
+namespace blender::nodes {
+
+static void geo_node_curve_subdivide_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>("Geometry");
+ b.add_input<decl::String>("Cuts");
+ b.add_input<decl::Int>("Cuts", "Cuts_001").default_value(1).min(0).max(1000);
+ b.add_output<decl::Geometry>("Geometry");
+}
+
+static void geo_node_curve_subdivide_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)
+{
+ NodeGeometryCurveSubdivide *data = (NodeGeometryCurveSubdivide *)MEM_callocN(
+ sizeof(NodeGeometryCurveSubdivide), __func__);
+
+ data->cuts_type = GEO_NODE_ATTRIBUTE_INPUT_INTEGER;
+ node->storage = data;
+}
+
+static void geo_node_curve_subdivide_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeGeometryPointTranslate &node_storage = *(NodeGeometryPointTranslate *)node->storage;
+
+ update_attribute_input_socket_availabilities(
+ *node, "Cuts", (GeometryNodeAttributeInputMode)node_storage.input_type);
+}
+
+static Array<int> get_subdivided_offsets(const Spline &spline,
+ const VArray<int> &cuts,
+ const int spline_offset)
+{
+ Array<int> offsets(spline.segments_size() + 1);
+ int offset = 0;
+ for (const int i : IndexRange(spline.segments_size())) {
+ offsets[i] = offset;
+ offset = offset + std::max(cuts[spline_offset + i], 0) + 1;
+ }
+ offsets.last() = offset;
+ return offsets;
+}
+
+template<typename T>
+static void subdivide_attribute(Span<T> src,
+ const Span<int> offsets,
+ const bool is_cyclic,
+ MutableSpan<T> dst)
+{
+ const int src_size = src.size();
+ threading::parallel_for(IndexRange(src_size - 1), 1024, [&](IndexRange range) {
+ for (const int i : range) {
+ const int cuts = offsets[i + 1] - offsets[i];
+ dst[offsets[i]] = src[i];
+ const float factor_delta = 1.0f / (cuts + 1.0f);
+ for (const int cut : IndexRange(cuts)) {
+ const float factor = (cut + 1) * factor_delta;
+ dst[offsets[i] + cut] = attribute_math::mix2(factor, src[i], src[i + 1]);
+ }
+ }
+ });
+
+ if (is_cyclic) {
+ const int i = src_size - 1;
+ const int cuts = offsets[i + 1] - offsets[i];
+ dst[offsets[i]] = src.last();
+ const float factor_delta = 1.0f / (cuts + 1.0f);
+ for (const int cut : IndexRange(cuts)) {
+ const float factor = (cut + 1) * factor_delta;
+ dst[offsets[i] + cut] = attribute_math::mix2(factor, src.last(), src.first());
+ }
+ }
+ else {
+ dst.last() = src.last();
+ }
+}
+
+/**
+ * In order to generate a Bezier spline with the same shape as the input spline, apply the
+ * De Casteljau algorithm iteratively for the provided number of cuts, constantly updating the
+ * previous result point's right handle and the left handle at the end of the segment.
+ *
+ * \note Non-vector segments in the result spline are given free handles. This could possibly be
+ * improved with another pass that sets handles to aligned where possible, but currently that does
+ * not provide much benefit for the increased complexity.
+ */
+static void subdivide_bezier_segment(const BezierSpline &src,
+ const int index,
+ const int offset,
+ const int result_size,
+ Span<float3> src_positions,
+ Span<float3> src_handles_left,
+ Span<float3> src_handles_right,
+ MutableSpan<float3> dst_positions,
+ MutableSpan<float3> dst_handles_left,
+ MutableSpan<float3> dst_handles_right,
+ MutableSpan<BezierSpline::HandleType> dst_type_left,
+ MutableSpan<BezierSpline::HandleType> dst_type_right)
+{
+ const bool is_last_cyclic_segment = index == (src.size() - 1);
+ const int next_index = is_last_cyclic_segment ? 0 : index + 1;
+
+ /* The first point in the segment is always copied. */
+ dst_positions[offset] = src_positions[index];
+
+ if (src.segment_is_vector(index)) {
+ if (is_last_cyclic_segment) {
+ dst_type_left.first() = BezierSpline::HandleType::Vector;
+ }
+ dst_type_left.slice(offset + 1, result_size).fill(BezierSpline::HandleType::Vector);
+ dst_type_right.slice(offset, result_size).fill(BezierSpline::HandleType::Vector);
+
+ const float factor_delta = 1.0f / result_size;
+ for (const int cut : IndexRange(result_size)) {
+ const float factor = cut * factor_delta;
+ dst_positions[offset + cut] = attribute_math::mix2(
+ factor, src_positions[index], src_positions[next_index]);
+ }
+ }
+ else {
+ if (is_last_cyclic_segment) {
+ dst_type_left.first() = BezierSpline::HandleType::Free;
+ }
+ dst_type_left.slice(offset + 1, result_size).fill(BezierSpline::HandleType::Free);
+ dst_type_right.slice(offset, result_size).fill(BezierSpline::HandleType::Free);
+
+ const int i_segment_last = is_last_cyclic_segment ? 0 : offset + result_size;
+
+ /* Create a Bezier segment to update iteratively for every subdivision
+ * and references to the meaningful values for ease of use. */
+ BezierSpline temp;
+ temp.resize(2);
+ float3 &segment_start = temp.positions().first();
+ float3 &segment_end = temp.positions().last();
+ float3 &handle_prev = temp.handle_positions_right().first();
+ float3 &handle_next = temp.handle_positions_left().last();
+ segment_start = src_positions[index];
+ segment_end = src_positions[next_index];
+ handle_prev = src_handles_right[index];
+ handle_next = src_handles_left[next_index];
+
+ for (const int cut : IndexRange(result_size - 1)) {
+ const float parameter = 1.0f / (result_size - cut);
+ const BezierSpline::InsertResult insert = temp.calculate_segment_insertion(0, 1, parameter);
+
+ /* Copy relevant temporary data to the result. */
+ dst_handles_right[offset + cut] = insert.handle_prev;
+ dst_handles_left[offset + cut + 1] = insert.left_handle;
+ dst_positions[offset + cut + 1] = insert.position;
+
+ /* Update the segment to prepare it for the next subdivision. */
+ segment_start = insert.position;
+ handle_prev = insert.right_handle;
+ handle_next = insert.handle_next;
+ }
+
+ /* Copy the handles for the last segment from the temporary spline. */
+ dst_handles_right[offset + result_size - 1] = handle_prev;
+ dst_handles_left[i_segment_last] = handle_next;
+ }
+}
+
+static void subdivide_bezier_spline(const BezierSpline &src,
+ const Span<int> offsets,
+ BezierSpline &dst)
+{
+ Span<float3> src_positions = src.positions();
+ Span<float3> src_handles_left = src.handle_positions_left();
+ Span<float3> src_handles_right = src.handle_positions_right();
+ MutableSpan<float3> dst_positions = dst.positions();
+ MutableSpan<float3> dst_handles_left = dst.handle_positions_left();
+ MutableSpan<float3> dst_handles_right = dst.handle_positions_right();
+ MutableSpan<BezierSpline::HandleType> dst_type_left = dst.handle_types_left();
+ MutableSpan<BezierSpline::HandleType> dst_type_right = dst.handle_types_right();
+
+ threading::parallel_for(IndexRange(src.size() - 1), 512, [&](IndexRange range) {
+ for (const int i : range) {
+ subdivide_bezier_segment(src,
+ i,
+ offsets[i],
+ offsets[i + 1] - offsets[i],
+ src_positions,
+ src_handles_left,
+ src_handles_right,
+ dst_positions,
+ dst_handles_left,
+ dst_handles_right,
+ dst_type_left,
+ dst_type_right);
+ }
+ });
+
+ if (src.is_cyclic()) {
+ const int i_last = src.size() - 1;
+ subdivide_bezier_segment(src,
+ i_last,
+ offsets[i_last],
+ offsets.last() - offsets[i_last],
+ src_positions,
+ src_handles_left,
+ src_handles_right,
+ dst_positions,
+ dst_handles_left,
+ dst_handles_right,
+ dst_type_left,
+ dst_type_right);
+ }
+ else {
+ dst_positions.last() = src_positions.last();
+ }
+}
+
+static void subdivide_builtin_attributes(const Spline &src_spline,
+ const Span<int> offsets,
+ Spline &dst_spline)
+{
+ const bool is_cyclic = src_spline.is_cyclic();
+ subdivide_attribute<float>(src_spline.radii(), offsets, is_cyclic, dst_spline.radii());
+ subdivide_attribute<float>(src_spline.tilts(), offsets, is_cyclic, dst_spline.tilts());
+ switch (src_spline.type()) {
+ case Spline::Type::Poly: {
+ const PolySpline &src = static_cast<const PolySpline &>(src_spline);
+ PolySpline &dst = static_cast<PolySpline &>(dst_spline);
+ subdivide_attribute<float3>(src.positions(), offsets, is_cyclic, dst.positions());
+ break;
+ }
+ case Spline::Type::Bezier: {
+ const BezierSpline &src = static_cast<const BezierSpline &>(src_spline);
+ BezierSpline &dst = static_cast<BezierSpline &>(dst_spline);
+ subdivide_bezier_spline(src, offsets, dst);
+ dst.mark_cache_invalid();
+ break;
+ }
+ case Spline::Type::NURBS: {
+ const NURBSpline &src = static_cast<const NURBSpline &>(src_spline);
+ NURBSpline &dst = static_cast<NURBSpline &>(dst_spline);
+ subdivide_attribute<float3>(src.positions(), offsets, is_cyclic, dst.positions());
+ subdivide_attribute<float>(src.weights(), offsets, is_cyclic, dst.weights());
+ break;
+ }
+ }
+}
+
+static void subdivide_dynamic_attributes(const Spline &src_spline,
+ const Span<int> offsets,
+ Spline &dst_spline)
+{
+ const bool is_cyclic = src_spline.is_cyclic();
+ src_spline.attributes.foreach_attribute(
+ [&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ std::optional<GSpan> src = src_spline.attributes.get_for_read(attribute_id);
+ BLI_assert(src);
+
+ if (!dst_spline.attributes.create(attribute_id, meta_data.data_type)) {
+ /* Since the source spline of the same type had the attribute, adding it should work. */
+ BLI_assert_unreachable();
+ }
+
+ std::optional<GMutableSpan> dst = dst_spline.attributes.get_for_write(attribute_id);
+ BLI_assert(dst);
+
+ attribute_math::convert_to_static_type(dst->type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ subdivide_attribute<T>(src->typed<T>(), offsets, is_cyclic, dst->typed<T>());
+ });
+ return true;
+ },
+ ATTR_DOMAIN_POINT);
+}
+
+static SplinePtr subdivide_spline(const Spline &spline,
+ const VArray<int> &cuts,
+ const int spline_offset)
+{
+ /* Since we expect to access each value many times, it should be worth it to make sure the
+ * attribute is a real span (especially considering the note below). Using the offset at each
+ * point facilitates subdividing in parallel later. */
+ Array<int> offsets = get_subdivided_offsets(spline, cuts, spline_offset);
+ const int result_size = offsets.last() + int(!spline.is_cyclic());
+ SplinePtr new_spline = spline.copy_only_settings();
+ new_spline->resize(result_size);
+ subdivide_builtin_attributes(spline, offsets, *new_spline);
+ subdivide_dynamic_attributes(spline, offsets, *new_spline);
+ return new_spline;
+}
+
+/**
+ * \note Passing the virtual array for the entire spline is possibly quite inefficient here when
+ * the attribute was on the point domain and stored separately for each spline already, and it
+ * prevents some other optimizations like skipping splines with a single attribute value of < 1.
+ * However, it allows the node to access builtin attribute easily, so it the makes most sense this
+ * way until the attribute API is refactored.
+ */
+static std::unique_ptr<CurveEval> subdivide_curve(const CurveEval &input_curve,
+ const VArray<int> &cuts)
+{
+ const Array<int> control_point_offsets = input_curve.control_point_offsets();
+ const Span<SplinePtr> input_splines = input_curve.splines();
+
+ std::unique_ptr<CurveEval> output_curve = std::make_unique<CurveEval>();
+ output_curve->resize(input_splines.size());
+ output_curve->attributes = input_curve.attributes;
+ MutableSpan<SplinePtr> output_splines = output_curve->splines();
+
+ threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) {
+ for (const int i : range) {
+ output_splines[i] = subdivide_spline(*input_splines[i], cuts, control_point_offsets[i]);
+ }
+ });
+
+ return output_curve;
+}
+
+static void geo_node_subdivide_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+
+ geometry_set = bke::geometry_set_realize_instances(geometry_set);
+
+ if (!geometry_set.has_curve()) {
+ params.set_output("Geometry", geometry_set);
+ return;
+ }
+
+ const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
+ GVArray_Typed<int> cuts = params.get_input_attribute<int>(
+ "Cuts", component, ATTR_DOMAIN_POINT, 0);
+ if (cuts->is_single() && cuts->get_internal_single() < 1) {
+ params.set_output("Geometry", geometry_set);
+ return;
+ }
+
+ std::unique_ptr<CurveEval> output_curve = subdivide_curve(*component.get_for_read(), *cuts);
+
+ params.set_output("Geometry", GeometrySet::create_with_curve(output_curve.release()));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_legacy_curve_subdivide()
+{
+ 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;
+ 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;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_to_points.cc
index 1e66b340f5c..0c435d69991 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_to_points.cc
@@ -358,7 +358,8 @@ void register_node_type_geo_curve_to_points()
{
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_TO_POINTS, "Curve to Points", NODE_CLASS_GEOMETRY, 0);
+ 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;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_delete_geometry.cc
index 1e2f652cd78..1e2f652cd78 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_delete_geometry.cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_edge_split.cc
index 867fecea251..2ea6516996d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_edge_split.cc
@@ -82,7 +82,7 @@ void register_node_type_geo_edge_split()
{
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_EDGE_SPLIT, "Edge Split", NODE_CLASS_GEOMETRY, 0);
+ 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;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_mesh_to_curve.cc
index 11349dc7d42..11349dc7d42 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_mesh_to_curve.cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_point_distribute.cc
index 04b4003daed..f95b0da86ed 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_point_distribute.cc
@@ -36,7 +36,6 @@
#include "node_geometry_util.hh"
-using blender::bke::AttributeKind;
using blender::bke::GeometryInstanceGroup;
namespace blender::nodes {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc
index fb45c22ced4..fb45c22ced4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_rotate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_point_rotate.cc
index 60c82360007..60c82360007 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_rotate.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_point_rotate.cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_scale.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_point_scale.cc
index 99adce149e9..99adce149e9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_scale.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_point_scale.cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_point_separate.cc
index 48b6676c1dd..48b6676c1dd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_point_separate.cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_point_translate.cc
index f2fce45c57b..f2fce45c57b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_point_translate.cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_points_to_volume.cc
index d920c8de9f0..d920c8de9f0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_points_to_volume.cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_raycast.cc
index 401a478f04c..401a478f04c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_raycast.cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_subdivision_surface.cc
index 4541bf3569f..07d3f89bdb7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_subdivision_surface.cc
@@ -133,7 +133,7 @@ void register_node_type_geo_subdivision_surface()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY, 0);
+ &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;
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 c8a33205de4..43fb00a482c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
@@ -26,18 +26,18 @@ namespace blender::nodes {
static void geo_node_attribute_capture_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Vector>("Value");
- b.add_input<decl::Float>("Value", "Value_001");
- b.add_input<decl::Color>("Value", "Value_002");
- b.add_input<decl::Bool>("Value", "Value_003");
- b.add_input<decl::Int>("Value", "Value_004");
+ b.add_input<decl::Vector>("Value").supports_field();
+ b.add_input<decl::Float>("Value", "Value_001").supports_field();
+ b.add_input<decl::Color>("Value", "Value_002").supports_field();
+ b.add_input<decl::Bool>("Value", "Value_003").supports_field();
+ b.add_input<decl::Int>("Value", "Value_004").supports_field();
b.add_output<decl::Geometry>("Geometry");
- b.add_output<decl::Vector>("Attribute");
- b.add_output<decl::Float>("Attribute", "Attribute_001");
- b.add_output<decl::Color>("Attribute", "Attribute_002");
- b.add_output<decl::Bool>("Attribute", "Attribute_003");
- b.add_output<decl::Int>("Attribute", "Attribute_004");
+ b.add_output<decl::Vector>("Attribute").field_source();
+ b.add_output<decl::Float>("Attribute", "Attribute_001").field_source();
+ b.add_output<decl::Color>("Attribute", "Attribute_002").field_source();
+ b.add_output<decl::Bool>("Attribute", "Attribute_003").field_source();
+ b.add_output<decl::Int>("Attribute", "Attribute_004").field_source();
}
static void geo_node_attribute_capture_layout(uiLayout *layout,
@@ -117,8 +117,6 @@ static void geo_node_attribute_capture_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
-
const bNode &node = params.node();
const NodeGeometryAttributeCapture &storage = *(const NodeGeometryAttributeCapture *)
node.storage;
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 21a9a338857..f93ef6f1db3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
@@ -47,8 +47,6 @@ static void geo_node_attribute_remove_exec(GeoNodeExecParams params)
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
Vector<std::string> attribute_names = params.extract_multi_input<std::string>("Attribute");
- geometry_set = geometry_set_realize_instances(geometry_set);
-
if (geometry_set.has<MeshComponent>()) {
remove_attribute(
geometry_set.get_component_for_write<MeshComponent>(), params, attribute_names);
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 5001034518c..1b7d2fe28a1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
@@ -29,8 +29,8 @@ namespace blender::nodes {
static void geo_node_attribute_statistic_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Float>("Attribute").hide_value();
- b.add_input<decl::Vector>("Attribute", "Attribute_001").hide_value();
+ b.add_input<decl::Float>("Attribute").hide_value().supports_field();
+ b.add_input<decl::Vector>("Attribute", "Attribute_001").hide_value().supports_field();
b.add_output<decl::Float>("Mean");
b.add_output<decl::Float>("Median");
diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
index 2a1c43a89fe..21b425c0ed4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
@@ -83,10 +83,14 @@ static void geo_node_boolean_exec(GeoNodeExecParams params)
GeometrySet set_a;
if (operation == GEO_NODE_BOOLEAN_DIFFERENCE) {
set_a = params.extract_input<GeometrySet>("Geometry 1");
+ if (set_a.has_instances()) {
+ params.error_message_add(
+ NodeWarningType::Info,
+ TIP_("Instances are not supported for the first geometry input, and will not be used"));
+ }
/* Note that it technically wouldn't be necessary to realize the instances for the first
* geometry input, but the boolean code expects the first shape for the difference operation
* to be a single mesh. */
- set_a = geometry_set_realize_instances(set_a);
const Mesh *mesh_in_a = set_a.get_mesh_for_read();
if (mesh_in_a != nullptr) {
meshes.append(mesh_in_a);
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 f4c295b06fb..d03221703f0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
@@ -21,6 +21,8 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "BKE_collection.h"
+
#include "node_geometry_util.hh"
namespace blender::nodes {
@@ -28,6 +30,12 @@ namespace blender::nodes {
static void geo_node_collection_info_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Collection>("Collection").hide_label();
+ b.add_input<decl::Bool>("Separate Children")
+ .description("Output each child of the collection as a separate instance");
+ b.add_input<decl::Bool>("Reset Children")
+ .description(
+ "Reset the transforms of every child instance in the output. Only used when Separate "
+ "Children is enabled");
b.add_output<decl::Geometry>("Geometry");
}
@@ -57,23 +65,66 @@ static void geo_node_collection_info_exec(GeoNodeExecParams params)
const bNode &bnode = params.node();
NodeGeometryCollectionInfo *node_storage = (NodeGeometryCollectionInfo *)bnode.storage;
- const bool transform_space_relative = (node_storage->transform_space ==
- GEO_NODE_TRANSFORM_SPACE_RELATIVE);
+ const bool use_relative_transform = (node_storage->transform_space ==
+ GEO_NODE_TRANSFORM_SPACE_RELATIVE);
InstancesComponent &instances = geometry_set_out.get_component_for_write<InstancesComponent>();
- float transform_mat[4][4];
- unit_m4(transform_mat);
const Object *self_object = params.self_object();
- if (transform_space_relative) {
- copy_v3_v3(transform_mat[3], collection->instance_offset);
-
- mul_m4_m4_pre(transform_mat, self_object->imat);
+ const bool separate_children = params.get_input<bool>("Separate Children");
+ if (separate_children) {
+ const bool reset_children = params.get_input<bool>("Reset Children");
+ Vector<Collection *> children_collections;
+ LISTBASE_FOREACH (CollectionChild *, collection_child, &collection->children) {
+ children_collections.append(collection_child->collection);
+ }
+ Vector<Object *> children_objects;
+ LISTBASE_FOREACH (CollectionObject *, collection_object, &collection->gobject) {
+ children_objects.append(collection_object->ob);
+ }
+
+ instances.reserve(children_collections.size() + children_objects.size());
+
+ for (Collection *child_collection : children_collections) {
+ float4x4 transform = float4x4::identity();
+ if (!reset_children) {
+ add_v3_v3(transform.values[3], child_collection->instance_offset);
+ if (use_relative_transform) {
+ mul_m4_m4_pre(transform.values, self_object->imat);
+ }
+ else {
+ sub_v3_v3(transform.values[3], collection->instance_offset);
+ }
+ }
+ const int handle = instances.add_reference(*child_collection);
+ instances.add_instance(handle, transform);
+ }
+ for (Object *child_object : children_objects) {
+ const int handle = instances.add_reference(*child_object);
+ float4x4 transform = float4x4::identity();
+ if (!reset_children) {
+ if (use_relative_transform) {
+ transform = self_object->imat;
+ }
+ else {
+ sub_v3_v3(transform.values[3], collection->instance_offset);
+ }
+ mul_m4_m4_post(transform.values, child_object->obmat);
+ }
+ instances.add_instance(handle, transform);
+ }
+ }
+ else {
+ float4x4 transform = float4x4::identity();
+ if (use_relative_transform) {
+ copy_v3_v3(transform.values[3], collection->instance_offset);
+ mul_m4_m4_pre(transform.values, self_object->imat);
+ }
+
+ const int handle = instances.add_reference(*collection);
+ instances.add_instance(handle, transform);
}
-
- const int handle = instances.add_reference(*collection);
- instances.add_instance(handle, transform_mat, -1);
params.set_output("Geometry", geometry_set_out);
}
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 f1e10e3d276..4377d32210d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
@@ -227,9 +227,13 @@ static Mesh *compute_hull(const GeometrySet &geometry_set)
return hull_from_bullet(geometry_set.get_mesh_for_read(), positions);
}
+/* Since only positions are read from the instances, this can be used as an internal optimization
+ * to avoid the cost of realizing instances before the node. But disable this for now, since
+ * re-enabling that optimization will be a separate step. */
+# if 0
static void read_positions(const GeometryComponent &component,
- Span<float4x4> transforms,
- Vector<float3> *r_coords)
+ Span<float4x4> transforms,
+ Vector<float3> *r_coords)
{
GVArray_Typed<float3> positions = component.attribute_get_for_read<float3>(
"position", ATTR_DOMAIN_POINT, {0, 0, 0});
@@ -265,6 +269,31 @@ static void read_curve_positions(const CurveEval &curve,
}
}
+static Mesh *convex_hull_from_instances(const GeometrySet &geometry_set)
+{
+ Vector<GeometryInstanceGroup> set_groups;
+ bke::geometry_set_gather_instances(geometry_set, set_groups);
+
+ Vector<float3> coords;
+
+ for (const GeometryInstanceGroup &set_group : set_groups) {
+ const GeometrySet &set = set_group.geometry_set;
+ Span<float4x4> transforms = set_group.transforms;
+
+ if (set.has_pointcloud()) {
+ read_positions(*set.get_component_for_read<PointCloudComponent>(), transforms, &coords);
+ }
+ if (set.has_mesh()) {
+ read_positions(*set.get_component_for_read<MeshComponent>(), transforms, &coords);
+ }
+ if (set.has_curve()) {
+ read_curve_positions(*set.get_curve_for_read(), transforms, &coords);
+ }
+ }
+ return hull_from_bullet(nullptr, coords);
+}
+# endif
+
#endif /* WITH_BULLET */
static void geo_node_convex_hull_exec(GeoNodeExecParams params)
@@ -272,33 +301,14 @@ static void geo_node_convex_hull_exec(GeoNodeExecParams params)
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
#ifdef WITH_BULLET
- Mesh *mesh = nullptr;
- if (geometry_set.has_instances()) {
- Vector<GeometryInstanceGroup> set_groups;
- bke::geometry_set_gather_instances(geometry_set, set_groups);
-
- Vector<float3> coords;
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- Span<float4x4> transforms = set_group.transforms;
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ Mesh *mesh = compute_hull(geometry_set);
+ geometry_set.replace_mesh(mesh);
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_INSTANCES});
+ });
- if (set.has_pointcloud()) {
- read_positions(*set.get_component_for_read<PointCloudComponent>(), transforms, &coords);
- }
- if (set.has_mesh()) {
- read_positions(*set.get_component_for_read<MeshComponent>(), transforms, &coords);
- }
- if (set.has_curve()) {
- read_curve_positions(*set.get_curve_for_read(), transforms, &coords);
- }
- }
- mesh = hull_from_bullet(nullptr, coords);
- }
- else {
- mesh = compute_hull(geometry_set);
- }
- params.set_output("Convex Hull", GeometrySet::create_with_mesh(mesh));
+ params.set_output("Convex Hull", std::move(geometry_set));
#else
params.error_message_add(NodeWarningType::Error,
TIP_("Disabled, Blender was compiled without Bullet"));
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 8de2975f9b0..c30741cf786 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
@@ -154,23 +154,8 @@ static void geo_node_curve_fill_exec(GeoNodeExecParams params)
const NodeGeometryCurveFill &storage = *(const NodeGeometryCurveFill *)params.node().storage;
const GeometryNodeCurveFillMode mode = (GeometryNodeCurveFillMode)storage.mode;
- if (geometry_set.has_instances()) {
- InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
- instances.ensure_geometry_instances();
-
- threading::parallel_for(IndexRange(instances.references_amount()), 16, [&](IndexRange range) {
- for (int i : range) {
- GeometrySet &geometry_set = instances.geometry_set_from_reference(i);
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
- curve_fill_calculate(geometry_set, mode);
- }
- });
-
- params.set_output("Mesh", std::move(geometry_set));
- return;
- }
-
- curve_fill_calculate(geometry_set, mode);
+ geometry_set.modify_geometry_sets(
+ [&](GeometrySet &geometry_set) { curve_fill_calculate(geometry_set, mode); });
params.set_output("Mesh", std::move(geometry_set));
}
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 830cfcc8331..67ce20efd9d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
@@ -563,19 +563,16 @@ static std::unique_ptr<CurveEval> fillet_curve(const CurveEval &input_curve,
return output_curve;
}
-static void geo_node_fillet_exec(GeoNodeExecParams params)
+static void calculate_curve_fillet(GeometrySet &geometry_set,
+ const GeometryNodeCurveFilletMode mode,
+ const Field<float> &radius_field,
+ const std::optional<Field<int>> &count_field,
+ const bool limit_radius)
{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
-
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
-
if (!geometry_set.has_curve()) {
- params.set_output("Curve", geometry_set);
return;
}
- NodeGeometryCurveFillet &node_storage = *(NodeGeometryCurveFillet *)params.node().storage;
- const GeometryNodeCurveFilletMode mode = (GeometryNodeCurveFilletMode)node_storage.mode;
FilletParam fillet_param;
fillet_param.mode = mode;
@@ -584,19 +581,16 @@ static void geo_node_fillet_exec(GeoNodeExecParams params)
const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
fn::FieldEvaluator field_evaluator{field_context, domain_size};
- Field<float> radius_field = params.extract_input<Field<float>>("Radius");
- field_evaluator.add(std::move(radius_field));
+ field_evaluator.add(radius_field);
if (mode == GEO_NODE_CURVE_FILLET_POLY) {
- Field<int> count_field = params.extract_input<Field<int>>("Count");
- field_evaluator.add(std::move(count_field));
+ field_evaluator.add(*count_field);
}
field_evaluator.evaluate();
fillet_param.radii = &field_evaluator.get_evaluated<float>(0);
if (fillet_param.radii->is_single() && fillet_param.radii->get_internal_single() < 0.0f) {
- params.set_output("Geometry", geometry_set);
return;
}
@@ -604,13 +598,36 @@ static void geo_node_fillet_exec(GeoNodeExecParams params)
fillet_param.counts = &field_evaluator.get_evaluated<int>(1);
}
- fillet_param.limit_radius = params.extract_input<bool>("Limit Radius");
+ fillet_param.limit_radius = limit_radius;
const CurveEval &input_curve = *geometry_set.get_curve_for_read();
std::unique_ptr<CurveEval> output_curve = fillet_curve(input_curve, fillet_param);
- params.set_output("Curve", GeometrySet::create_with_curve(output_curve.release()));
+ geometry_set.replace_curve(output_curve.release());
+}
+
+static void geo_node_fillet_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;
+
+ Field<float> radius_field = params.extract_input<Field<float>>("Radius");
+ const bool limit_radius = params.extract_input<bool>("Limit Radius");
+
+ std::optional<Field<int>> count_field;
+ if (mode == GEO_NODE_CURVE_FILLET_POLY) {
+ count_field.emplace(params.extract_input<Field<int>>("Count"));
+ }
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ calculate_curve_fillet(geometry_set, mode, radius_field, count_field, limit_radius);
+ });
+
+ params.set_output("Curve", std::move(geometry_set));
}
+
} // namespace blender::nodes
void register_node_type_geo_curve_fillet()
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 8fe054633a1..ac7df35bb72 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
@@ -28,7 +28,6 @@ static void geo_node_curve_length_declare(NodeDeclarationBuilder &b)
static void geo_node_curve_length_exec(GeoNodeExecParams params)
{
GeometrySet curve_set = params.extract_input<GeometrySet>("Curve");
- curve_set = bke::geometry_set_realize_instances(curve_set);
if (!curve_set.has_curve()) {
params.set_output("Length", 0.0f);
return;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc
index 2cde198e679..90853387ec7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc
@@ -24,7 +24,7 @@ namespace blender::nodes {
static void geo_node_curve_parameter_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Float>("Factor");
+ b.add_output<decl::Float>("Factor").field_source();
}
/**
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 0803d43e5c3..7292fafc8b0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
@@ -43,26 +43,18 @@ static std::unique_ptr<CurveEval> create_spiral_curve(const float rotations,
const int totalpoints = std::max(int(resolution * rotations), 1);
const float delta_radius = (end_radius - start_radius) / (float)totalpoints;
- float radius = start_radius;
const float delta_height = height / (float)totalpoints;
- const float delta_theta = (M_PI * 2 * rotations) / (float)totalpoints;
- float theta = 0.0f;
+ const float delta_theta = (M_PI * 2 * rotations) / (float)totalpoints *
+ (direction ? 1.0f : -1.0f);
for (const int i : IndexRange(totalpoints + 1)) {
+ const float theta = i * delta_theta;
+ const float radius = start_radius + i * delta_radius;
const float x = radius * cos(theta);
const float y = radius * sin(theta);
const float z = delta_height * i;
spline->add_point(float3(x, y, z), 1.0f, 0.0f);
-
- radius += delta_radius;
-
- if (direction) {
- theta += delta_theta;
- }
- else {
- theta -= delta_theta;
- }
}
spline->attributes.reallocate(spline->size());
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 208525f17f6..e5be9b7a6f4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
@@ -35,8 +35,9 @@ namespace blender::nodes {
static void geo_node_curve_resample_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Int>("Count").default_value(10).min(1).max(100000);
- b.add_input<decl::Float>("Length").default_value(0.1f).min(0.001f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Int>("Count").default_value(10).min(1).max(100000).supports_field();
+ b.add_input<decl::Float>("Length").default_value(0.1f).min(0.001f).supports_field().subtype(
+ PROP_DISTANCE);
b.add_output<decl::Geometry>("Geometry");
}
@@ -68,8 +69,8 @@ static void geo_node_curve_resample_update(bNodeTree *UNUSED(ntree), bNode *node
struct SampleModeParam {
GeometryNodeCurveResampleMode mode;
- std::optional<float> length;
- std::optional<int> count;
+ std::optional<Field<float>> length;
+ std::optional<Field<int>> count;
};
static SplinePtr resample_spline(const Spline &src, const int count)
@@ -163,28 +164,44 @@ static SplinePtr resample_spline_evaluated(const Spline &src)
return dst;
}
-static std::unique_ptr<CurveEval> resample_curve(const CurveEval &input_curve,
+static std::unique_ptr<CurveEval> resample_curve(const CurveComponent *component,
const SampleModeParam &mode_param)
{
- Span<SplinePtr> input_splines = input_curve.splines();
+ const CurveEval *input_curve = component->get_for_read();
+ GeometryComponentFieldContext field_context{*component, ATTR_DOMAIN_CURVE};
+ const int domain_size = component->attribute_domain_size(ATTR_DOMAIN_CURVE);
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+
+ Span<SplinePtr> input_splines = input_curve->splines();
std::unique_ptr<CurveEval> output_curve = std::make_unique<CurveEval>();
output_curve->resize(input_splines.size());
MutableSpan<SplinePtr> output_splines = output_curve->splines();
if (mode_param.mode == GEO_NODE_CURVE_RESAMPLE_COUNT) {
+ evaluator.add(*mode_param.count);
+ evaluator.evaluate();
+ const VArray<int> &cuts = evaluator.get_evaluated<int>(0);
+
threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) {
for (const int i : range) {
BLI_assert(mode_param.count);
- output_splines[i] = resample_spline(*input_splines[i], *mode_param.count);
+ output_splines[i] = resample_spline(*input_splines[i], std::max(cuts[i], 1));
}
});
}
else if (mode_param.mode == GEO_NODE_CURVE_RESAMPLE_LENGTH) {
+ evaluator.add(*mode_param.length);
+ evaluator.evaluate();
+ const VArray<float> &lengths = evaluator.get_evaluated<float>(0);
+
threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) {
for (const int i : range) {
- const float length = input_splines[i]->length();
- const int count = std::max(int(length / *mode_param.length) + 1, 1);
+ /* 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();
+ const int count = std::max(int(spline_length / divide_length) + 1, 1);
output_splines[i] = resample_spline(*input_splines[i], count);
}
});
@@ -197,29 +214,35 @@ static std::unique_ptr<CurveEval> resample_curve(const CurveEval &input_curve,
});
}
- output_curve->attributes = input_curve.attributes;
+ output_curve->attributes = input_curve->attributes;
return output_curve;
}
-static void geo_node_resample_exec(GeoNodeExecParams params)
+static void geometry_set_curve_resample(GeometrySet &geometry_set,
+ const SampleModeParam &mode_param)
{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
-
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
-
if (!geometry_set.has_curve()) {
- params.set_output("Geometry", GeometrySet());
return;
}
- const CurveEval &input_curve = *geometry_set.get_curve_for_read();
+ std::unique_ptr<CurveEval> output_curve = resample_curve(
+ geometry_set.get_component_for_read<CurveComponent>(), mode_param);
+
+ geometry_set.replace_curve(output_curve.release());
+}
+
+static void geo_node_resample_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+
NodeGeometryCurveResample &node_storage = *(NodeGeometryCurveResample *)params.node().storage;
const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode;
+
SampleModeParam mode_param;
mode_param.mode = mode;
if (mode == GEO_NODE_CURVE_RESAMPLE_COUNT) {
- const int count = params.extract_input<int>("Count");
+ Field<int> count = params.extract_input<Field<int>>("Count");
if (count < 1) {
params.set_output("Geometry", GeometrySet());
return;
@@ -227,14 +250,14 @@ static void geo_node_resample_exec(GeoNodeExecParams params)
mode_param.count.emplace(count);
}
else if (mode == GEO_NODE_CURVE_RESAMPLE_LENGTH) {
- /* Don't allow asymptotic count increase for low resolution values. */
- const float resolution = std::max(params.extract_input<float>("Length"), 0.0001f);
+ Field<int> resolution = params.extract_input<Field<int>>("Length");
mode_param.length.emplace(resolution);
}
- std::unique_ptr<CurveEval> output_curve = resample_curve(input_curve, mode_param);
+ geometry_set.modify_geometry_sets(
+ [&](GeometrySet &geometry_set) { geometry_set_curve_resample(geometry_set, mode_param); });
- params.set_output("Geometry", GeometrySet::create_with_curve(output_curve.release()));
+ params.set_output("Geometry", std::move(geometry_set));
}
} // namespace blender::nodes
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 32bcbe2c608..b644faabedb 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
@@ -25,37 +25,39 @@ namespace blender::nodes {
static void geo_node_curve_reverse_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Curve");
- b.add_input<decl::String>("Selection");
+ b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
b.add_output<decl::Geometry>("Curve");
}
static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
- if (!geometry_set.has_curve()) {
- params.set_output("Curve", geometry_set);
- return;
- }
- /* Retrieve data for write access so we can avoid new allocations for the reversed data. */
- CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
- CurveEval &curve = *curve_component.get_for_write();
- MutableSpan<SplinePtr> splines = curve.splines();
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (!geometry_set.has_curve()) {
+ return;
+ }
+
+ Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+ CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
- const std::string selection_name = params.extract_input<std::string>("Selection");
- GVArray_Typed<bool> selection = curve_component.attribute_get_for_read(
- selection_name, ATTR_DOMAIN_CURVE, true);
+ 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);
- threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
- for (const int i : range) {
- if (selection[i]) {
- splines[i]->reverse();
+ CurveEval &curve = *component.get_for_write();
+ MutableSpan<SplinePtr> splines = curve.splines();
+ threading::parallel_for(selection.index_range(), 128, [&](IndexRange range) {
+ for (const int i : range) {
+ splines[selection[i]]->reverse();
}
- }
+ });
});
- params.set_output("Curve", geometry_set);
+ params.set_output("Curve", std::move(geometry_set));
}
} // namespace blender::nodes
@@ -63,8 +65,7 @@ static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
void register_node_type_geo_curve_reverse()
{
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_CURVE_REVERSE, "Curve Reverse", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_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;
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 ac0cd510ffa..1266f525861 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
@@ -28,12 +28,12 @@ namespace blender::nodes {
static void geo_node_curve_sample_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Curve");
- b.add_input<decl::Float>("Factor").min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Float>("Length").min(0.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>("Factor").min(0.0f).max(1.0f).subtype(PROP_FACTOR).supports_field();
+ b.add_input<decl::Float>("Length").min(0.0f).subtype(PROP_DISTANCE).supports_field();
- b.add_output<decl::Vector>("Position");
- b.add_output<decl::Vector>("Tangent");
- b.add_output<decl::Vector>("Normal");
+ b.add_output<decl::Vector>("Position").dependent_field();
+ b.add_output<decl::Vector>("Tangent").dependent_field();
+ b.add_output<decl::Vector>("Normal").dependent_field();
}
static void geo_node_curve_sample_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
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 31c13134f79..9e7ac60c29d 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
@@ -23,10 +23,10 @@
namespace blender::nodes {
-static void geo_node_curve_set_handles_decalre(NodeDeclarationBuilder &b)
+static void geo_node_curve_set_handles_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Curve");
- b.add_input<decl::String>("Selection");
+ b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
b.add_output<decl::Geometry>("Curve");
}
@@ -44,7 +44,7 @@ static void geo_node_curve_set_handles_init(bNodeTree *UNUSED(tree), bNode *node
sizeof(NodeGeometryCurveSetHandles), __func__);
data->handle_type = GEO_NODE_CURVE_HANDLE_AUTO;
- data->mode = GEO_NODE_CURVE_HANDLE_LEFT | GEO_NODE_CURVE_HANDLE_RIGHT;
+ data->mode = GEO_NODE_CURVE_HANDLE_LEFT;
node->storage = data;
}
@@ -72,57 +72,63 @@ 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);
- if (!geometry_set.has_curve()) {
- params.set_output("Curve", geometry_set);
- return;
- }
-
- /* Retrieve data for write access so we can avoid new allocations for the handles data. */
- CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
- CurveEval &curve = *curve_component.get_for_write();
- MutableSpan<SplinePtr> splines = curve.splines();
+ Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
- const std::string selection_name = params.extract_input<std::string>("Selection");
- GVArray_Typed<bool> selection = curve_component.attribute_get_for_read(
- selection_name, ATTR_DOMAIN_POINT, true);
-
- const BezierSpline::HandleType new_handle_type = handle_type_from_input_type(type);
- int point_index = 0;
bool has_bezier_spline = false;
- for (SplinePtr &spline : splines) {
- if (spline->type() != Spline::Type::Bezier) {
- point_index += spline->positions().size();
- continue;
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (!geometry_set.has_curve()) {
+ return;
}
- BezierSpline &bezier_spline = static_cast<BezierSpline &>(*spline);
- if (ELEM(new_handle_type, BezierSpline::HandleType::Free, BezierSpline::HandleType::Align)) {
- /* In this case the automatically calculated handle types need to be "baked", because
- * they're possibly changing from a type that is calculated automatically to a type that
- * is positioned manually. */
- bezier_spline.ensure_auto_handles();
- }
- has_bezier_spline = true;
- for (int i_point : IndexRange(bezier_spline.size())) {
- if (selection[point_index]) {
- if (mode & GEO_NODE_CURVE_HANDLE_LEFT) {
- bezier_spline.handle_types_left()[i_point] = new_handle_type;
- }
- if (mode & GEO_NODE_CURVE_HANDLE_RIGHT) {
- bezier_spline.handle_types_right()[i_point] = new_handle_type;
+ /* Retrieve data for write access so we can avoid new allocations for the handles data. */
+ CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
+ CurveEval &curve = *curve_component.get_for_write();
+ MutableSpan<SplinePtr> splines = curve.splines();
+
+ GeometryComponentFieldContext field_context{curve_component, ATTR_DOMAIN_POINT};
+ const int domain_size = curve_component.attribute_domain_size(ATTR_DOMAIN_POINT);
+
+ fn::FieldEvaluator selection_evaluator{field_context, domain_size};
+ selection_evaluator.add(selection_field);
+ selection_evaluator.evaluate();
+ const VArray<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
+
+ const BezierSpline::HandleType new_handle_type = handle_type_from_input_type(type);
+ int point_index = 0;
+
+ for (SplinePtr &spline : splines) {
+ if (spline->type() != Spline::Type::Bezier) {
+ point_index += spline->positions().size();
+ continue;
+ }
+
+ has_bezier_spline = true;
+ BezierSpline &bezier_spline = static_cast<BezierSpline &>(*spline);
+ if (ELEM(new_handle_type, BezierSpline::HandleType::Free, BezierSpline::HandleType::Align)) {
+ /* In this case the automatically calculated handle types need to be "baked", because
+ * they're possibly changing from a type that is calculated automatically to a type that
+ * is positioned manually. */
+ bezier_spline.ensure_auto_handles();
+ }
+
+ for (int i_point : IndexRange(bezier_spline.size())) {
+ if (selection[point_index]) {
+ if (mode & GEO_NODE_CURVE_HANDLE_LEFT) {
+ bezier_spline.handle_types_left()[i_point] = new_handle_type;
+ }
+ if (mode & GEO_NODE_CURVE_HANDLE_RIGHT) {
+ bezier_spline.handle_types_right()[i_point] = new_handle_type;
+ }
}
+ point_index++;
}
- point_index++;
+ bezier_spline.mark_cache_invalid();
}
- bezier_spline.mark_cache_invalid();
- }
-
+ });
if (!has_bezier_spline) {
params.error_message_add(NodeWarningType::Info, TIP_("No Bezier splines in input curve"));
}
-
- params.set_output("Curve", geometry_set);
+ params.set_output("Curve", std::move(geometry_set));
}
} // namespace blender::nodes
@@ -130,8 +136,8 @@ void register_node_type_geo_curve_set_handles()
{
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, 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);
node_type_storage(&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 0ef107fd8a4..ec72154db13 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
@@ -28,7 +28,7 @@ namespace blender::nodes {
static void geo_node_curve_spline_type_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Curve");
- b.add_input<decl::String>("Selection");
+ b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
b.add_output<decl::Geometry>("Curve");
}
@@ -245,41 +245,47 @@ static void geo_node_curve_spline_type_exec(GeoNodeExecParams params)
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);
- if (!geometry_set.has_curve()) {
- params.set_output("Curve", geometry_set);
- return;
- }
+ Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
- const CurveComponent *curve_component = geometry_set.get_component_for_read<CurveComponent>();
- const CurveEval &curve = *curve_component->get_for_read();
-
- const std::string selection_name = params.extract_input<std::string>("Selection");
- GVArray_Typed<bool> selection = curve_component->attribute_get_for_read(
- selection_name, ATTR_DOMAIN_CURVE, true);
-
- 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;
- }
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (!geometry_set.has_curve()) {
+ return;
}
- else {
- new_curve->add_spline(curve.splines()[i]->copy());
+
+ const CurveComponent *curve_component = geometry_set.get_component_for_read<CurveComponent>();
+ const CurveEval &curve = *curve_component->get_for_read();
+ GeometryComponentFieldContext field_context{*curve_component, ATTR_DOMAIN_CURVE};
+ const int domain_size = curve_component->attribute_domain_size(ATTR_DOMAIN_CURVE);
+
+ fn::FieldEvaluator selection_evaluator{field_context, domain_size};
+ selection_evaluator.add(selection_field);
+ selection_evaluator.evaluate();
+ 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;
+ }
+ }
+ else {
+ new_curve->add_spline(curve.splines()[i]->copy());
+ }
}
- }
+ new_curve->attributes = curve.attributes;
+ geometry_set.replace_curve(new_curve.release());
+ });
- new_curve->attributes = curve.attributes;
- params.set_output("Curve", GeometrySet::create_with_curve(new_curve.release()));
+ params.set_output("Curve", std::move(geometry_set));
}
} // namespace blender::nodes
@@ -288,7 +294,7 @@ void register_node_type_geo_curve_spline_type()
{
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_CURVE_SPLINE_TYPE, "Set Spline Type", NODE_CLASS_GEOMETRY, 0);
+ &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);
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 0522f2b8981..34997c66cbb 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
@@ -34,35 +34,10 @@ namespace blender::nodes {
static void geo_node_curve_subdivide_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Cuts");
- b.add_input<decl::Int>("Cuts", "Cuts_001").default_value(1).min(0).max(1000);
+ b.add_input<decl::Int>("Cuts").default_value(1).min(0).max(1000).supports_field();
b.add_output<decl::Geometry>("Geometry");
}
-static void geo_node_curve_subdivide_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)
-{
- NodeGeometryCurveSubdivide *data = (NodeGeometryCurveSubdivide *)MEM_callocN(
- sizeof(NodeGeometryCurveSubdivide), __func__);
-
- data->cuts_type = GEO_NODE_ATTRIBUTE_INPUT_INTEGER;
- node->storage = data;
-}
-
-static void geo_node_curve_subdivide_update(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeGeometryPointTranslate &node_storage = *(NodeGeometryPointTranslate *)node->storage;
-
- update_attribute_input_socket_availabilities(
- *node, "Cuts", (GeometryNodeAttributeInputMode)node_storage.input_type);
-}
-
static Array<int> get_subdivided_offsets(const Spline &spline,
const VArray<int> &cuts,
const int spline_offset)
@@ -350,25 +325,30 @@ static std::unique_ptr<CurveEval> subdivide_curve(const CurveEval &input_curve,
static void geo_node_subdivide_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ Field<int> cuts_field = params.extract_input<Field<int>>("Cuts");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (!geometry_set.has_curve()) {
+ return;
+ }
- if (!geometry_set.has_curve()) {
- params.set_output("Geometry", geometry_set);
- return;
- }
+ const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
- const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
- GVArray_Typed<int> cuts = params.get_input_attribute<int>(
- "Cuts", component, ATTR_DOMAIN_POINT, 0);
- if (cuts->is_single() && cuts->get_internal_single() < 1) {
- params.set_output("Geometry", geometry_set);
- return;
- }
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.add(cuts_field);
+ evaluator.evaluate();
+ const VArray<int> &cuts = evaluator.get_evaluated<int>(0);
- std::unique_ptr<CurveEval> output_curve = subdivide_curve(*component.get_for_read(), *cuts);
+ if (cuts.is_single() && cuts.get_internal_single() < 1) {
+ return;
+ }
- params.set_output("Geometry", GeometrySet::create_with_curve(output_curve.release()));
+ std::unique_ptr<CurveEval> output_curve = subdivide_curve(*component.get_for_read(), cuts);
+ geometry_set.replace_curve(output_curve.release());
+ });
+ params.set_output("Geometry", geometry_set);
}
} // namespace blender::nodes
@@ -377,16 +357,8 @@ void register_node_type_geo_curve_subdivide()
{
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_CURVE_SUBDIVIDE, "Curve Subdivide", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_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;
- 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;
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 89ba635ff4b..00451946af9 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
@@ -32,39 +32,52 @@ static void geo_node_curve_to_mesh_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>("Mesh");
}
+static void geometry_set_curve_to_mesh(GeometrySet &geometry_set, const GeometrySet &profile_set)
+{
+ const CurveEval *profile_curve = profile_set.get_curve_for_read();
+
+ if (profile_curve == nullptr) {
+ Mesh *mesh = bke::curve_to_wire_mesh(*geometry_set.get_curve_for_read());
+ geometry_set.replace_mesh(mesh);
+ }
+ else {
+ Mesh *mesh = bke::curve_to_mesh_sweep(*geometry_set.get_curve_for_read(), *profile_curve);
+ geometry_set.replace_mesh(mesh);
+ }
+}
+
static void geo_node_curve_to_mesh_exec(GeoNodeExecParams params)
{
GeometrySet curve_set = params.extract_input<GeometrySet>("Curve");
GeometrySet profile_set = params.extract_input<GeometrySet>("Profile Curve");
- curve_set = bke::geometry_set_realize_instances(curve_set);
- profile_set = bke::geometry_set_realize_instances(profile_set);
+ if (profile_set.has_instances()) {
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("Instances are not supported in the profile input"));
+ params.set_output("Mesh", GeometrySet());
+ return;
+ }
- /* NOTE: Theoretically an "is empty" check would be more correct for errors. */
- if (profile_set.has_mesh() && !profile_set.has_curve()) {
+ if (!profile_set.has_curve() && !profile_set.is_empty()) {
params.error_message_add(NodeWarningType::Warning,
- TIP_("No curve data available in profile input"));
+ TIP_("No curve data available in the profile input"));
}
- if (!curve_set.has_curve()) {
- if (curve_set.has_mesh()) {
- params.error_message_add(NodeWarningType::Warning,
- TIP_("No curve data available in curve input"));
+ bool has_curve = false;
+ curve_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (geometry_set.has_curve()) {
+ has_curve = true;
+ geometry_set_curve_to_mesh(geometry_set, profile_set);
}
- params.set_output("Mesh", GeometrySet());
- return;
- }
-
- const CurveEval *profile_curve = profile_set.get_curve_for_read();
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_INSTANCES});
+ });
- if (profile_curve == nullptr) {
- Mesh *mesh = bke::curve_to_wire_mesh(*curve_set.get_curve_for_read());
- params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
- }
- else {
- Mesh *mesh = bke::curve_to_mesh_sweep(*curve_set.get_curve_for_read(), *profile_curve);
- params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
+ if (!has_curve && !curve_set.is_empty()) {
+ params.error_message_add(NodeWarningType::Warning,
+ TIP_("No curve data available in curve input"));
}
+
+ params.set_output("Mesh", std::move(curve_set));
}
} // namespace blender::nodes
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 2b6d25b6bf3..97043980899 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
@@ -320,28 +320,18 @@ static void trim_bezier_spline(Spline &spline,
bezier_spline.resize(size);
}
-static void geo_node_curve_trim_exec(GeoNodeExecParams params)
+static void geometry_set_curve_trim(GeometrySet &geometry_set,
+ const GeometryNodeCurveSampleMode mode,
+ const float start,
+ const float end)
{
- const NodeGeometryCurveTrim &node_storage = *(NodeGeometryCurveTrim *)params.node().storage;
- const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode;
-
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
if (!geometry_set.has_curve()) {
- params.set_output("Curve", std::move(geometry_set));
return;
}
- CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
- CurveEval &curve = *curve_component.get_for_write();
+ CurveEval &curve = *geometry_set.get_curve_for_write();
MutableSpan<SplinePtr> splines = curve.splines();
- const float start = mode == GEO_NODE_CURVE_SAMPLE_FACTOR ?
- params.extract_input<float>("Start") :
- params.extract_input<float>("Start_001");
- const float end = mode == GEO_NODE_CURVE_SAMPLE_FACTOR ? params.extract_input<float>("End") :
- params.extract_input<float>("End_001");
-
threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
for (const int i : range) {
Spline &spline = *splines[i];
@@ -382,6 +372,29 @@ static void geo_node_curve_trim_exec(GeoNodeExecParams params)
splines[i]->mark_cache_invalid();
}
});
+}
+
+static void geo_node_curve_trim_exec(GeoNodeExecParams params)
+{
+ const NodeGeometryCurveTrim &node_storage = *(NodeGeometryCurveTrim *)params.node().storage;
+ const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode;
+
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
+
+ if (mode == GEO_NODE_CURVE_SAMPLE_FACTOR) {
+ const float start = params.extract_input<float>("Start");
+ const float end = params.extract_input<float>("End");
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ geometry_set_curve_trim(geometry_set, mode, start, end);
+ });
+ }
+ else if (mode == GEO_NODE_CURVE_SAMPLE_LENGTH) {
+ const float start = params.extract_input<float>("Start_001");
+ const float end = params.extract_input<float>("End_001");
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ geometry_set_curve_trim(geometry_set, mode, start, end);
+ });
+ }
params.set_output("Curve", std::move(geometry_set));
}
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
new file mode 100644
index 00000000000..1a4c5d84dbf
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
@@ -0,0 +1,594 @@
+/*
+ * 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_kdtree.h"
+#include "BLI_noise.hh"
+#include "BLI_rand.hh"
+#include "BLI_task.hh"
+#include "BLI_timeit.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_pointcloud_types.h"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_bvhutils.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_mesh_sample.hh"
+#include "BKE_pointcloud.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+using blender::bke::GeometryInstanceGroup;
+
+namespace blender::nodes {
+
+static void geo_node_point_distribute_points_on_faces_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>("Geometry");
+ b.add_input<decl::Float>("Distance Min").min(0.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>("Density Max").default_value(10.0f).min(0.0f);
+ b.add_input<decl::Float>("Density").default_value(10.0f).supports_field();
+ b.add_input<decl::Float>("Density Factor")
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR)
+ .supports_field();
+ b.add_input<decl::Int>("Seed");
+ b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
+
+ b.add_output<decl::Geometry>("Points");
+ b.add_output<decl::Vector>("Normal").field_source();
+ b.add_output<decl::Vector>("Rotation").subtype(PROP_EULER).field_source();
+ b.add_output<decl::Int>("Stable ID").field_source();
+}
+
+static void geo_node_point_distribute_points_on_faces_layout(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "distribute_method", 0, "", ICON_NONE);
+}
+
+static void node_point_distribute_points_on_faces_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *sock_distance_min = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
+ bNodeSocket *sock_density_max = (bNodeSocket *)sock_distance_min->next;
+ bNodeSocket *sock_density = sock_density_max->next;
+ bNodeSocket *sock_density_factor = sock_density->next;
+ nodeSetSocketAvailability(sock_distance_min,
+ node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON);
+ nodeSetSocketAvailability(sock_density_max,
+ node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON);
+ nodeSetSocketAvailability(sock_density,
+ node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_RANDOM);
+ nodeSetSocketAvailability(sock_density_factor,
+ node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON);
+}
+
+/**
+ * Use an arbitrary choice of axes for a usable rotation attribute directly out of this node.
+ */
+static float3 normal_to_euler_rotation(const float3 normal)
+{
+ float quat[4];
+ vec_to_quat(quat, normal, OB_NEGZ, OB_POSY);
+ float3 rotation;
+ quat_to_eul(rotation, quat);
+ return rotation;
+}
+
+static void sample_mesh_surface(const Mesh &mesh,
+ const float base_density,
+ const Span<float> density_factors,
+ const int seed,
+ Vector<float3> &r_positions,
+ Vector<float3> &r_bary_coords,
+ Vector<int> &r_looptri_indices)
+{
+ const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
+ BKE_mesh_runtime_looptri_len(&mesh)};
+
+ for (const int looptri_index : looptris.index_range()) {
+ const MLoopTri &looptri = looptris[looptri_index];
+ const int v0_loop = looptri.tri[0];
+ const int v1_loop = looptri.tri[1];
+ const int v2_loop = looptri.tri[2];
+ const int v0_index = mesh.mloop[v0_loop].v;
+ const int v1_index = mesh.mloop[v1_loop].v;
+ const int v2_index = mesh.mloop[v2_loop].v;
+ const float3 v0_pos = float3(mesh.mvert[v0_index].co);
+ const float3 v1_pos = float3(mesh.mvert[v1_index].co);
+ const float3 v2_pos = float3(mesh.mvert[v2_index].co);
+
+ float looptri_density_factor = 1.0f;
+ if (!density_factors.is_empty()) {
+ const float v0_density_factor = std::max(0.0f, density_factors[v0_loop]);
+ const float v1_density_factor = std::max(0.0f, density_factors[v1_loop]);
+ const float v2_density_factor = std::max(0.0f, density_factors[v2_loop]);
+ looptri_density_factor = (v0_density_factor + v1_density_factor + v2_density_factor) / 3.0f;
+ }
+ const float area = area_tri_v3(v0_pos, v1_pos, v2_pos);
+
+ const int looptri_seed = noise::hash(looptri_index, seed);
+ RandomNumberGenerator looptri_rng(looptri_seed);
+
+ const float points_amount_fl = area * base_density * looptri_density_factor;
+ const float add_point_probability = fractf(points_amount_fl);
+ const bool add_point = add_point_probability > looptri_rng.get_float();
+ const int point_amount = (int)points_amount_fl + (int)add_point;
+
+ for (int i = 0; i < point_amount; i++) {
+ const float3 bary_coord = looptri_rng.get_barycentric_coordinates();
+ float3 point_pos;
+ interp_v3_v3v3v3(point_pos, v0_pos, v1_pos, v2_pos, bary_coord);
+ r_positions.append(point_pos);
+ r_bary_coords.append(bary_coord);
+ r_looptri_indices.append(looptri_index);
+ }
+ }
+}
+
+BLI_NOINLINE static KDTree_3d *build_kdtree(Span<float3> positions)
+{
+ KDTree_3d *kdtree = BLI_kdtree_3d_new(positions.size());
+
+ int i_point = 0;
+ for (const float3 position : positions) {
+ BLI_kdtree_3d_insert(kdtree, i_point, position);
+ i_point++;
+ }
+
+ BLI_kdtree_3d_balance(kdtree);
+ return kdtree;
+}
+
+BLI_NOINLINE static void update_elimination_mask_for_close_points(
+ Span<float3> positions, const float minimum_distance, MutableSpan<bool> elimination_mask)
+{
+ if (minimum_distance <= 0.0f) {
+ return;
+ }
+
+ KDTree_3d *kdtree = build_kdtree(positions);
+
+ for (const int i : positions.index_range()) {
+ if (elimination_mask[i]) {
+ continue;
+ }
+
+ struct CallbackData {
+ int index;
+ MutableSpan<bool> elimination_mask;
+ } callback_data = {i, elimination_mask};
+
+ BLI_kdtree_3d_range_search_cb(
+ kdtree,
+ positions[i],
+ minimum_distance,
+ [](void *user_data, int index, const float *UNUSED(co), float UNUSED(dist_sq)) {
+ CallbackData &callback_data = *static_cast<CallbackData *>(user_data);
+ if (index != callback_data.index) {
+ callback_data.elimination_mask[index] = true;
+ }
+ return true;
+ },
+ &callback_data);
+ }
+
+ BLI_kdtree_3d_free(kdtree);
+}
+
+BLI_NOINLINE static void update_elimination_mask_based_on_density_factors(
+ const Mesh &mesh,
+ const Span<float> density_factors,
+ const Span<float3> bary_coords,
+ const Span<int> looptri_indices,
+ const MutableSpan<bool> elimination_mask)
+{
+ const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
+ BKE_mesh_runtime_looptri_len(&mesh)};
+ for (const int i : bary_coords.index_range()) {
+ if (elimination_mask[i]) {
+ continue;
+ }
+
+ const MLoopTri &looptri = looptris[looptri_indices[i]];
+ const float3 bary_coord = bary_coords[i];
+
+ const int v0_loop = looptri.tri[0];
+ const int v1_loop = looptri.tri[1];
+ const int v2_loop = looptri.tri[2];
+
+ const float v0_density_factor = std::max(0.0f, density_factors[v0_loop]);
+ const float v1_density_factor = std::max(0.0f, density_factors[v1_loop]);
+ const float v2_density_factor = std::max(0.0f, density_factors[v2_loop]);
+
+ const float probablity = v0_density_factor * bary_coord.x + v1_density_factor * bary_coord.y +
+ v2_density_factor * bary_coord.z;
+
+ const float hash = noise::hash_float_to_float(bary_coord);
+ if (hash > probablity) {
+ elimination_mask[i] = true;
+ }
+ }
+}
+
+BLI_NOINLINE static void eliminate_points_based_on_mask(const Span<bool> elimination_mask,
+ Vector<float3> &positions,
+ Vector<float3> &bary_coords,
+ Vector<int> &looptri_indices)
+{
+ for (int i = positions.size() - 1; i >= 0; i--) {
+ if (elimination_mask[i]) {
+ positions.remove_and_reorder(i);
+ bary_coords.remove_and_reorder(i);
+ looptri_indices.remove_and_reorder(i);
+ }
+ }
+}
+
+BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh,
+ const Span<float3> bary_coords,
+ const Span<int> looptri_indices,
+ const AttributeDomain source_domain,
+ const GVArray &source_data,
+ GMutableSpan output_data)
+{
+ switch (source_domain) {
+ case ATTR_DOMAIN_POINT: {
+ bke::mesh_surface_sample::sample_point_attribute(
+ mesh, looptri_indices, bary_coords, source_data, output_data);
+ break;
+ }
+ case ATTR_DOMAIN_CORNER: {
+ bke::mesh_surface_sample::sample_corner_attribute(
+ mesh, looptri_indices, bary_coords, source_data, output_data);
+ break;
+ }
+ case ATTR_DOMAIN_FACE: {
+ bke::mesh_surface_sample::sample_face_attribute(
+ mesh, looptri_indices, source_data, output_data);
+ break;
+ }
+ default: {
+ /* Not supported currently. */
+ return;
+ }
+ }
+}
+
+BLI_NOINLINE static void propagate_existing_attributes(
+ const MeshComponent &mesh_component,
+ const Map<AttributeIDRef, AttributeKind> &attributes,
+ GeometryComponent &point_component,
+ const Span<float3> bary_coords,
+ const Span<int> looptri_indices)
+{
+ const Mesh &mesh = *mesh_component.get_for_read();
+
+ for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
+ const AttributeIDRef attribute_id = entry.key;
+ const CustomDataType output_data_type = entry.value.data_type;
+ /* The output domain is always #ATTR_DOMAIN_POINT, since we are creating a point cloud. */
+ OutputAttribute attribute_out = point_component.attribute_try_get_for_output_only(
+ attribute_id, ATTR_DOMAIN_POINT, output_data_type);
+ if (!attribute_out) {
+ continue;
+ }
+
+ GMutableSpan out_span = attribute_out.as_span();
+
+ std::optional<AttributeMetaData> attribute_info = point_component.attribute_get_meta_data(
+ attribute_id);
+ if (!attribute_info) {
+ continue;
+ }
+
+ const AttributeDomain source_domain = attribute_info->domain;
+ GVArrayPtr source_attribute = mesh_component.attribute_get_for_read(
+ attribute_id, source_domain, output_data_type, nullptr);
+ if (!source_attribute) {
+ continue;
+ }
+
+ interpolate_attribute(
+ mesh, bary_coords, looptri_indices, source_domain, *source_attribute, out_span);
+
+ attribute_out.save();
+ }
+}
+
+namespace {
+struct AttributeOutputs {
+ StrongAnonymousAttributeID normal_id;
+ StrongAnonymousAttributeID rotation_id;
+ StrongAnonymousAttributeID stable_id_id;
+};
+} // namespace
+
+BLI_NOINLINE static void compute_attribute_outputs(const MeshComponent &mesh_component,
+ PointCloudComponent &point_component,
+ const Span<float3> bary_coords,
+ const Span<int> looptri_indices,
+ const AttributeOutputs &attribute_outputs)
+{
+ std::optional<OutputAttribute_Typed<int>> id_attribute;
+ std::optional<OutputAttribute_Typed<float3>> normal_attribute;
+ std::optional<OutputAttribute_Typed<float3>> rotation_attribute;
+
+ MutableSpan<int> ids;
+ MutableSpan<float3> normals;
+ MutableSpan<float3> rotations;
+
+ if (attribute_outputs.stable_id_id) {
+ id_attribute.emplace(point_component.attribute_try_get_for_output_only<int>(
+ attribute_outputs.stable_id_id.get(), ATTR_DOMAIN_POINT));
+ ids = id_attribute->as_span();
+ }
+ if (attribute_outputs.normal_id) {
+ normal_attribute.emplace(point_component.attribute_try_get_for_output_only<float3>(
+ attribute_outputs.normal_id.get(), ATTR_DOMAIN_POINT));
+ normals = normal_attribute->as_span();
+ }
+ if (attribute_outputs.rotation_id) {
+ rotation_attribute.emplace(point_component.attribute_try_get_for_output_only<float3>(
+ attribute_outputs.rotation_id.get(), ATTR_DOMAIN_POINT));
+ rotations = rotation_attribute->as_span();
+ }
+
+ const Mesh &mesh = *mesh_component.get_for_read();
+ const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
+ BKE_mesh_runtime_looptri_len(&mesh)};
+
+ for (const int i : bary_coords.index_range()) {
+ const int looptri_index = looptri_indices[i];
+ const MLoopTri &looptri = looptris[looptri_index];
+ const float3 &bary_coord = bary_coords[i];
+
+ const int v0_index = mesh.mloop[looptri.tri[0]].v;
+ const int v1_index = mesh.mloop[looptri.tri[1]].v;
+ const int v2_index = mesh.mloop[looptri.tri[2]].v;
+ const float3 v0_pos = float3(mesh.mvert[v0_index].co);
+ const float3 v1_pos = float3(mesh.mvert[v1_index].co);
+ const float3 v2_pos = float3(mesh.mvert[v2_index].co);
+
+ if (!ids.is_empty()) {
+ ids[i] = noise::hash(noise::hash_float(bary_coord), looptri_index);
+ }
+ float3 normal;
+ if (!normals.is_empty() || !rotations.is_empty()) {
+ normal_tri_v3(normal, v0_pos, v1_pos, v2_pos);
+ }
+ if (!normals.is_empty()) {
+ normals[i] = normal;
+ }
+ if (!rotations.is_empty()) {
+ rotations[i] = normal_to_euler_rotation(normal);
+ }
+ }
+
+ if (id_attribute) {
+ id_attribute->save();
+ }
+ if (normal_attribute) {
+ normal_attribute->save();
+ }
+ if (rotation_attribute) {
+ rotation_attribute->save();
+ }
+}
+
+static Array<float> calc_full_density_factors_with_selection(const MeshComponent &component,
+ const Field<float> &density_field,
+ const Field<bool> &selection_field)
+{
+ const AttributeDomain attribute_domain = ATTR_DOMAIN_CORNER;
+ 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();
+ return densities;
+}
+
+static void distribute_points_random(const MeshComponent &component,
+ const Field<float> &density_field,
+ const Field<bool> &selection_field,
+ const int seed,
+ Vector<float3> &positions,
+ Vector<float3> &bary_coords,
+ Vector<int> &looptri_indices)
+{
+ const Array<float> densities = calc_full_density_factors_with_selection(
+ component, density_field, selection_field);
+ const Mesh &mesh = *component.get_for_read();
+ sample_mesh_surface(mesh, 1.0f, densities, seed, positions, bary_coords, looptri_indices);
+}
+
+static void distribute_points_poisson_disk(const MeshComponent &mesh_component,
+ const float minimum_distance,
+ const float max_density,
+ const Field<float> &density_factor_field,
+ const Field<bool> &selection_field,
+ const int seed,
+ Vector<float3> &positions,
+ Vector<float3> &bary_coords,
+ Vector<int> &looptri_indices)
+{
+ const Mesh &mesh = *mesh_component.get_for_read();
+ sample_mesh_surface(mesh, max_density, {}, seed, positions, bary_coords, looptri_indices);
+
+ Array<bool> elimination_mask(positions.size(), false);
+ update_elimination_mask_for_close_points(positions, minimum_distance, elimination_mask);
+
+ const Array<float> density_factors = calc_full_density_factors_with_selection(
+ mesh_component, density_factor_field, selection_field);
+
+ update_elimination_mask_based_on_density_factors(
+ mesh, density_factors, bary_coords, looptri_indices, elimination_mask.as_mutable_span());
+
+ eliminate_points_based_on_mask(
+ elimination_mask.as_span(), positions, bary_coords, looptri_indices);
+}
+
+static void point_distribution_calculate(GeometrySet &geometry_set,
+ const Field<bool> selection_field,
+ const GeometryNodeDistributePointsOnFacesMode method,
+ const int seed,
+ const AttributeOutputs &attribute_outputs,
+ const GeoNodeExecParams &params)
+{
+ if (!geometry_set.has_mesh()) {
+ return;
+ }
+
+ const MeshComponent &mesh_component = *geometry_set.get_component_for_read<MeshComponent>();
+
+ Vector<float3> positions;
+ Vector<float3> bary_coords;
+ Vector<int> looptri_indices;
+
+ switch (method) {
+ case GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_RANDOM: {
+ const Field<float> density_field = params.get_input<Field<float>>("Density");
+ distribute_points_random(mesh_component,
+ density_field,
+ selection_field,
+ seed,
+ positions,
+ bary_coords,
+ looptri_indices);
+ break;
+ }
+ case GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON: {
+ const float minimum_distance = params.get_input<float>("Distance Min");
+ const float density_max = params.get_input<float>("Density Max");
+ const Field<float> density_factors_field = params.get_input<Field<float>>("Density Factor");
+ distribute_points_poisson_disk(mesh_component,
+ minimum_distance,
+ density_max,
+ density_factors_field,
+ selection_field,
+ seed,
+ positions,
+ bary_coords,
+ looptri_indices);
+ break;
+ }
+ }
+
+ PointCloud *pointcloud = BKE_pointcloud_new_nomain(positions.size());
+ memcpy(pointcloud->co, positions.data(), sizeof(float3) * positions.size());
+ uninitialized_fill_n(pointcloud->radius, pointcloud->totpoint, 0.05f);
+ geometry_set.replace_pointcloud(pointcloud);
+
+ PointCloudComponent &point_component =
+ geometry_set.get_component_for_write<PointCloudComponent>();
+
+ Map<AttributeIDRef, AttributeKind> attributes;
+ geometry_set.gather_attributes_for_propagation(
+ {GEO_COMPONENT_TYPE_MESH}, GEO_COMPONENT_TYPE_POINT_CLOUD, false, attributes);
+
+ /* Position is set separately. */
+ attributes.remove("position");
+
+ propagate_existing_attributes(
+ mesh_component, attributes, point_component, bary_coords, looptri_indices);
+
+ compute_attribute_outputs(
+ mesh_component, point_component, bary_coords, looptri_indices, attribute_outputs);
+}
+
+static void geo_node_point_distribute_points_on_faces_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+
+ const GeometryNodeDistributePointsOnFacesMode method =
+ static_cast<GeometryNodeDistributePointsOnFacesMode>(params.node().custom1);
+
+ const int seed = params.get_input<int>("Seed") * 5383843;
+ const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+
+ AttributeOutputs attribute_outputs;
+ if (params.output_is_required("Normal")) {
+ attribute_outputs.normal_id = StrongAnonymousAttributeID("normal");
+ }
+ if (params.output_is_required("Rotation")) {
+ attribute_outputs.rotation_id = StrongAnonymousAttributeID("rotation");
+ }
+ if (params.output_is_required("Stable ID")) {
+ attribute_outputs.stable_id_id = StrongAnonymousAttributeID("stable id");
+ }
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ point_distribution_calculate(
+ geometry_set, selection_field, method, seed, attribute_outputs, params);
+ /* Keep instances because the original geometry set may contain instances that are processed as
+ * well. */
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_INSTANCES});
+ });
+
+ params.set_output("Points", std::move(geometry_set));
+
+ if (attribute_outputs.normal_id) {
+ params.set_output(
+ "Normal",
+ AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.normal_id)));
+ }
+ if (attribute_outputs.rotation_id) {
+ params.set_output(
+ "Rotation",
+ AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.rotation_id)));
+ }
+ if (attribute_outputs.stable_id_id) {
+ params.set_output(
+ "Stable ID",
+ AnonymousAttributeFieldInput::Create<int>(std::move(attribute_outputs.stable_id_id)));
+ }
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_distribute_points_on_faces()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype,
+ GEO_NODE_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_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;
+ 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 c52ff3d448e..7fcbaf429dd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_index.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_index.cc
@@ -20,30 +20,12 @@ namespace blender::nodes {
static void geo_node_input_index_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Int>("Index");
+ b.add_output<decl::Int>("Index").field_source();
}
-class IndexFieldInput final : public fn::FieldInput {
- public:
- IndexFieldInput() : FieldInput(CPPType::get<int>(), "Index")
- {
- }
-
- const GVArray *get_varray_for_context(const fn::FieldContext &UNUSED(context),
- IndexMask mask,
- ResourceScope &scope) const final
- {
- /* TODO: Investigate a similar method to IndexRange::as_span() */
- auto index_func = [](int i) { return i; };
- return &scope.construct<
- fn::GVArray_For_EmbeddedVArray<int, VArray_For_Func<int, decltype(index_func)>>>(
- mask.min_array_size(), mask.min_array_size(), index_func);
- }
-};
-
static void geo_node_input_index_exec(GeoNodeExecParams params)
{
- Field<int> index_field{std::make_shared<IndexFieldInput>()};
+ Field<int> index_field{std::make_shared<fn::IndexFieldInput>()};
params.set_output("Index", std::move(index_field));
}
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 f92086acdf0..5a2495afb9e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
@@ -28,7 +28,7 @@ namespace blender::nodes {
static void geo_node_input_normal_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Vector>("Normal");
+ b.add_output<decl::Vector>("Normal").field_source();
}
static GVArrayPtr mesh_face_normals(const Mesh &mesh,
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 3f3457a3acb..44874259e20 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_position.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_position.cc
@@ -20,13 +20,12 @@ namespace blender::nodes {
static void geo_node_input_position_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Vector>("Position");
+ b.add_output<decl::Vector>("Position").field_source();
}
static void geo_node_input_position_exec(GeoNodeExecParams params)
{
- Field<float3> position_field{
- std::make_shared<AttributeFieldInput>("position", CPPType::get<float3>())};
+ Field<float3> position_field{AttributeFieldInput::Create<float3>("position")};
params.set_output("Position", std::move(position_field));
}
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
new file mode 100644
index 00000000000..b5f3e1b0c28
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
@@ -0,0 +1,109 @@
+/*
+ * 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"
+
+#include "BKE_spline.hh"
+
+namespace blender::nodes {
+
+static void geo_node_input_spline_length_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Float>("Length").field_source();
+}
+
+static const GVArray *construct_spline_length_gvarray(const CurveComponent &component,
+ const AttributeDomain domain,
+ ResourceScope &scope)
+{
+ const CurveEval *curve = component.get_for_read();
+ if (curve == nullptr) {
+ return nullptr;
+ }
+
+ Span<SplinePtr> splines = curve->splines();
+ auto length_fn = [splines](int i) { return splines[i]->length(); };
+
+ if (domain == ATTR_DOMAIN_CURVE) {
+ return &scope.construct<
+ fn::GVArray_For_EmbeddedVArray<float, VArray_For_Func<float, decltype(length_fn)>>>(
+ splines.size(), splines.size(), length_fn);
+ }
+ if (domain == ATTR_DOMAIN_POINT) {
+ GVArrayPtr length = std::make_unique<
+ fn::GVArray_For_EmbeddedVArray<float, VArray_For_Func<float, decltype(length_fn)>>>(
+ splines.size(), splines.size(), length_fn);
+ return scope
+ .add_value(component.attribute_try_adapt_domain(
+ std::move(length), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT))
+ .get();
+ }
+
+ return nullptr;
+}
+
+class SplineLengthFieldInput final : public fn::FieldInput {
+ public:
+ SplineLengthFieldInput() : fn::FieldInput(CPPType::get<float>(), "Spline Length")
+ {
+ }
+
+ const GVArray *get_varray_for_context(const fn::FieldContext &context,
+ IndexMask UNUSED(mask),
+ ResourceScope &scope) 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);
+ }
+ }
+ return nullptr;
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 3549623580;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const SplineLengthFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void geo_node_input_spline_length_exec(GeoNodeExecParams params)
+{
+ Field<float> length_field{std::make_shared<SplineLengthFieldInput>()};
+ params.set_output("Length", std::move(length_field));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_input_spline_length()
+{
+ 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;
+ 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 68788709f1e..d690642373a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
@@ -24,7 +24,7 @@ namespace blender::nodes {
static void geo_node_input_tangent_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Vector>("Tangent");
+ b.add_output<decl::Vector>("Tangent").field_source();
}
static void calculate_bezier_tangents(const BezierSpline &spline, MutableSpan<float3> tangents)
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
new file mode 100644
index 00000000000..8c0c0763be8
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
@@ -0,0 +1,207 @@
+/*
+ * 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_collection_types.h"
+
+#include "BLI_hash.h"
+#include "BLI_task.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes {
+
+static void geo_node_instance_on_points_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>("Points").description("Points to instance on");
+ b.add_input<decl::Geometry>("Instance").description("Geometry that is instanced on the points");
+ b.add_input<decl::Bool>("Pick Instance")
+ .supports_field()
+ .description("Place different instances on different points");
+ b.add_input<decl::Int>("Instance Index")
+ .implicit_field()
+ .description(
+ "Index of the instance that used for each point. This is only used when Pick Instances "
+ "is on. By default the point index is used");
+ b.add_input<decl::Vector>("Rotation")
+ .subtype(PROP_EULER)
+ .supports_field()
+ .description("Rotation of the instances");
+ b.add_input<decl::Vector>("Scale")
+ .default_value({1.0f, 1.0f, 1.0f})
+ .supports_field()
+ .description("Scale of the instances");
+ b.add_input<decl::Int>("Stable ID")
+ .supports_field()
+ .description(
+ "ID for every instance that is used to identify it over time even when the number of "
+ "instances changes. Used for example for motion blur");
+
+ b.add_output<decl::Geometry>("Instances");
+}
+
+static void add_instances_from_component(InstancesComponent &dst_component,
+ const GeometryComponent &src_component,
+ const GeometrySet &instance,
+ const GeoNodeExecParams &params)
+{
+ const AttributeDomain domain = ATTR_DOMAIN_POINT;
+ const int domain_size = src_component.attribute_domain_size(domain);
+
+ /* The initial size of the component might be non-zero when this function is called for multiple
+ * component types. */
+ const int start_len = dst_component.instances_amount();
+ dst_component.resize(start_len + domain_size);
+ MutableSpan<int> dst_handles = dst_component.instance_reference_handles().slice(start_len,
+ domain_size);
+ MutableSpan<float4x4> dst_transforms = dst_component.instance_transforms().slice(start_len,
+ domain_size);
+ MutableSpan<int> dst_stable_ids = dst_component.instance_ids().slice(start_len, domain_size);
+
+ GeometryComponentFieldContext field_context{src_component, domain};
+ FieldEvaluator field_evaluator{field_context, domain_size};
+
+ const VArray<bool> *pick_instance = nullptr;
+ const VArray<int> *indices = nullptr;
+ const VArray<float3> *rotations = nullptr;
+ const VArray<float3> *scales = nullptr;
+ 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.add_with_destination(params.get_input<Field<int>>("Stable ID"), dst_stable_ids);
+ field_evaluator.evaluate();
+
+ GVArray_Typed<float3> positions = src_component.attribute_get_for_read<float3>(
+ "position", domain, {0, 0, 0});
+
+ const InstancesComponent *src_instances = instance.get_component_for_read<InstancesComponent>();
+
+ /* Maps handles from the source instances to handles on the new instance. */
+ Array<int> handle_mapping;
+ /* Only fill #handle_mapping when it may be used below. */
+ if (src_instances != nullptr &&
+ (!pick_instance->is_single() || pick_instance->get_internal_single())) {
+ Span<InstanceReference> src_references = src_instances->references();
+ handle_mapping.reinitialize(src_references.size());
+ for (const int src_instance_handle : src_references.index_range()) {
+ const InstanceReference &reference = src_references[src_instance_handle];
+ const int dst_instance_handle = dst_component.add_reference(reference);
+ handle_mapping[src_instance_handle] = dst_instance_handle;
+ }
+ }
+
+ const int full_instance_handle = dst_component.add_reference(instance);
+ /* Add this reference last, because it is the most likely one to be removed later on. */
+ const int empty_reference_handle = dst_component.add_reference(InstanceReference());
+
+ threading::parallel_for(IndexRange(domain_size), 1024, [&](IndexRange range) {
+ for (const int i : range) {
+ /* Compute base transform for every instances. */
+ float4x4 &dst_transform = dst_transforms[i];
+ dst_transform = float4x4::from_loc_eul_scale(
+ positions[i], rotations->get(i), scales->get(i));
+
+ /* Reference that will be used by this new instance. */
+ int dst_handle = empty_reference_handle;
+
+ const bool use_individual_instance = pick_instance->get(i);
+ if (use_individual_instance) {
+ if (src_instances != nullptr) {
+ const int src_instances_amount = src_instances->instances_amount();
+ const int original_index = indices->get(i);
+ /* Use #mod_i instead of `%` to get the desirable wrap around behavior where -1 refers to
+ * the last element. */
+ const int index = mod_i(original_index, std::max(src_instances_amount, 1));
+ if (index < src_instances_amount) {
+ /* Get the reference to the source instance. */
+ const int src_handle = src_instances->instance_reference_handles()[index];
+ dst_handle = handle_mapping[src_handle];
+
+ /* Take transforms of the source instance into account. */
+ mul_m4_m4_post(dst_transform.values,
+ src_instances->instance_transforms()[index].values);
+ }
+ }
+ }
+ else {
+ /* Use entire source geometry as instance. */
+ dst_handle = full_instance_handle;
+ }
+ /* Set properties of new instance. */
+ dst_handles[i] = dst_handle;
+ }
+ });
+
+ if (pick_instance->is_single()) {
+ if (pick_instance->get_internal_single()) {
+ if (instance.has_realized_data()) {
+ params.error_message_add(
+ NodeWarningType::Info,
+ TIP_("Realized geometry is not used when pick instances is true"));
+ }
+ }
+ }
+}
+
+static void geo_node_instance_on_points_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Points");
+ GeometrySet instance = params.get_input<GeometrySet>("Instance");
+ instance.ensure_owns_direct_data();
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
+
+ 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);
+ }
+ 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);
+ }
+ 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);
+ }
+ /* Unused references may have been added above. Remove those now so that other nodes don't
+ * process them needlessly. */
+ instances.remove_unused_references();
+ });
+
+ params.set_output("Instances", std::move(geometry_set));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_instance_on_points()
+{
+ 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;
+ 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 93643298f92..3e9b615f478 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
@@ -437,7 +437,7 @@ static void join_curve_components(MutableSpan<GeometrySet> src_geometry_sets, Ge
/* 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", "cyclic", "resolution"});
+ {"position", "radius", "tilt", "handle_left", "handle_right", "cyclic", "resolution"});
CurveComponent &dst_component = result.get_component_for_write<CurveComponent>();
CurveEval *dst_curve = new CurveEval();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_assign.cc b/source/blender/nodes/geometry/nodes/node_geo_material_assign.cc
index 43818947272..780994996ae 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_material_assign.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_material_assign.cc
@@ -30,7 +30,7 @@ static void geo_node_material_assign_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Material>("Material").hide_label();
- b.add_input<decl::Bool>("Selection").default_value(true).hide_value();
+ b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
b.add_output<decl::Geometry>("Geometry");
}
@@ -64,23 +64,22 @@ static void geo_node_material_assign_exec(GeoNodeExecParams params)
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (geometry_set.has<MeshComponent>()) {
+ 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};
- if (geometry_set.has<MeshComponent>()) {
- MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
- Mesh *mesh = mesh_component.get_for_write();
- if (mesh != nullptr) {
+ 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);
- 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);
-
- assign_material_to_faces(*mesh, selection, material);
+ assign_material_to_faces(*mesh, selection, material);
+ }
}
- }
+ });
params.set_output("Geometry", std::move(geometry_set));
}
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 a9c3bfc6ce0..a917434fa00 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc
@@ -40,11 +40,9 @@ static void geo_node_material_replace_exec(GeoNodeExecParams params)
Material *new_material = params.extract_input<Material *>("New");
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
- if (geometry_set.has<MeshComponent>()) {
- MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
- Mesh *mesh = mesh_component.get_for_write();
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ Mesh *mesh = geometry_set.get_mesh_for_write();
if (mesh != nullptr) {
for (const int i : IndexRange(mesh->totcol)) {
if (mesh->mat[i] == old_material) {
@@ -52,7 +50,7 @@ static void geo_node_material_replace_exec(GeoNodeExecParams params)
}
}
}
- }
+ });
params.set_output("Geometry", std::move(geometry_set));
}
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 22c24e34314..9d4533b9bda 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
@@ -31,7 +31,7 @@ namespace blender::nodes {
static void geo_node_material_selection_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Material>("Material").hide_label(true);
- b.add_output<decl::Bool>("Selection");
+ b.add_output<decl::Bool>("Selection").field_source();
}
static void select_mesh_by_material(const Mesh &mesh,
@@ -100,13 +100,16 @@ class MaterialSelectionFieldInput final : public fn::FieldInput {
uint64_t hash() const override
{
- /* Some random constant hash. */
- return 91619626;
+ return get_default_hash(material_);
}
bool is_equal_to(const fn::FieldNode &other) const override
{
- return dynamic_cast<const MaterialSelectionFieldInput *>(&other) != nullptr;
+ if (const MaterialSelectionFieldInput *other_material_selection =
+ dynamic_cast<const MaterialSelectionFieldInput *>(&other)) {
+ return material_ == other_material_selection->material_;
+ }
+ return false;
}
};
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 0d58476fc58..059e6e8680c 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,13 +29,38 @@ namespace blender::nodes {
static void geo_node_mesh_primitive_cone_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Int>("Vertices").default_value(32).min(3);
+ b.add_input<decl::Int>("Vertices").default_value(32).min(3).max(512);
+ b.add_input<decl::Int>("Side Segments").default_value(1).min(1).max(512);
+ b.add_input<decl::Int>("Fill Segments").default_value(1).min(1).max(512);
b.add_input<decl::Float>("Radius Top").min(0.0f).subtype(PROP_DISTANCE);
b.add_input<decl::Float>("Radius Bottom").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
b.add_input<decl::Float>("Depth").default_value(2.0f).min(0.0f).subtype(PROP_DISTANCE);
b.add_output<decl::Geometry>("Geometry");
}
+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 *UNUSED(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(fill_subdiv_socket, has_fill);
+}
+
static void geo_node_mesh_primitive_cone_layout(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
@@ -45,493 +70,632 @@ static void geo_node_mesh_primitive_cone_layout(uiLayout *layout,
uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE);
}
-static void geo_node_mesh_primitive_cone_init(bNodeTree *UNUSED(ntree), bNode *node)
+struct ConeConfig {
+ float radius_top;
+ float radius_bottom;
+ float height;
+ int circle_segments;
+ int side_segments;
+ int fill_segments;
+ GeometryNodeMeshCircleFillType fill_type;
+
+ bool top_is_point;
+ bool bottom_is_point;
+ /* The cone tip and a triangle fan filling are topologically identical.
+ * This simplifies the logic in some cases. */
+ bool top_has_center_vert;
+ bool bottom_has_center_vert;
+
+ /* Helpful quantities. */
+ int tot_quad_rings;
+ int tot_edge_rings;
+ int tot_verts;
+ int tot_edges;
+
+ /* Helpful vertex indices. */
+ int first_vert;
+ int first_ring_verts_start;
+ int last_ring_verts_start;
+ int last_vert;
+
+ /* Helpful edge indices. */
+ int first_ring_edges_start;
+ int last_ring_edges_start;
+ int last_fan_edges_start;
+ int last_edge;
+
+ ConeConfig(float radius_top,
+ float radius_bottom,
+ float depth,
+ int circle_segments,
+ int side_segments,
+ int fill_segments,
+ GeometryNodeMeshCircleFillType fill_type)
+ : radius_top(radius_top),
+ radius_bottom(radius_bottom),
+ height(0.5f * depth),
+ circle_segments(circle_segments),
+ side_segments(side_segments),
+ fill_segments(fill_segments),
+ fill_type(fill_type)
+ {
+ this->top_is_point = this->radius_top == 0.0f;
+ this->bottom_is_point = this->radius_bottom == 0.0f;
+ this->top_has_center_vert = this->top_is_point ||
+ this->fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN;
+ this->bottom_has_center_vert = this->bottom_is_point ||
+ this->fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN;
+
+ this->tot_quad_rings = this->calculate_total_quad_rings();
+ this->tot_edge_rings = this->calculate_total_edge_rings();
+ this->tot_verts = this->calculate_total_verts();
+ this->tot_edges = this->calculate_total_edges();
+
+ this->first_vert = 0;
+ this->first_ring_verts_start = this->top_has_center_vert ? 1 : first_vert;
+ this->last_vert = this->tot_verts - 1;
+ this->last_ring_verts_start = this->last_vert - this->circle_segments;
+
+ this->first_ring_edges_start = this->top_has_center_vert ? this->circle_segments : 0;
+ this->last_ring_edges_start = this->first_ring_edges_start +
+ this->tot_quad_rings * this->circle_segments * 2;
+ this->last_fan_edges_start = this->tot_edges - this->circle_segments;
+ this->last_edge = this->tot_edges - 1;
+ }
+
+ private:
+ int calculate_total_quad_rings();
+ int calculate_total_edge_rings();
+ int calculate_total_verts();
+ int calculate_total_edges();
+
+ public:
+ int get_tot_corners() const;
+ int get_tot_faces() const;
+};
+
+int ConeConfig::calculate_total_quad_rings()
{
- NodeGeometryMeshCone *node_storage = (NodeGeometryMeshCone *)MEM_callocN(
- sizeof(NodeGeometryMeshCone), __func__);
+ if (top_is_point && bottom_is_point) {
+ return 0;
+ }
- node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NGON;
+ int quad_rings = 0;
- node->storage = node_storage;
+ if (!top_is_point) {
+ quad_rings += fill_segments - 1;
+ }
+
+ quad_rings += (!top_is_point && !bottom_is_point) ? side_segments : (side_segments - 1);
+
+ if (!bottom_is_point) {
+ quad_rings += fill_segments - 1;
+ }
+
+ return quad_rings;
}
-static int vert_total(const GeometryNodeMeshCircleFillType fill_type,
- const int verts_num,
- const bool top_is_point,
- const bool bottom_is_point)
+int ConeConfig::calculate_total_edge_rings()
{
- int vert_total = 0;
+ if (top_is_point && bottom_is_point) {
+ return 0;
+ }
+
+ int edge_rings = 0;
+
if (!top_is_point) {
- vert_total += verts_num;
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- vert_total++;
- }
+ edge_rings += fill_segments;
}
- else {
+
+ edge_rings += side_segments - 1;
+
+ if (!bottom_is_point) {
+ edge_rings += fill_segments;
+ }
+
+ return edge_rings;
+}
+
+int ConeConfig::calculate_total_verts()
+{
+ if (top_is_point && bottom_is_point) {
+ return side_segments + 1;
+ }
+
+ int vert_total = 0;
+
+ if (top_has_center_vert) {
vert_total++;
}
+
+ if (!top_is_point) {
+ vert_total += circle_segments * fill_segments;
+ }
+
+ vert_total += circle_segments * (side_segments - 1);
+
if (!bottom_is_point) {
- vert_total += verts_num;
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- vert_total++;
- }
+ vert_total += circle_segments * fill_segments;
}
- else {
+
+ if (bottom_has_center_vert) {
vert_total++;
}
return vert_total;
}
-static int edge_total(const GeometryNodeMeshCircleFillType fill_type,
- const int verts_num,
- const bool top_is_point,
- const bool bottom_is_point)
+int ConeConfig::calculate_total_edges()
{
if (top_is_point && bottom_is_point) {
- return 1;
+ return side_segments;
}
int edge_total = 0;
- if (!top_is_point) {
- edge_total += verts_num;
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- edge_total += verts_num;
- }
+ if (top_has_center_vert) {
+ edge_total += circle_segments;
}
- edge_total += verts_num;
+ edge_total += circle_segments * (tot_quad_rings * 2 + 1);
- if (!bottom_is_point) {
- edge_total += verts_num;
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- edge_total += verts_num;
- }
+ if (bottom_has_center_vert) {
+ edge_total += circle_segments;
}
return edge_total;
}
-static int corner_total(const GeometryNodeMeshCircleFillType fill_type,
- const int verts_num,
- const bool top_is_point,
- const bool bottom_is_point)
+int ConeConfig::get_tot_corners() const
{
if (top_is_point && bottom_is_point) {
return 0;
}
int corner_total = 0;
- if (!top_is_point) {
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
- corner_total += verts_num;
- }
- else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- corner_total += verts_num * 3;
- }
- }
- if (!top_is_point && !bottom_is_point) {
- corner_total += verts_num * 4;
+ if (top_has_center_vert) {
+ corner_total += (circle_segments * 3);
}
- else {
- corner_total += verts_num * 3;
+ else if (!top_is_point && fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
+ corner_total += circle_segments;
}
- if (!bottom_is_point) {
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
- corner_total += verts_num;
- }
- else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- corner_total += verts_num * 3;
- }
+ corner_total += tot_quad_rings * (circle_segments * 4);
+
+ if (bottom_has_center_vert) {
+ corner_total += (circle_segments * 3);
+ }
+ else if (!bottom_is_point && fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
+ corner_total += circle_segments;
}
return corner_total;
}
-static int face_total(const GeometryNodeMeshCircleFillType fill_type,
- const int verts_num,
- const bool top_is_point,
- const bool bottom_is_point)
+int ConeConfig::get_tot_faces() const
{
if (top_is_point && bottom_is_point) {
return 0;
}
int face_total = 0;
- if (!top_is_point) {
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
- face_total++;
- }
- else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- face_total += verts_num;
- }
+ if (top_has_center_vert) {
+ face_total += circle_segments;
+ }
+ else if (!top_is_point && fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
+ face_total++;
}
- face_total += verts_num;
+ face_total += tot_quad_rings * circle_segments;
- if (!bottom_is_point) {
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
- face_total++;
- }
- else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- face_total += verts_num;
- }
+ if (bottom_has_center_vert) {
+ face_total += circle_segments;
+ }
+ else if (!bottom_is_point && fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
+ face_total++;
}
return face_total;
}
-static void calculate_uvs(Mesh *mesh,
- const bool top_is_point,
- const bool bottom_is_point,
- const int verts_num,
- const GeometryNodeMeshCircleFillType fill_type)
+static void calculate_cone_vertices(const MutableSpan<MVert> &verts, const ConeConfig &config)
{
- MeshComponent mesh_component;
- mesh_component.replace(mesh, GeometryOwnershipType::Editable);
- OutputAttribute_Typed<float2> uv_attribute =
- mesh_component.attribute_try_get_for_output_only<float2>("uv_map", ATTR_DOMAIN_CORNER);
- MutableSpan<float2> uvs = uv_attribute.as_span();
-
- Array<float2> circle(verts_num);
+ Array<float2> circle(config.circle_segments);
+ const float angle_delta = 2.0f * (M_PI / static_cast<float>(config.circle_segments));
float angle = 0.0f;
- const float angle_delta = 2.0f * M_PI / static_cast<float>(verts_num);
- for (const int i : IndexRange(verts_num)) {
- circle[i].x = std::cos(angle) * 0.225f + 0.25f;
- circle[i].y = std::sin(angle) * 0.225f + 0.25f;
+ for (const int i : IndexRange(config.circle_segments)) {
+ circle[i].x = std::cos(angle);
+ circle[i].y = std::sin(angle);
angle += angle_delta;
}
- int loop_index = 0;
- if (!top_is_point) {
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
- for (const int i : IndexRange(verts_num)) {
- uvs[loop_index++] = circle[i];
- }
- }
- else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- for (const int i : IndexRange(verts_num)) {
- uvs[loop_index++] = circle[i];
- uvs[loop_index++] = circle[(i + 1) % verts_num];
- uvs[loop_index++] = float2(0.25f, 0.25f);
- }
- }
- }
+ int vert_index = 0;
- /* Create side corners and faces. */
- if (!top_is_point && !bottom_is_point) {
- const float bottom = (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NONE) ? 0.0f : 0.5f;
- /* Quads connect the top and bottom. */
- for (const int i : IndexRange(verts_num)) {
- const float vert = static_cast<float>(i);
- uvs[loop_index++] = float2(vert / verts_num, bottom);
- uvs[loop_index++] = float2(vert / verts_num, 1.0f);
- uvs[loop_index++] = float2((vert + 1.0f) / verts_num, 1.0f);
- uvs[loop_index++] = float2((vert + 1.0f) / verts_num, bottom);
- }
+ /* Top cone tip or triangle fan center. */
+ if (config.top_has_center_vert) {
+ copy_v3_fl3(verts[vert_index++].co, 0.0f, 0.0f, config.height);
}
- else {
- /* Triangles connect the top and bottom section. */
- if (!top_is_point) {
- for (const int i : IndexRange(verts_num)) {
- uvs[loop_index++] = circle[i] + float2(0.5f, 0.0f);
- uvs[loop_index++] = float2(0.75f, 0.25f);
- uvs[loop_index++] = circle[(i + 1) % verts_num] + float2(0.5f, 0.0f);
- }
- }
- else {
- BLI_assert(!bottom_is_point);
- for (const int i : IndexRange(verts_num)) {
- uvs[loop_index++] = circle[i];
- uvs[loop_index++] = circle[(i + 1) % verts_num];
- uvs[loop_index++] = float2(0.25f, 0.25f);
+
+ /* Top fill including the outer edge of the fill. */
+ if (!config.top_is_point) {
+ const float top_fill_radius_delta = config.radius_top /
+ static_cast<float>(config.fill_segments);
+ for (const int i : IndexRange(config.fill_segments)) {
+ const float top_fill_radius = top_fill_radius_delta * (i + 1);
+ for (const int j : IndexRange(config.circle_segments)) {
+ const float x = circle[j].x * top_fill_radius;
+ const float y = circle[j].y * top_fill_radius;
+ copy_v3_fl3(verts[vert_index++].co, x, y, config.height);
}
}
}
- /* Create bottom corners and faces. */
- if (!bottom_is_point) {
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
- for (const int i : IndexRange(verts_num)) {
- /* Go backwards because of reversed face normal. */
- uvs[loop_index++] = circle[verts_num - 1 - i] + float2(0.5f, 0.0f);
- }
+ /* Rings along the side. */
+ const float side_radius_delta = (config.radius_bottom - config.radius_top) /
+ static_cast<float>(config.side_segments);
+ const float height_delta = 2.0f * config.height / static_cast<float>(config.side_segments);
+ for (const int i : IndexRange(config.side_segments - 1)) {
+ const float ring_radius = config.radius_top + (side_radius_delta * (i + 1));
+ const float ring_height = config.height - (height_delta * (i + 1));
+ for (const int j : IndexRange(config.circle_segments)) {
+ const float x = circle[j].x * ring_radius;
+ const float y = circle[j].y * ring_radius;
+ copy_v3_fl3(verts[vert_index++].co, x, y, ring_height);
}
- else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- for (const int i : IndexRange(verts_num)) {
- uvs[loop_index++] = circle[i] + float2(0.5f, 0.0f);
- uvs[loop_index++] = float2(0.75f, 0.25f);
- uvs[loop_index++] = circle[(i + 1) % verts_num] + float2(0.5f, 0.0f);
+ }
+
+ /* Bottom fill including the outer edge of the fill. */
+ if (!config.bottom_is_point) {
+ const float bottom_fill_radius_delta = config.radius_bottom /
+ static_cast<float>(config.fill_segments);
+ for (const int i : IndexRange(config.fill_segments)) {
+ const float bottom_fill_radius = config.radius_bottom - (i * bottom_fill_radius_delta);
+ for (const int j : IndexRange(config.circle_segments)) {
+ const float x = circle[j].x * bottom_fill_radius;
+ const float y = circle[j].y * bottom_fill_radius;
+ copy_v3_fl3(verts[vert_index++].co, x, y, -config.height);
}
}
}
- uv_attribute.save();
+ /* Bottom cone tip or triangle fan center. */
+ if (config.bottom_has_center_vert) {
+ copy_v3_fl3(verts[vert_index++].co, 0.0f, 0.0f, -config.height);
+ }
}
-Mesh *create_cylinder_or_cone_mesh(const float radius_top,
- const float radius_bottom,
- const float depth,
- const int verts_num,
- const GeometryNodeMeshCircleFillType fill_type)
+static void calculate_cone_edges(const MutableSpan<MEdge> &edges, const ConeConfig &config)
{
- const bool top_is_point = radius_top == 0.0f;
- const bool bottom_is_point = radius_bottom == 0.0f;
- const float height = depth * 0.5f;
- /* Handle the case of a line / single point before everything else to avoid
- * the need to check for it later. */
- if (top_is_point && bottom_is_point) {
- const bool single_vertex = height == 0.0f;
- Mesh *mesh = BKE_mesh_new_nomain(single_vertex ? 1 : 2, single_vertex ? 0 : 1, 0, 0, 0);
- copy_v3_v3(mesh->mvert[0].co, float3(0.0f, 0.0f, height));
- if (single_vertex) {
- const short up[3] = {0, 0, SHRT_MAX};
- copy_v3_v3_short(mesh->mvert[0].no, up);
- return mesh;
- }
- copy_v3_v3(mesh->mvert[1].co, float3(0.0f, 0.0f, -height));
- mesh->medge[0].v1 = 0;
- mesh->medge[0].v2 = 1;
- mesh->medge[0].flag |= ME_LOOSEEDGE;
- BKE_mesh_normals_tag_dirty(mesh);
- return mesh;
- }
-
- Mesh *mesh = BKE_mesh_new_nomain(
- vert_total(fill_type, verts_num, top_is_point, bottom_is_point),
- edge_total(fill_type, verts_num, top_is_point, bottom_is_point),
- 0,
- corner_total(fill_type, verts_num, top_is_point, bottom_is_point),
- face_total(fill_type, verts_num, top_is_point, bottom_is_point));
- BKE_id_material_eval_ensure_default_slot(&mesh->id);
- MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
- MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop};
- MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
- MutableSpan<MPoly> polys{mesh->mpoly, mesh->totpoly};
-
- /* Calculate vertex positions. */
- const int top_verts_start = 0;
- const int bottom_verts_start = top_verts_start + (!top_is_point ? verts_num : 1);
- const float angle_delta = 2.0f * (M_PI / static_cast<float>(verts_num));
- for (const int i : IndexRange(verts_num)) {
- const float angle = i * angle_delta;
- const float x = std::cos(angle);
- const float y = std::sin(angle);
- if (!top_is_point) {
- copy_v3_v3(verts[top_verts_start + i].co, float3(x * radius_top, y * radius_top, height));
- }
- if (!bottom_is_point) {
- copy_v3_v3(verts[bottom_verts_start + i].co,
- float3(x * radius_bottom, y * radius_bottom, -height));
+ int edge_index = 0;
+
+ /* Edges for top cone tip or triangle fan */
+ if (config.top_has_center_vert) {
+ for (const int i : IndexRange(config.circle_segments)) {
+ MEdge &edge = edges[edge_index++];
+ edge.v1 = config.first_vert;
+ edge.v2 = config.first_ring_verts_start + i;
+ edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
}
}
- if (top_is_point) {
- copy_v3_v3(verts[top_verts_start].co, float3(0.0f, 0.0f, height));
- }
- if (bottom_is_point) {
- copy_v3_v3(verts[bottom_verts_start].co, float3(0.0f, 0.0f, -height));
- }
- /* Add center vertices for the triangle fans at the end. */
- const int top_center_vert_index = bottom_verts_start + (bottom_is_point ? 1 : verts_num);
- const int bottom_center_vert_index = top_center_vert_index + (top_is_point ? 0 : 1);
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- if (!top_is_point) {
- copy_v3_v3(verts[top_center_vert_index].co, float3(0.0f, 0.0f, height));
+ /* Rings and connecting edges between the rings. */
+ for (const int i : IndexRange(config.tot_edge_rings)) {
+ const int this_ring_vert_start = config.first_ring_verts_start + (i * config.circle_segments);
+ const int next_ring_vert_start = this_ring_vert_start + config.circle_segments;
+ /* Edge rings. */
+ for (const int j : IndexRange(config.circle_segments)) {
+ MEdge &edge = edges[edge_index++];
+ edge.v1 = this_ring_vert_start + j;
+ edge.v2 = this_ring_vert_start + ((j + 1) % config.circle_segments);
+ edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
}
- if (!bottom_is_point) {
- copy_v3_v3(verts[bottom_center_vert_index].co, float3(0.0f, 0.0f, -height));
+ if (i == config.tot_edge_rings - 1) {
+ /* There is one fewer ring of connecting edges. */
+ break;
}
- }
-
- /* Create top edges. */
- const int top_edges_start = 0;
- const int top_fan_edges_start = (!top_is_point &&
- fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) ?
- top_edges_start + verts_num :
- top_edges_start;
- if (!top_is_point) {
- for (const int i : IndexRange(verts_num)) {
- MEdge &edge = edges[top_edges_start + i];
- edge.v1 = top_verts_start + i;
- edge.v2 = top_verts_start + (i + 1) % verts_num;
+ /* Connecting edges. */
+ for (const int j : IndexRange(config.circle_segments)) {
+ MEdge &edge = edges[edge_index++];
+ edge.v1 = this_ring_vert_start + j;
+ edge.v2 = next_ring_vert_start + j;
edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
}
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- for (const int i : IndexRange(verts_num)) {
- MEdge &edge = edges[top_fan_edges_start + i];
- edge.v1 = top_center_vert_index;
- edge.v2 = top_verts_start + i;
- edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
- }
- }
}
- /* Create connecting edges. */
- const int connecting_edges_start = top_fan_edges_start + (!top_is_point ? verts_num : 0);
- for (const int i : IndexRange(verts_num)) {
- MEdge &edge = edges[connecting_edges_start + i];
- edge.v1 = top_verts_start + (!top_is_point ? i : 0);
- edge.v2 = bottom_verts_start + (!bottom_is_point ? i : 0);
- edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
- }
-
- /* Create bottom edges. */
- const int bottom_edges_start = connecting_edges_start + verts_num;
- const int bottom_fan_edges_start = (!bottom_is_point &&
- fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) ?
- bottom_edges_start + verts_num :
- bottom_edges_start;
- if (!bottom_is_point) {
- for (const int i : IndexRange(verts_num)) {
- MEdge &edge = edges[bottom_edges_start + i];
- edge.v1 = bottom_verts_start + i;
- edge.v2 = bottom_verts_start + (i + 1) % verts_num;
+ /* Edges for bottom triangle fan or tip. */
+ if (config.bottom_has_center_vert) {
+ for (const int i : IndexRange(config.circle_segments)) {
+ MEdge &edge = edges[edge_index++];
+ edge.v1 = config.last_ring_verts_start + i;
+ edge.v2 = config.last_vert;
edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
}
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- for (const int i : IndexRange(verts_num)) {
- MEdge &edge = edges[bottom_fan_edges_start + i];
- edge.v1 = bottom_center_vert_index;
- edge.v2 = bottom_verts_start + i;
- edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
- }
- }
}
+}
- /* Create top corners and faces. */
+static void calculate_cone_faces(const MutableSpan<MLoop> &loops,
+ const MutableSpan<MPoly> &polys,
+ const ConeConfig &config)
+{
int loop_index = 0;
int poly_index = 0;
- if (!top_is_point) {
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
+
+ if (config.top_has_center_vert) {
+ /* Top cone tip or center triangle fan in the fill. */
+ const int top_center_vert = 0;
+ const int top_fan_edges_start = 0;
+
+ for (const int i : IndexRange(config.circle_segments)) {
MPoly &poly = polys[poly_index++];
poly.loopstart = loop_index;
- poly.totloop = verts_num;
+ poly.totloop = 3;
- for (const int i : IndexRange(verts_num)) {
- MLoop &loop = loops[loop_index++];
- loop.v = top_verts_start + i;
- loop.e = top_edges_start + i;
- }
+ MLoop &loop_a = loops[loop_index++];
+ loop_a.v = config.first_ring_verts_start + i;
+ loop_a.e = config.first_ring_edges_start + i;
+ MLoop &loop_b = loops[loop_index++];
+ loop_b.v = config.first_ring_verts_start + ((i + 1) % config.circle_segments);
+ loop_b.e = top_fan_edges_start + ((i + 1) % config.circle_segments);
+ MLoop &loop_c = loops[loop_index++];
+ loop_c.v = top_center_vert;
+ loop_c.e = top_fan_edges_start + i;
}
- else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- for (const int i : IndexRange(verts_num)) {
+ }
+ else if (config.fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
+ /* Center n-gon in the fill. */
+ MPoly &poly = polys[poly_index++];
+ poly.loopstart = loop_index;
+ poly.totloop = config.circle_segments;
+ for (const int i : IndexRange(config.circle_segments)) {
+ MLoop &loop = loops[loop_index++];
+ loop.v = i;
+ loop.e = i;
+ }
+ }
+
+ /* Quads connect one edge ring to the next one. */
+ if (config.tot_quad_rings > 0) {
+ for (const int i : IndexRange(config.tot_quad_rings)) {
+ const int this_ring_vert_start = config.first_ring_verts_start +
+ (i * config.circle_segments);
+ const int next_ring_vert_start = this_ring_vert_start + config.circle_segments;
+
+ const int this_ring_edges_start = config.first_ring_edges_start +
+ (i * 2 * config.circle_segments);
+ const int next_ring_edges_start = this_ring_edges_start + (2 * config.circle_segments);
+ const int ring_connections_start = this_ring_edges_start + config.circle_segments;
+
+ for (const int j : IndexRange(config.circle_segments)) {
MPoly &poly = polys[poly_index++];
poly.loopstart = loop_index;
- poly.totloop = 3;
+ poly.totloop = 4;
MLoop &loop_a = loops[loop_index++];
- loop_a.v = top_verts_start + i;
- loop_a.e = top_edges_start + i;
+ loop_a.v = this_ring_vert_start + j;
+ loop_a.e = ring_connections_start + j;
MLoop &loop_b = loops[loop_index++];
- loop_b.v = top_verts_start + (i + 1) % verts_num;
- loop_b.e = top_fan_edges_start + (i + 1) % verts_num;
+ loop_b.v = next_ring_vert_start + j;
+ loop_b.e = next_ring_edges_start + j;
MLoop &loop_c = loops[loop_index++];
- loop_c.v = top_center_vert_index;
- loop_c.e = top_fan_edges_start + i;
+ loop_c.v = next_ring_vert_start + ((j + 1) % config.circle_segments);
+ loop_c.e = ring_connections_start + ((j + 1) % config.circle_segments);
+ MLoop &loop_d = loops[loop_index++];
+ loop_d.v = this_ring_vert_start + ((j + 1) % config.circle_segments);
+ loop_d.e = this_ring_edges_start + j;
}
}
}
- /* Create side corners and faces. */
- if (!top_is_point && !bottom_is_point) {
- /* Quads connect the top and bottom. */
- for (const int i : IndexRange(verts_num)) {
+ if (config.bottom_has_center_vert) {
+ /* Bottom cone tip or center triangle fan in the fill. */
+ for (const int i : IndexRange(config.circle_segments)) {
MPoly &poly = polys[poly_index++];
poly.loopstart = loop_index;
- poly.totloop = 4;
+ poly.totloop = 3;
MLoop &loop_a = loops[loop_index++];
- loop_a.v = top_verts_start + i;
- loop_a.e = connecting_edges_start + i;
+ loop_a.v = config.last_ring_verts_start + i;
+ loop_a.e = config.last_fan_edges_start + i;
MLoop &loop_b = loops[loop_index++];
- loop_b.v = bottom_verts_start + i;
- loop_b.e = bottom_edges_start + i;
+ loop_b.v = config.last_vert;
+ loop_b.e = config.last_fan_edges_start + (i + 1) % config.circle_segments;
MLoop &loop_c = loops[loop_index++];
- loop_c.v = bottom_verts_start + (i + 1) % verts_num;
- loop_c.e = connecting_edges_start + (i + 1) % verts_num;
- MLoop &loop_d = loops[loop_index++];
- loop_d.v = top_verts_start + (i + 1) % verts_num;
- loop_d.e = top_edges_start + i;
+ loop_c.v = config.last_ring_verts_start + (i + 1) % config.circle_segments;
+ loop_c.e = config.last_ring_edges_start + i;
}
}
- else {
- /* Triangles connect the top and bottom section. */
- if (!top_is_point) {
- for (const int i : IndexRange(verts_num)) {
- MPoly &poly = polys[poly_index++];
- poly.loopstart = loop_index;
- poly.totloop = 3;
+ else if (config.fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
+ /* Center n-gon in the fill. */
+ MPoly &poly = polys[poly_index++];
+ poly.loopstart = loop_index;
+ poly.totloop = config.circle_segments;
- MLoop &loop_a = loops[loop_index++];
- loop_a.v = top_verts_start + i;
- loop_a.e = connecting_edges_start + i;
- MLoop &loop_b = loops[loop_index++];
- loop_b.v = bottom_verts_start;
- loop_b.e = connecting_edges_start + (i + 1) % verts_num;
- MLoop &loop_c = loops[loop_index++];
- loop_c.v = top_verts_start + (i + 1) % verts_num;
- loop_c.e = top_edges_start + i;
- }
+ for (const int i : IndexRange(config.circle_segments)) {
+ /* Go backwards to reverse surface normal. */
+ MLoop &loop = loops[loop_index++];
+ loop.v = config.last_vert - i;
+ loop.e = config.last_edge - ((i + 1) % config.circle_segments);
}
- else {
- BLI_assert(!bottom_is_point);
- for (const int i : IndexRange(verts_num)) {
- MPoly &poly = polys[poly_index++];
- poly.loopstart = loop_index;
- poly.totloop = 3;
+ }
+}
- MLoop &loop_a = loops[loop_index++];
- loop_a.v = bottom_verts_start + i;
- loop_a.e = bottom_edges_start + i;
- MLoop &loop_b = loops[loop_index++];
- loop_b.v = bottom_verts_start + (i + 1) % verts_num;
- loop_b.e = connecting_edges_start + (i + 1) % verts_num;
- MLoop &loop_c = loops[loop_index++];
- loop_c.v = top_verts_start;
- loop_c.e = connecting_edges_start + i;
+/**
+ * If the top is the cone tip or has a fill, it is unwrapped into a circle in the
+ * lower left quadrant of the UV.
+ * Likewise, if the bottom is the cone tip or has a fill, it is unwrapped into a circle
+ * in the lower right quadrant of the UV.
+ * If the mesh is a truncated cone or a cylinder, the side faces are unwrapped into
+ * a rectangle that fills the top half of the UV (or the entire UV, if there are no fills).
+ */
+static void calculate_cone_uvs(Mesh *mesh, const ConeConfig &config)
+{
+ MeshComponent mesh_component;
+ mesh_component.replace(mesh, GeometryOwnershipType::Editable);
+ OutputAttribute_Typed<float2> uv_attribute =
+ mesh_component.attribute_try_get_for_output_only<float2>("uv_map", ATTR_DOMAIN_CORNER);
+ MutableSpan<float2> uvs = uv_attribute.as_span();
+
+ Array<float2> circle(config.circle_segments);
+ float angle = 0.0f;
+ const float angle_delta = 2.0f * M_PI / static_cast<float>(config.circle_segments);
+ for (const int i : IndexRange(config.circle_segments)) {
+ circle[i].x = std::cos(angle) * 0.225f;
+ circle[i].y = std::sin(angle) * 0.225f;
+ angle += angle_delta;
+ }
+
+ int loop_index = 0;
+
+ /* Left circle of the UV representing the top fill or top cone tip. */
+ if (config.top_is_point || config.fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE) {
+ const float2 center_left(0.25f, 0.25f);
+ const float radius_factor_delta = 1.0f / (config.top_is_point ?
+ static_cast<float>(config.side_segments) :
+ static_cast<float>(config.fill_segments));
+ const int left_circle_segment_count = config.top_is_point ? config.side_segments :
+ config.fill_segments;
+
+ if (config.top_has_center_vert) {
+ /* Cone tip itself or triangle fan center of the fill. */
+ for (const int i : IndexRange(config.circle_segments)) {
+ uvs[loop_index++] = radius_factor_delta * circle[i] + center_left;
+ uvs[loop_index++] = radius_factor_delta * circle[(i + 1) % config.circle_segments] +
+ center_left;
+ uvs[loop_index++] = center_left;
+ }
+ }
+ else if (!config.top_is_point && config.fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
+ /* N-gon at the center of the fill. */
+ for (const int i : IndexRange(config.circle_segments)) {
+ uvs[loop_index++] = radius_factor_delta * circle[i] + center_left;
+ }
+ }
+ /* The rest of the top fill is made out of quad rings. */
+ for (const int i : IndexRange(1, left_circle_segment_count - 1)) {
+ const float inner_radius_factor = i * radius_factor_delta;
+ const float outer_radius_factor = (i + 1) * radius_factor_delta;
+ for (const int j : IndexRange(config.circle_segments)) {
+ uvs[loop_index++] = inner_radius_factor * circle[j] + center_left;
+ uvs[loop_index++] = outer_radius_factor * circle[j] + center_left;
+ uvs[loop_index++] = outer_radius_factor * circle[(j + 1) % config.circle_segments] +
+ center_left;
+ uvs[loop_index++] = inner_radius_factor * circle[(j + 1) % config.circle_segments] +
+ center_left;
}
}
}
- /* Create bottom corners and faces. */
- if (!bottom_is_point) {
- if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
- MPoly &poly = polys[poly_index++];
- poly.loopstart = loop_index;
- poly.totloop = verts_num;
+ if (!config.top_is_point && !config.bottom_is_point) {
+ /* Mesh is a truncated cone or cylinder. The sides are unwrapped into a rectangle. */
+ const float bottom = (config.fill_type == GEO_NODE_MESH_CIRCLE_FILL_NONE) ? 0.0f : 0.5f;
+ const float x_delta = 1.0f / static_cast<float>(config.circle_segments);
+ const float y_delta = (1.0f - bottom) / static_cast<float>(config.side_segments);
- for (const int i : IndexRange(verts_num)) {
- /* Go backwards to reverse surface normal. */
- MLoop &loop = loops[loop_index++];
- loop.v = bottom_verts_start + verts_num - 1 - i;
- loop.e = bottom_edges_start + verts_num - 1 - (i + 1) % verts_num;
+ for (const int i : IndexRange(config.side_segments)) {
+ for (const int j : IndexRange(config.circle_segments)) {
+ uvs[loop_index++] = float2(j * x_delta, i * y_delta + bottom);
+ uvs[loop_index++] = float2(j * x_delta, (i + 1) * y_delta + bottom);
+ uvs[loop_index++] = float2((j + 1) * x_delta, (i + 1) * y_delta + bottom);
+ uvs[loop_index++] = float2((j + 1) * x_delta, i * y_delta + bottom);
}
}
- else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
- for (const int i : IndexRange(verts_num)) {
- MPoly &poly = polys[poly_index++];
- poly.loopstart = loop_index;
- poly.totloop = 3;
+ }
- MLoop &loop_a = loops[loop_index++];
- loop_a.v = bottom_verts_start + i;
- loop_a.e = bottom_fan_edges_start + i;
- MLoop &loop_b = loops[loop_index++];
- loop_b.v = bottom_center_vert_index;
- loop_b.e = bottom_fan_edges_start + (i + 1) % verts_num;
- MLoop &loop_c = loops[loop_index++];
- loop_c.v = bottom_verts_start + (i + 1) % verts_num;
- loop_c.e = bottom_edges_start + i;
+ /* Right circle of the UV representing the bottom fill or bottom cone tip. */
+ if (config.bottom_is_point || config.fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE) {
+ const float2 center_right(0.75f, 0.25f);
+ const float radius_factor_delta = 1.0f / (config.bottom_is_point ?
+ static_cast<float>(config.side_segments) :
+ static_cast<float>(config.fill_segments));
+ const int right_circle_segment_count = config.bottom_is_point ? config.side_segments :
+ config.fill_segments;
+
+ /* The bottom circle has to be created outside in to match the loop order. */
+ for (const int i : IndexRange(right_circle_segment_count - 1)) {
+ const float outer_radius_factor = 1.0f - i * radius_factor_delta;
+ const float inner_radius_factor = 1.0f - (i + 1) * radius_factor_delta;
+ for (const int j : IndexRange(config.circle_segments)) {
+ uvs[loop_index++] = outer_radius_factor * circle[j] + center_right;
+ uvs[loop_index++] = inner_radius_factor * circle[j] + center_right;
+ uvs[loop_index++] = inner_radius_factor * circle[(j + 1) % config.circle_segments] +
+ center_right;
+ uvs[loop_index++] = outer_radius_factor * circle[(j + 1) % config.circle_segments] +
+ center_right;
+ }
+ }
+
+ if (config.bottom_has_center_vert) {
+ /* Cone tip itself or triangle fan center of the fill. */
+ for (const int i : IndexRange(config.circle_segments)) {
+ uvs[loop_index++] = radius_factor_delta * circle[i] + center_right;
+ uvs[loop_index++] = center_right;
+ uvs[loop_index++] = radius_factor_delta * circle[(i + 1) % config.circle_segments] +
+ center_right;
+ }
+ }
+ else if (!config.bottom_is_point && config.fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
+ /* N-gon at the center of the fill. */
+ for (const int i : IndexRange(config.circle_segments)) {
+ /* Go backwards because of reversed face normal. */
+ uvs[loop_index++] = radius_factor_delta * circle[config.circle_segments - 1 - i] +
+ center_right;
}
}
}
+ uv_attribute.save();
+}
+
+static Mesh *create_vertex_mesh()
+{
+ /* Returns a mesh with a single vertex at the origin. */
+ Mesh *mesh = BKE_mesh_new_nomain(1, 0, 0, 0, 0);
+ copy_v3_fl3(mesh->mvert[0].co, 0.0f, 0.0f, 0.0f);
+ const short up[3] = {0, 0, SHRT_MAX};
+ copy_v3_v3_short(mesh->mvert[0].no, up);
+ return mesh;
+}
+
+Mesh *create_cylinder_or_cone_mesh(const float radius_top,
+ const float radius_bottom,
+ const float depth,
+ const int circle_segments,
+ const int side_segments,
+ const int fill_segments,
+ const GeometryNodeMeshCircleFillType fill_type)
+{
+ const ConeConfig config(
+ radius_top, radius_bottom, depth, circle_segments, side_segments, fill_segments, fill_type);
+
+ /* Handle the case of a line / single point before everything else to avoid
+ * the need to check for it later. */
+ if (config.top_is_point && config.bottom_is_point) {
+ if (config.height == 0.0f) {
+ return create_vertex_mesh();
+ }
+ const float z_delta = -2.0f * config.height / static_cast<float>(config.side_segments);
+ const float3 start(0.0f, 0.0f, config.height);
+ const float3 delta(0.0f, 0.0f, z_delta);
+ return create_line_mesh(start, delta, config.tot_verts);
+ }
+
+ Mesh *mesh = BKE_mesh_new_nomain(
+ config.tot_verts, config.tot_edges, 0, config.get_tot_corners(), config.get_tot_faces());
+ BKE_id_material_eval_ensure_default_slot(&mesh->id);
+
+ MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
+ MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop};
+ MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
+ MutableSpan<MPoly> polys{mesh->mpoly, mesh->totpoly};
+
+ calculate_cone_vertices(verts, config);
+ calculate_cone_edges(edges, config);
+ calculate_cone_faces(loops, polys, config);
+ calculate_cone_uvs(mesh, config);
+
BKE_mesh_normals_tag_dirty(mesh);
- calculate_uvs(mesh, top_is_point, bottom_is_point, verts_num, fill_type);
+ calculate_cone_uvs(mesh, config);
return mesh;
}
@@ -540,23 +704,37 @@ static void geo_node_mesh_primitive_cone_exec(GeoNodeExecParams params)
{
const bNode &node = params.node();
const NodeGeometryMeshCone &storage = *(const NodeGeometryMeshCone *)node.storage;
-
const GeometryNodeMeshCircleFillType fill_type = (const GeometryNodeMeshCircleFillType)
storage.fill_type;
- const int verts_num = params.extract_input<int>("Vertices");
- if (verts_num < 3) {
+ 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"));
params.set_output("Geometry", GeometrySet());
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"));
+ params.set_output("Geometry", GeometrySet());
+ return;
+ }
+
+ const bool no_fill = fill_type == 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"));
+ params.set_output("Geometry", GeometrySet());
+ return;
+ }
+
const float radius_top = params.extract_input<float>("Radius Top");
const float radius_bottom = params.extract_input<float>("Radius Bottom");
const float depth = params.extract_input<float>("Depth");
Mesh *mesh = create_cylinder_or_cone_mesh(
- radius_top, radius_bottom, depth, verts_num, fill_type);
+ radius_top, radius_bottom, depth, circle_segments, side_segments, fill_segments, fill_type);
/* Transform the mesh so that the base of the cone is at the origin. */
BKE_mesh_translate(mesh, float3(0.0f, 0.0f, depth * 0.5f), false);
@@ -572,6 +750,7 @@ void register_node_type_geo_mesh_primitive_cone()
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_storage(
&ntype, "NodeGeometryMeshCone", node_free_standard_storage, node_copy_standard_storage);
ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_cone_exec;
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 ed701c921ca..287ea896ade 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
@@ -29,9 +29,31 @@ namespace blender::nodes {
static void geo_node_mesh_primitive_cylinder_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Int>("Vertices").default_value(32).min(3).max(4096);
- b.add_input<decl::Float>("Radius").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>("Depth").default_value(2.0f).min(0.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Int>("Vertices")
+ .default_value(32)
+ .min(3)
+ .max(512)
+ .description("The number of vertices around the circumference");
+ b.add_input<decl::Int>("Side Segments")
+ .default_value(1)
+ .min(1)
+ .max(512)
+ .description("The number of segments along the side");
+ b.add_input<decl::Int>("Fill Segments")
+ .default_value(1)
+ .min(1)
+ .max(512)
+ .description("The number of concentric segments of the fill");
+ b.add_input<decl::Float>("Radius")
+ .default_value(1.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description("The radius of the cylinder");
+ b.add_input<decl::Float>("Depth")
+ .default_value(2.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description("The height of the cylinder on the Z axis");
b.add_output<decl::Geometry>("Geometry");
}
@@ -54,6 +76,19 @@ 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 *UNUSED(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(fill_subdiv_socket, has_fill);
+}
+
static void geo_node_mesh_primitive_cylinder_exec(GeoNodeExecParams params)
{
const bNode &node = params.node();
@@ -64,15 +99,31 @@ static void geo_node_mesh_primitive_cylinder_exec(GeoNodeExecParams params)
const float radius = params.extract_input<float>("Radius");
const float depth = params.extract_input<float>("Depth");
- const int verts_num = params.extract_input<int>("Vertices");
- if (verts_num < 3) {
+ 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"));
params.set_output("Geometry", GeometrySet());
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"));
+ params.set_output("Geometry", GeometrySet());
+ return;
+ }
+
+ const bool no_fill = fill_type == 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"));
+ params.set_output("Geometry", GeometrySet());
+ return;
+ }
+
/* The cylinder is a special case of the cone mesh where the top and bottom radius are equal. */
- Mesh *mesh = create_cylinder_or_cone_mesh(radius, radius, depth, verts_num, fill_type);
+ Mesh *mesh = create_cylinder_or_cone_mesh(
+ radius, radius, depth, circle_segments, side_segments, fill_segments, fill_type);
params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
}
@@ -84,6 +135,7 @@ void register_node_type_geo_mesh_primitive_cylinder()
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_storage(
&ntype, "NodeGeometryMeshCylinder", node_free_standard_storage, node_copy_standard_storage);
ntype.declare = blender::nodes::geo_node_mesh_primitive_cylinder_declare;
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 9ca74fed9a7..c436f5bd480 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
@@ -32,28 +32,9 @@ static void geo_node_mesh_subdivide_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>("Geometry");
}
-static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params)
+static void geometry_set_mesh_subdivide(GeometrySet &geometry_set, const int level)
{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
-
if (!geometry_set.has_mesh()) {
- params.set_output("Geometry", geometry_set);
- return;
- }
-
-#ifndef WITH_OPENSUBDIV
- params.error_message_add(NodeWarningType::Error,
- TIP_("Disabled, Blender was compiled without OpenSubdiv"));
- params.set_output("Geometry", std::move(geometry_set));
- return;
-#endif
-
- /* See CCGSUBSURF_LEVEL_MAX for max limit. */
- const int subdiv_level = clamp_i(params.extract_input<int>("Level"), 0, 11);
-
- if (subdiv_level == 0) {
- params.set_output("Geometry", std::move(geometry_set));
return;
}
@@ -61,7 +42,7 @@ static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params)
/* Initialize mesh settings. */
SubdivToMeshSettings mesh_settings;
- mesh_settings.resolution = (1 << subdiv_level) + 1;
+ mesh_settings.resolution = (1 << level) + 1;
mesh_settings.use_optimal_display = false;
/* Initialize subdivision settings. */
@@ -79,7 +60,6 @@ static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params)
/* In case of bad topology, skip to input mesh. */
if (subdiv == nullptr) {
- params.set_output("Geometry", std::move(geometry_set));
return;
}
@@ -90,6 +70,29 @@ static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params)
mesh_component.replace(mesh_out);
BKE_subdiv_free(subdiv);
+}
+
+static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+
+#ifndef WITH_OPENSUBDIV
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("Disabled, Blender was compiled without OpenSubdiv"));
+ params.set_output("Geometry", std::move(geometry_set));
+ return;
+#endif
+
+ /* See CCGSUBSURF_LEVEL_MAX for max limit. */
+ const int subdiv_level = clamp_i(params.extract_input<int>("Level"), 0, 11);
+
+ if (subdiv_level == 0) {
+ params.set_output("Geometry", std::move(geometry_set));
+ return;
+ }
+
+ geometry_set.modify_geometry_sets(
+ [&](GeometrySet &geometry_set) { geometry_set_mesh_subdivide(geometry_set, subdiv_level); });
params.set_output("Geometry", std::move(geometry_set));
}
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
new file mode 100644
index 00000000000..6863f685eae
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
@@ -0,0 +1,189 @@
+/*
+ * 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_pointcloud_types.h"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_pointcloud.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+using blender::Array;
+
+namespace blender::nodes {
+
+static void geo_node_mesh_to_points_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>("Mesh");
+ b.add_input<decl::Vector>("Position").implicit_field();
+ b.add_input<decl::Float>("Radius")
+ .default_value(0.05f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .supports_field();
+ b.add_input<decl::Bool>("Selection").default_value(true).supports_field().hide_value();
+ b.add_output<decl::Geometry>("Points");
+}
+
+static void geo_node_mesh_to_points_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)
+{
+ NodeGeometryMeshToPoints *data = (NodeGeometryMeshToPoints *)MEM_callocN(
+ sizeof(NodeGeometryMeshToPoints), __func__);
+ data->mode = GEO_NODE_MESH_TO_POINTS_VERTICES;
+ node->storage = data;
+}
+
+template<typename T>
+static void copy_attribute_to_points(const VArray<T> &src,
+ const IndexMask mask,
+ MutableSpan<T> dst)
+{
+ for (const int i : mask.index_range()) {
+ dst[i] = src[mask[i]];
+ }
+}
+
+static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
+ Field<float3> &position_field,
+ Field<float> &radius_field,
+ Field<bool> &selection_field,
+ const AttributeDomain domain)
+{
+ const MeshComponent *mesh_component = geometry_set.get_component_for_read<MeshComponent>();
+ if (mesh_component == nullptr) {
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
+ return;
+ }
+ GeometryComponentFieldContext field_context{*mesh_component, domain};
+ const int domain_size = mesh_component->attribute_domain_size(domain);
+ if (domain_size == 0) {
+ 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);
+
+ PointCloud *pointcloud = BKE_pointcloud_new_nomain(selection.size());
+ uninitialized_fill_n(pointcloud->radius, pointcloud->totpoint, 0.05f);
+ geometry_set.replace_pointcloud(pointcloud);
+ 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});
+ copy_attribute_to_points(
+ evaluator.get_evaluated<float>(1), selection, {pointcloud->radius, pointcloud->totpoint});
+
+ Map<AttributeIDRef, AttributeKind> attributes;
+ geometry_set.gather_attributes_for_propagation(
+ {GEO_COMPONENT_TYPE_MESH}, GEO_COMPONENT_TYPE_POINT_CLOUD, false, attributes);
+ attributes.remove("position");
+
+ for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
+ const AttributeIDRef attribute_id = entry.key;
+ const CustomDataType data_type = entry.value.data_type;
+ GVArrayPtr src = mesh_component->attribute_get_for_read(attribute_id, domain, data_type);
+ OutputAttribute dst = point_component.attribute_try_get_for_output_only(
+ attribute_id, ATTR_DOMAIN_POINT, data_type);
+ if (dst && src) {
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ GVArray_Typed<T> src_typed{*src};
+ copy_attribute_to_points(*src_typed, selection, dst.as_span().typed<T>());
+ });
+ dst.save();
+ }
+ }
+
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_INSTANCES});
+}
+
+static void geo_node_mesh_to_points_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
+ Field<float3> position = params.extract_input<Field<float3>>("Position");
+ Field<float> radius = params.extract_input<Field<float>>("Radius");
+ Field<bool> selection = params.extract_input<Field<bool>>("Selection");
+
+ /* Use another multi-function operation to make sure the input radius is greater than zero.
+ * TODO: Use mutable multi-function once that is supported. */
+ static fn::CustomMF_SI_SO<float, float> max_zero_fn(
+ __func__, [](float value) { return std::max(0.0f, value); });
+ auto max_zero_op = std::make_shared<FieldOperation>(
+ 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 GeometryNodeMeshToPointsMode mode = (GeometryNodeMeshToPointsMode)storage.mode;
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ switch (mode) {
+ case GEO_NODE_MESH_TO_POINTS_VERTICES:
+ geometry_set_mesh_to_points(
+ geometry_set, position, positive_radius, selection, ATTR_DOMAIN_POINT);
+ break;
+ case GEO_NODE_MESH_TO_POINTS_EDGES:
+ geometry_set_mesh_to_points(
+ geometry_set, position, positive_radius, selection, ATTR_DOMAIN_EDGE);
+ break;
+ case GEO_NODE_MESH_TO_POINTS_FACES:
+ geometry_set_mesh_to_points(
+ geometry_set, position, positive_radius, selection, ATTR_DOMAIN_FACE);
+ break;
+ case GEO_NODE_MESH_TO_POINTS_CORNERS:
+ geometry_set_mesh_to_points(
+ geometry_set, position, positive_radius, selection, ATTR_DOMAIN_CORNER);
+ break;
+ }
+ });
+
+ params.set_output("Points", std::move(geometry_set));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_mesh_to_points()
+{
+ 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;
+ 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_points_to_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc
new file mode 100644
index 00000000000..afd0ced6360
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc
@@ -0,0 +1,118 @@
+/*
+ * 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 "BKE_attribute_math.hh"
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+using blender::Array;
+
+namespace blender::nodes {
+
+static void geo_node_points_to_vertices_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>("Points");
+ b.add_input<decl::Bool>("Selection").default_value(true).supports_field().hide_value();
+ b.add_output<decl::Geometry>("Mesh");
+}
+
+template<typename T>
+static void copy_attribute_to_vertices(const Span<T> src, const IndexMask mask, MutableSpan<T> dst)
+{
+ for (const int i : mask.index_range()) {
+ dst[i] = src[mask[i]];
+ }
+}
+
+/* One improvement would be to move the attribute arrays directly to the mesh when possible. */
+static void geometry_set_points_to_vertices(GeometrySet &geometry_set,
+ Field<bool> &selection_field)
+{
+ const PointCloudComponent *point_component =
+ geometry_set.get_component_for_read<PointCloudComponent>();
+ if (point_component == nullptr) {
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
+ return;
+ }
+
+ GeometryComponentFieldContext field_context{*point_component, ATTR_DOMAIN_POINT};
+ const int domain_size = point_component->attribute_domain_size(ATTR_DOMAIN_POINT);
+ if (domain_size == 0) {
+ 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);
+
+ Map<AttributeIDRef, AttributeKind> attributes;
+ geometry_set.gather_attributes_for_propagation(
+ {GEO_COMPONENT_TYPE_POINT_CLOUD}, GEO_COMPONENT_TYPE_MESH, false, attributes);
+
+ Mesh *mesh = BKE_mesh_new_nomain(selection.size(), 0, 0, 0, 0);
+ geometry_set.replace_mesh(mesh);
+ MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
+
+ for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
+ const AttributeIDRef attribute_id = entry.key;
+ const CustomDataType data_type = entry.value.data_type;
+ GVArrayPtr src = point_component->attribute_get_for_read(
+ attribute_id, ATTR_DOMAIN_POINT, data_type);
+ OutputAttribute dst = mesh_component.attribute_try_get_for_output_only(
+ attribute_id, ATTR_DOMAIN_POINT, data_type);
+ if (dst && src) {
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ GVArray_Typed<T> src_typed{*src};
+ VArray_Span<T> src_typed_span{*src_typed};
+ copy_attribute_to_vertices(src_typed_span, selection, dst.as_span().typed<T>());
+ });
+ dst.save();
+ }
+ }
+
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_INSTANCES});
+}
+
+static void geo_node_points_to_vertices_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Points");
+ Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ geometry_set_points_to_vertices(geometry_set, selection_field);
+ });
+
+ params.set_output("Mesh", std::move(geometry_set));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_points_to_vertices()
+{
+ 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;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_proximity.cc b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc
new file mode 100644
index 00000000000..7062deff2f1
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc
@@ -0,0 +1,235 @@
+/*
+ * 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 "BLI_timeit.hh"
+
+#include "DNA_mesh_types.h"
+
+#include "BKE_bvhutils.h"
+#include "BKE_geometry_set.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes {
+
+static void geo_node_proximity_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>("Target");
+ b.add_input<decl::Vector>("Source Position").implicit_field();
+ b.add_output<decl::Vector>("Position").dependent_field();
+ b.add_output<decl::Float>("Distance").dependent_field();
+}
+
+static void geo_node_proximity_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "target_element", 0, "", ICON_NONE);
+}
+
+static void geo_proximity_init(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeGeometryProximity *node_storage = (NodeGeometryProximity *)MEM_callocN(
+ sizeof(NodeGeometryProximity), __func__);
+ node_storage->target_element = GEO_NODE_PROX_TARGET_FACES;
+ node->storage = node_storage;
+}
+
+static void calculate_mesh_proximity(const VArray<float3> &positions,
+ const IndexMask mask,
+ const Mesh &mesh,
+ const GeometryNodeProximityTargetType type,
+ const MutableSpan<float> r_distances,
+ const MutableSpan<float3> r_locations)
+{
+ BVHTreeFromMesh bvh_data;
+ switch (type) {
+ case GEO_NODE_PROX_TARGET_POINTS:
+ BKE_bvhtree_from_mesh_get(&bvh_data, &mesh, BVHTREE_FROM_VERTS, 2);
+ break;
+ case GEO_NODE_PROX_TARGET_EDGES:
+ BKE_bvhtree_from_mesh_get(&bvh_data, &mesh, BVHTREE_FROM_EDGES, 2);
+ break;
+ case GEO_NODE_PROX_TARGET_FACES:
+ BKE_bvhtree_from_mesh_get(&bvh_data, &mesh, BVHTREE_FROM_LOOPTRI, 2);
+ break;
+ }
+
+ if (bvh_data.tree == nullptr) {
+ return;
+ }
+
+ threading::parallel_for(mask.index_range(), 512, [&](IndexRange range) {
+ BVHTreeNearest nearest;
+ copy_v3_fl(nearest.co, FLT_MAX);
+ nearest.index = -1;
+
+ for (int i : range) {
+ const int index = mask[i];
+ /* Use the distance to the last found point as upper bound to speedup the bvh lookup. */
+ nearest.dist_sq = float3::distance_squared(nearest.co, positions[index]);
+
+ BLI_bvhtree_find_nearest(
+ bvh_data.tree, positions[index], &nearest, bvh_data.nearest_callback, &bvh_data);
+
+ if (nearest.dist_sq < r_distances[index]) {
+ r_distances[index] = nearest.dist_sq;
+ if (!r_locations.is_empty()) {
+ r_locations[index] = nearest.co;
+ }
+ }
+ }
+ });
+
+ free_bvhtree_from_mesh(&bvh_data);
+}
+
+static void calculate_pointcloud_proximity(const VArray<float3> &positions,
+ const IndexMask mask,
+ const PointCloud &pointcloud,
+ const MutableSpan<float> r_distances,
+ const MutableSpan<float3> r_locations)
+{
+ BVHTreeFromPointCloud bvh_data;
+ BKE_bvhtree_from_pointcloud_get(&bvh_data, &pointcloud, 2);
+ if (bvh_data.tree == nullptr) {
+ return;
+ }
+
+ threading::parallel_for(mask.index_range(), 512, [&](IndexRange range) {
+ BVHTreeNearest nearest;
+ copy_v3_fl(nearest.co, FLT_MAX);
+ nearest.index = -1;
+
+ for (int i : range) {
+ const int index = mask[i];
+ /* Use the distance to the closest point in the mesh to speedup the pointcloud bvh lookup.
+ * This is ok because we only need to find the closest point in the pointcloud if it's
+ * closer than the mesh. */
+ nearest.dist_sq = r_distances[index];
+
+ BLI_bvhtree_find_nearest(
+ bvh_data.tree, positions[index], &nearest, bvh_data.nearest_callback, &bvh_data);
+
+ if (nearest.dist_sq < r_distances[index]) {
+ r_distances[index] = nearest.dist_sq;
+ if (!r_locations.is_empty()) {
+ r_locations[index] = nearest.co;
+ }
+ }
+ }
+ });
+
+ free_bvhtree_from_pointcloud(&bvh_data);
+}
+
+class ProximityFunction : public fn::MultiFunction {
+ private:
+ GeometrySet target_;
+ GeometryNodeProximityTargetType type_;
+
+ public:
+ ProximityFunction(GeometrySet target, GeometryNodeProximityTargetType type)
+ : target_(std::move(target)), type_(type)
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ blender::fn::MFSignatureBuilder signature{"Geometry Proximity"};
+ signature.single_input<float3>("Source Position");
+ signature.single_output<float3>("Position");
+ signature.single_output<float>("Distance");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<float3> &src_positions = params.readonly_single_input<float3>(0,
+ "Source Position");
+ MutableSpan<float3> positions = params.uninitialized_single_output_if_required<float3>(
+ 1, "Position");
+ /* Make sure there is a distance array, used for finding the smaller distance when there are
+ * multiple components. Theoretically it would be possible to avoid using the distance array
+ * when there is only one component. However, this only adds an allocation and a single float
+ * comparison per vertex, so it's likely not worth it. */
+ MutableSpan<float> distances = params.uninitialized_single_output<float>(2, "Distance");
+
+ distances.fill(FLT_MAX);
+
+ if (target_.has_mesh()) {
+ calculate_mesh_proximity(
+ src_positions, mask, *target_.get_mesh_for_read(), type_, distances, positions);
+ }
+
+ if (target_.has_pointcloud() && type_ == GEO_NODE_PROX_TARGET_POINTS) {
+ calculate_pointcloud_proximity(
+ src_positions, mask, *target_.get_pointcloud_for_read(), distances, positions);
+ }
+
+ if (params.single_output_is_required(2, "Distance")) {
+ threading::parallel_for(mask.index_range(), 2048, [&](IndexRange range) {
+ for (const int i : range) {
+ const int j = mask[i];
+ distances[j] = std::sqrt(distances[j]);
+ }
+ });
+ }
+ }
+};
+
+static void geo_node_proximity_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set_target = params.extract_input<GeometrySet>("Target");
+
+ if (!geometry_set_target.has_mesh() && !geometry_set_target.has_pointcloud()) {
+ 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}));
+ return;
+ }
+
+ const NodeGeometryProximity &storage = *(const NodeGeometryProximity *)params.node().storage;
+ Field<float3> position_field = params.extract_input<Field<float3>>("Source Position");
+
+ auto proximity_fn = std::make_unique<ProximityFunction>(
+ std::move(geometry_set_target),
+ static_cast<GeometryNodeProximityTargetType>(storage.target_element));
+ auto proximity_op = std::make_shared<FieldOperation>(
+ FieldOperation(std::move(proximity_fn), {std::move(position_field)}));
+
+ params.set_output("Position", Field<float3>(proximity_op, 0));
+ params.set_output("Distance", Field<float>(proximity_op, 1));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_proximity()
+{
+ 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_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;
+ 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 c63e4ec49d9..dafd10cee2d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc
@@ -25,20 +25,18 @@ static void geo_node_join_geometry_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>("Point Cloud");
b.add_output<decl::Geometry>("Curve");
b.add_output<decl::Geometry>("Volume");
+ b.add_output<decl::Geometry>("Instances");
}
static void geo_node_separate_components_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- /* Note that it will be possible to skip realizing instances here when instancing
- * geometry directly is supported by creating corresponding geometry instances. */
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
-
GeometrySet meshes;
GeometrySet point_clouds;
GeometrySet volumes;
GeometrySet curves;
+ GeometrySet instances;
if (geometry_set.has<MeshComponent>()) {
meshes.add(*geometry_set.get_component_for_read<MeshComponent>());
@@ -52,11 +50,15 @@ static void geo_node_separate_components_exec(GeoNodeExecParams params)
if (geometry_set.has<VolumeComponent>()) {
volumes.add(*geometry_set.get_component_for_read<VolumeComponent>());
}
+ if (geometry_set.has<InstancesComponent>()) {
+ instances.add(*geometry_set.get_component_for_read<InstancesComponent>());
+ }
params.set_output("Mesh", meshes);
params.set_output("Point Cloud", point_clouds);
params.set_output("Curve", curves);
params.set_output("Volume", volumes);
+ params.set_output("Instances", instances);
}
} // namespace blender::nodes
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 c5e10b788ac..8caf961fc04 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
@@ -23,8 +23,8 @@ namespace blender::nodes {
static void geo_node_set_position_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Vector>("Position").hide_value();
- b.add_input<decl::Bool>("Selection").default_value(true).hide_value();
+ b.add_input<decl::Vector>("Position").implicit_field();
+ b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
b.add_output<decl::Geometry>("Geometry");
}
@@ -34,6 +34,9 @@ static void set_position_in_component(GeometryComponent &component,
{
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ if (domain_size == 0) {
+ return;
+ }
fn::FieldEvaluator selection_evaluator{field_context, domain_size};
selection_evaluator.add(selection_field);
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
new file mode 100644
index 00000000000..5e2f03806c3
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
@@ -0,0 +1,306 @@
+/*
+ * 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_curve_types.h"
+#include "DNA_vfont_types.h"
+
+#include "BKE_curve.h"
+#include "BKE_font.h"
+#include "BKE_spline.hh"
+
+#include "BLI_hash.h"
+#include "BLI_string_utf8.h"
+#include "BLI_task.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes {
+
+static void geo_node_string_to_curves_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::String>("String");
+ b.add_input<decl::Float>("Size").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>("Character Spacing")
+ .default_value(1.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>("Word Spacing").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>("Line Spacing").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>("Text Box Width").default_value(0.0f).min(0.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>("Text Box Height").default_value(0.0f).min(0.0f).subtype(PROP_DISTANCE);
+ b.add_output<decl::Geometry>("Curves");
+ b.add_output<decl::String>("Remainder");
+}
+
+static void geo_node_string_to_curves_layout(uiLayout *layout, struct bContext *C, PointerRNA *ptr)
+{
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "font",
+ nullptr,
+ "FONT_OT_open",
+ "FONT_OT_unlink",
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+ uiItemR(layout, ptr, "overflow", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "align_x", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "align_y", 0, "", ICON_NONE);
+}
+
+static void geo_node_string_to_curves_init(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeGeometryStringToCurves *data = (NodeGeometryStringToCurves *)MEM_callocN(
+ sizeof(NodeGeometryStringToCurves), __func__);
+
+ data->overflow = GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW;
+ data->align_x = GEO_NODE_STRING_TO_CURVES_ALIGN_X_LEFT;
+ data->align_y = GEO_NODE_STRING_TO_CURVES_ALIGN_Y_TOP_BASELINE;
+ node->storage = data;
+ node->id = (ID *)BKE_vfont_builtin_get();
+}
+
+static void geo_node_string_to_curves_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ const NodeGeometryStringToCurves *storage = (const NodeGeometryStringToCurves *)node->storage;
+ const GeometryNodeStringToCurvesOverflowMode overflow = (GeometryNodeStringToCurvesOverflowMode)
+ storage->overflow;
+ bNodeSocket *socket_remainder = ((bNodeSocket *)node->outputs.first)->next;
+ nodeSetSocketAvailability(socket_remainder, overflow == GEO_NODE_STRING_TO_CURVES_MODE_TRUNCATE);
+
+ bNodeSocket *height_socket = (bNodeSocket *)node->inputs.last;
+ bNodeSocket *width_socket = height_socket->prev;
+ nodeSetSocketAvailability(height_socket, overflow != GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW);
+ node_sock_label(width_socket,
+ overflow == GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW ? N_("Max Width") :
+ N_("Text Box Width"));
+}
+
+struct TextLayout {
+ /* Position of each character. */
+ Vector<float2> positions;
+
+ /* The text that fit into the text box, with newline character sequences replaced. */
+ std::string text;
+
+ /* The text that didn't fit into the text box in 'Truncate' mode. May be empty. */
+ std::string truncated_text;
+
+ /* Font size could be modified if in 'Scale to fit'-mode. */
+ float final_font_size;
+};
+
+static TextLayout get_text_layout(GeoNodeExecParams &params)
+{
+ TextLayout layout;
+ layout.text = params.extract_input<std::string>("String");
+ if (layout.text.empty()) {
+ return {};
+ }
+
+ const NodeGeometryStringToCurves &storage =
+ *(const NodeGeometryStringToCurves *)params.node().storage;
+ const GeometryNodeStringToCurvesOverflowMode overflow = (GeometryNodeStringToCurvesOverflowMode)
+ storage.overflow;
+ const GeometryNodeStringToCurvesAlignXMode align_x = (GeometryNodeStringToCurvesAlignXMode)
+ storage.align_x;
+ const GeometryNodeStringToCurvesAlignYMode align_y = (GeometryNodeStringToCurvesAlignYMode)
+ storage.align_y;
+
+ const float font_size = std::max(params.extract_input<float>("Size"), 0.0f);
+ const float char_spacing = params.extract_input<float>("Character Spacing");
+ const float word_spacing = params.extract_input<float>("Word Spacing");
+ const float line_spacing = params.extract_input<float>("Line Spacing");
+ const float textbox_w = params.extract_input<float>("Text Box Width");
+ const float textbox_h = overflow == GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW ?
+ 0.0f :
+ params.extract_input<float>("Text Box Height");
+ VFont *vfont = (VFont *)params.node().id;
+
+ Curve cu = {nullptr};
+ cu.type = OB_FONT;
+ /* Set defaults */
+ cu.resolu = 12;
+ cu.smallcaps_scale = 0.75f;
+ cu.wordspace = 1.0f;
+ /* Set values from inputs */
+ cu.spacemode = align_x;
+ cu.align_y = align_y;
+ cu.fsize = font_size;
+ cu.spacing = char_spacing;
+ cu.wordspace = word_spacing;
+ cu.linedist = line_spacing;
+ cu.vfont = vfont;
+ cu.overflow = overflow;
+ cu.tb = (TextBox *)MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), __func__);
+ cu.tb->w = textbox_w;
+ cu.tb->h = textbox_h;
+ cu.totbox = 1;
+ size_t len_bytes;
+ size_t len_chars = BLI_strlen_utf8_ex(layout.text.c_str(), &len_bytes);
+ cu.len_char32 = len_chars;
+ cu.len = len_bytes;
+ cu.pos = len_chars;
+ /* The reason for the additional character here is unknown, but reflects other code elsewhere. */
+ cu.str = (char *)MEM_mallocN(len_bytes + sizeof(char32_t), __func__);
+ cu.strinfo = (CharInfo *)MEM_callocN((len_chars + 1) * sizeof(CharInfo), __func__);
+ BLI_strncpy(cu.str, layout.text.c_str(), len_bytes + 1);
+
+ struct CharTrans *chartransdata = nullptr;
+ int text_len;
+ bool text_free;
+ const char32_t *r_text = nullptr;
+ /* Mode FO_DUPLI used because it doesn't create curve splines. */
+ BKE_vfont_to_curve_ex(
+ nullptr, &cu, FO_DUPLI, nullptr, &r_text, &text_len, &text_free, &chartransdata);
+
+ if (text_free) {
+ MEM_freeN((void *)r_text);
+ }
+
+ Span<CharInfo> info{cu.strinfo, text_len};
+ layout.final_font_size = cu.fsize_realtime;
+ layout.positions.reserve(text_len);
+
+ for (const int i : IndexRange(text_len)) {
+ CharTrans &ct = chartransdata[i];
+ layout.positions.append(float2(ct.xof, ct.yof) * layout.final_font_size);
+
+ if ((info[i].flag & CU_CHINFO_OVERFLOW) && (cu.overflow == CU_OVERFLOW_TRUNCATE)) {
+ const int offset = BLI_str_utf8_offset_from_index(layout.text.c_str(), i + 1);
+ layout.truncated_text = layout.text.substr(offset);
+ layout.text = layout.text.substr(0, offset);
+ break;
+ }
+ }
+
+ MEM_SAFE_FREE(chartransdata);
+ MEM_SAFE_FREE(cu.str);
+ MEM_SAFE_FREE(cu.strinfo);
+ MEM_SAFE_FREE(cu.tb);
+
+ return layout;
+}
+
+/* Returns a mapping of UTF-32 character code to instance handle. */
+static Map<int, int> create_curve_instances(GeoNodeExecParams &params,
+ const float fontsize,
+ const Span<char32_t> charcodes,
+ InstancesComponent &instance_component)
+{
+ VFont *vfont = (VFont *)params.node().id;
+ Map<int, int> handles;
+
+ for (int i : charcodes.index_range()) {
+ if (handles.contains(charcodes[i])) {
+ continue;
+ }
+ Curve cu = {nullptr};
+ cu.type = OB_FONT;
+ cu.resolu = 12;
+ cu.vfont = vfont;
+ CharInfo charinfo = {0};
+ charinfo.mat_nr = 1;
+
+ BKE_vfont_build_char(&cu, &cu.nurb, charcodes[i], &charinfo, 0, 0, 0, i, 1);
+ std::unique_ptr<CurveEval> curve_eval = curve_eval_from_dna_curve(cu);
+ BKE_nurbList_free(&cu.nurb);
+ float4x4 size_matrix = float4x4::identity();
+ size_matrix.apply_scale(fontsize);
+ curve_eval->transform(size_matrix);
+
+ GeometrySet geometry_set_curve = GeometrySet::create_with_curve(curve_eval.release());
+ handles.add_new(charcodes[i], instance_component.add_reference(std::move(geometry_set_curve)));
+ }
+ return handles;
+}
+
+static void add_instances_from_handles(InstancesComponent &instances,
+ const Map<int, int> &char_handles,
+ const Span<char32_t> charcodes,
+ const Span<float2> positions)
+{
+ instances.resize(positions.size());
+ MutableSpan<int> handles = instances.instance_reference_handles();
+ MutableSpan<float4x4> transforms = instances.instance_transforms();
+ MutableSpan<int> instance_ids = instances.instance_ids();
+
+ threading::parallel_for(IndexRange(positions.size()), 256, [&](IndexRange range) {
+ for (const int i : range) {
+ handles[i] = char_handles.lookup(charcodes[i]);
+ transforms[i] = float4x4::from_location({positions[i].x, positions[i].y, 0});
+ instance_ids[i] = i;
+ }
+ });
+}
+
+static void geo_node_string_to_curves_exec(GeoNodeExecParams params)
+{
+ TextLayout layout = get_text_layout(params);
+
+ const NodeGeometryStringToCurves &storage =
+ *(const NodeGeometryStringToCurves *)params.node().storage;
+ if (storage.overflow == GEO_NODE_STRING_TO_CURVES_MODE_TRUNCATE) {
+ params.set_output("Remainder", std::move(layout.truncated_text));
+ }
+
+ if (layout.positions.size() == 0) {
+ params.set_output("Curves", GeometrySet());
+ return;
+ }
+
+ /* Convert UTF-8 encoded string to UTF-32. */
+ size_t len_bytes;
+ size_t len_chars = BLI_strlen_utf8_ex(layout.text.c_str(), &len_bytes);
+ Array<char32_t> char_codes(len_chars + 1);
+ BLI_str_utf8_as_utf32(char_codes.data(), layout.text.c_str(), len_chars + 1);
+
+ /* Create and add instances. */
+ GeometrySet geometry_set_out;
+ InstancesComponent &instances = geometry_set_out.get_component_for_write<InstancesComponent>();
+ Map<int, int> char_handles = create_curve_instances(
+ params, layout.final_font_size, char_codes, instances);
+ add_instances_from_handles(instances, char_handles, char_codes, layout.positions);
+
+ params.set_output("Curves", std::move(geometry_set_out));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_string_to_curves()
+{
+ 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);
+ 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;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_switch.cc b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
index ca857c4d2e3..05df927fb39 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_switch.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
@@ -19,24 +19,37 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_material.h"
+
+#include "FN_multi_function_signature.hh"
+
namespace blender::nodes {
static void geo_node_switch_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Bool>("Switch");
-
- b.add_input<decl::Float>("False");
- b.add_input<decl::Float>("True");
- b.add_input<decl::Int>("False", "False_001").min(-100000).max(100000);
- b.add_input<decl::Int>("True", "True_001").min(-100000).max(100000);
- b.add_input<decl::Bool>("False", "False_002");
- b.add_input<decl::Bool>("True", "True_002");
- b.add_input<decl::Vector>("False", "False_003");
- b.add_input<decl::Vector>("True", "True_003");
- b.add_input<decl::Color>("False", "False_004").default_value({0.8f, 0.8f, 0.8f, 1.0f});
- b.add_input<decl::Color>("True", "True_004").default_value({0.8f, 0.8f, 0.8f, 1.0f});
- b.add_input<decl::String>("False", "False_005");
- b.add_input<decl::String>("True", "True_005");
+ b.add_input<decl::Bool>("Switch").default_value(false).supports_field();
+ b.add_input<decl::Bool>("Switch", "Switch_001").default_value(false);
+
+ b.add_input<decl::Float>("False").supports_field();
+ b.add_input<decl::Float>("True").supports_field();
+ b.add_input<decl::Int>("False", "False_001").min(-100000).max(100000).supports_field();
+ b.add_input<decl::Int>("True", "True_001").min(-100000).max(100000).supports_field();
+ b.add_input<decl::Bool>("False", "False_002").default_value(false).hide_value().supports_field();
+ b.add_input<decl::Bool>("True", "True_002").default_value(true).hide_value().supports_field();
+ b.add_input<decl::Vector>("False", "False_003").supports_field();
+ b.add_input<decl::Vector>("True", "True_003").supports_field();
+ b.add_input<decl::Color>("False", "False_004")
+ .default_value({0.8f, 0.8f, 0.8f, 1.0f})
+ .supports_field();
+ b.add_input<decl::Color>("True", "True_004")
+ .default_value({0.8f, 0.8f, 0.8f, 1.0f})
+ .supports_field();
+ b.add_input<decl::String>("False", "False_005").supports_field();
+ b.add_input<decl::String>("True", "True_005").supports_field();
+
b.add_input<decl::Geometry>("False", "False_006");
b.add_input<decl::Geometry>("True", "True_006");
b.add_input<decl::Object>("False", "False_007");
@@ -48,12 +61,12 @@ static void geo_node_switch_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Material>("False", "False_010");
b.add_input<decl::Material>("True", "True_010");
- b.add_output<decl::Float>("Output");
- b.add_output<decl::Int>("Output", "Output_001");
- b.add_output<decl::Bool>("Output", "Output_002");
- b.add_output<decl::Vector>("Output", "Output_003");
- b.add_output<decl::Color>("Output", "Output_004");
- b.add_output<decl::String>("Output", "Output_005");
+ b.add_output<decl::Float>("Output").dependent_field();
+ b.add_output<decl::Int>("Output", "Output_001").dependent_field();
+ b.add_output<decl::Bool>("Output", "Output_002").dependent_field();
+ b.add_output<decl::Vector>("Output", "Output_003").dependent_field();
+ b.add_output<decl::Color>("Output", "Output_004").dependent_field();
+ b.add_output<decl::String>("Output", "Output_005").dependent_field();
b.add_output<decl::Geometry>("Output", "Output_006");
b.add_output<decl::Object>("Output", "Output_007");
b.add_output<decl::Collection>("Output", "Output_008");
@@ -77,91 +90,168 @@ static void geo_node_switch_update(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeSwitch *node_storage = (NodeSwitch *)node->storage;
int index = 0;
- LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
- nodeSetSocketAvailability(
- socket, index == 0 || socket->type == (eNodeSocketDatatype)node_storage->input_type);
- index++;
+ 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);
+
+ nodeSetSocketAvailability(field_switch, fields_type);
+ nodeSetSocketAvailability(non_field_switch, !fields_type);
+
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &node->inputs, index) {
+ if (index <= 1) {
+ continue;
+ }
+ nodeSetSocketAvailability(socket,
+ socket->type == (eNodeSocketDatatype)node_storage->input_type);
}
+
LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
nodeSetSocketAvailability(socket,
socket->type == (eNodeSocketDatatype)node_storage->input_type);
}
}
-template<typename T>
-static void output_input(GeoNodeExecParams &params,
- const bool input,
- const StringRef input_suffix,
- const StringRef output_identifier)
+template<typename T> class SwitchFieldsFunction : public fn::MultiFunction {
+ public:
+ SwitchFieldsFunction()
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"Switch"};
+ signature.single_input<bool>("Switch");
+ signature.single_input<T>("False");
+ signature.single_input<T>("True");
+ signature.single_output<T>("Output");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<bool> &switches = params.readonly_single_input<bool>(0, "Switch");
+ const VArray<T> &falses = params.readonly_single_input<T>(1, "False");
+ const VArray<T> &trues = params.readonly_single_input<T>(2, "True");
+ MutableSpan<T> values = params.uninitialized_single_output_if_required<T>(3, "Output");
+ for (int64_t i : mask) {
+ new (&values[i]) T(switches[i] ? trues[i] : falses[i]);
+ }
+ }
+};
+
+template<typename T> void switch_fields(GeoNodeExecParams &params, const StringRef suffix)
+{
+ if (params.lazy_require_input("Switch")) {
+ return;
+ }
+
+ const std::string name_false = "False" + suffix;
+ const std::string name_true = "True" + suffix;
+ const std::string name_output = "Output" + suffix;
+
+ /* TODO: Allow for Laziness when the switch field is constant. */
+ const bool require_false = params.lazy_require_input(name_false);
+ const bool require_true = params.lazy_require_input(name_true);
+ if (require_false | require_true) {
+ return;
+ }
+
+ Field<bool> switches_field = params.extract_input<Field<bool>>("Switch");
+ Field<T> falses_field = params.extract_input<Field<T>>(name_false);
+ Field<T> trues_field = params.extract_input<Field<T>>(name_true);
+
+ auto switch_fn = std::make_unique<SwitchFieldsFunction<T>>();
+ auto switch_op = std::make_shared<FieldOperation>(FieldOperation(
+ std::move(switch_fn),
+ {std::move(switches_field), std::move(falses_field), std::move(trues_field)}));
+
+ params.set_output(name_output, Field<T>(switch_op, 0));
+}
+
+template<typename T> void switch_no_fields(GeoNodeExecParams &params, const StringRef suffix)
{
- const std::string name_a = "False" + input_suffix;
- const std::string name_b = "True" + input_suffix;
- if (input) {
- params.set_input_unused(name_a);
- if (params.lazy_require_input(name_b)) {
+ if (params.lazy_require_input("Switch_001")) {
+ return;
+ }
+ bool switch_value = params.get_input<bool>("Switch_001");
+
+ const std::string name_false = "False" + suffix;
+ const std::string name_true = "True" + suffix;
+ const std::string name_output = "Output" + suffix;
+
+ if (switch_value) {
+ params.set_input_unused(name_false);
+ if (params.lazy_require_input(name_true)) {
return;
}
- params.set_output(output_identifier, params.extract_input<T>(name_b));
+ params.set_output(name_output, params.extract_input<T>(name_true));
}
else {
- params.set_input_unused(name_b);
- if (params.lazy_require_input(name_a)) {
+ params.set_input_unused(name_true);
+ if (params.lazy_require_input(name_false)) {
return;
}
- params.set_output(output_identifier, params.extract_input<T>(name_a));
+ params.set_output(name_output, params.extract_input<T>(name_false));
}
}
static void geo_node_switch_exec(GeoNodeExecParams params)
{
- if (params.lazy_require_input("Switch")) {
- return;
- }
const NodeSwitch &storage = *(const NodeSwitch *)params.node().storage;
- const bool input = params.get_input<bool>("Switch");
- switch ((eNodeSocketDatatype)storage.input_type) {
+ const eNodeSocketDatatype data_type = static_cast<eNodeSocketDatatype>(storage.input_type);
+
+ switch (data_type) {
+
case SOCK_FLOAT: {
- output_input<float>(params, input, "", "Output");
+ switch_fields<float>(params, "");
break;
}
case SOCK_INT: {
- output_input<int>(params, input, "_001", "Output_001");
+ switch_fields<int>(params, "_001");
break;
}
case SOCK_BOOLEAN: {
- output_input<bool>(params, input, "_002", "Output_002");
+ switch_fields<bool>(params, "_002");
break;
}
case SOCK_VECTOR: {
- output_input<float3>(params, input, "_003", "Output_003");
+ switch_fields<float3>(params, "_003");
break;
}
case SOCK_RGBA: {
- output_input<ColorGeometry4f>(params, input, "_004", "Output_004");
+ switch_fields<ColorGeometry4f>(params, "_004");
break;
}
case SOCK_STRING: {
- output_input<std::string>(params, input, "_005", "Output_005");
+ switch_fields<std::string>(params, "_005");
break;
}
case SOCK_GEOMETRY: {
- output_input<GeometrySet>(params, input, "_006", "Output_006");
+ switch_no_fields<GeometrySet>(params, "_006");
break;
}
case SOCK_OBJECT: {
- output_input<Object *>(params, input, "_007", "Output_007");
+ switch_no_fields<Object *>(params, "_007");
break;
}
case SOCK_COLLECTION: {
- output_input<Collection *>(params, input, "_008", "Output_008");
+ switch_no_fields<Collection *>(params, "_008");
break;
}
case SOCK_TEXTURE: {
- output_input<Tex *>(params, input, "_009", "Output_009");
+ switch_no_fields<Tex *>(params, "_009");
break;
}
case SOCK_MATERIAL: {
- output_input<Material *>(params, input, "_010", "Output_010");
+ switch_no_fields<Material *>(params, "_010");
break;
}
default:
diff --git a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
index 8886c7194db..7ef0913622c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
@@ -58,14 +58,14 @@ static void geo_node_triangulate_exec(GeoNodeExecParams params)
GeometryNodeTriangulateNGons ngon_method = static_cast<GeometryNodeTriangulateNGons>(
params.node().custom2);
- geometry_set = geometry_set_realize_instances(geometry_set);
-
- /* #triangulate_mesh might modify the input mesh currently. */
- Mesh *mesh_in = geometry_set.get_mesh_for_write();
- if (mesh_in != nullptr) {
- Mesh *mesh_out = triangulate_mesh(mesh_in, quad_method, ngon_method, min_vertices, 0);
- geometry_set.replace_mesh(mesh_out);
- }
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ /* #triangulate_mesh might modify the input mesh currently. */
+ Mesh *mesh_in = geometry_set.get_mesh_for_write();
+ if (mesh_in != nullptr) {
+ Mesh *mesh_out = triangulate_mesh(mesh_in, quad_method, ngon_method, min_vertices, 0);
+ geometry_set.replace_mesh(mesh_out);
+ }
+ });
params.set_output("Geometry", std::move(geometry_set));
}
diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
index 3b3b643d0ae..fa9bf09d8d9 100644
--- a/source/blender/nodes/intern/geometry_nodes_eval_log.cc
+++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
@@ -159,15 +159,22 @@ const SocketLog *NodeLog::lookup_socket_log(const bNode &node, const bNodeSocket
GeometryValueLog::GeometryValueLog(const GeometrySet &geometry_set, bool log_full_geometry)
{
- bke::geometry_set_instances_attribute_foreach(
- geometry_set,
- [&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ static std::array all_component_types = {GEO_COMPONENT_TYPE_CURVE,
+ GEO_COMPONENT_TYPE_INSTANCES,
+ GEO_COMPONENT_TYPE_MESH,
+ GEO_COMPONENT_TYPE_POINT_CLOUD,
+ GEO_COMPONENT_TYPE_VOLUME};
+ geometry_set.attribute_foreach(
+ all_component_types,
+ true,
+ [&](const bke::AttributeIDRef &attribute_id,
+ const AttributeMetaData &meta_data,
+ const GeometryComponent &UNUSED(component)) {
if (attribute_id.is_named()) {
this->attributes_.append({attribute_id.name(), meta_data.domain, meta_data.data_type});
}
- return true;
- },
- 8);
+ });
+
for (const GeometryComponent *component : geometry_set.get_components_for_read()) {
component_types_.append(component->type());
switch (component->type()) {
diff --git a/source/blender/nodes/intern/node_common.c b/source/blender/nodes/intern/node_common.cc
index b8c89d1db37..f5e6e7640ad 100644
--- a/source/blender/nodes/intern/node_common.c
+++ b/source/blender/nodes/intern/node_common.cc
@@ -21,12 +21,16 @@
* \ingroup nodes
*/
-#include <stddef.h>
-#include <string.h>
+#include <cstddef>
+#include <cstring>
#include "DNA_node_types.h"
#include "BLI_listbase.h"
+#include "BLI_map.hh"
+#include "BLI_multi_value_map.hh"
+#include "BLI_set.hh"
+#include "BLI_stack.hh"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -42,10 +46,10 @@
#include "node_common.h"
#include "node_util.h"
-enum {
- REFINE_FORWARD = 1 << 0,
- REFINE_BACKWARD = 1 << 1,
-};
+using blender::Map;
+using blender::MultiValueMap;
+using blender::Set;
+using blender::Stack;
/* -------------------------------------------------------------------- */
/** \name Node Group
@@ -53,24 +57,22 @@ enum {
bNodeSocket *node_group_find_input_socket(bNode *groupnode, const char *identifier)
{
- bNodeSocket *sock;
- for (sock = groupnode->inputs.first; sock; sock = sock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &groupnode->inputs) {
if (STREQ(sock->identifier, identifier)) {
return sock;
}
}
- return NULL;
+ return nullptr;
}
bNodeSocket *node_group_find_output_socket(bNode *groupnode, const char *identifier)
{
- bNodeSocket *sock;
- for (sock = groupnode->outputs.first; sock; sock = sock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &groupnode->outputs) {
if (STREQ(sock->identifier, identifier)) {
return sock;
}
}
- return NULL;
+ return nullptr;
}
/* groups display their internal tree name as label */
@@ -95,13 +97,12 @@ bool node_group_poll_instance(bNode *node, bNodeTree *nodetree, const char **dis
bool nodeGroupPoll(bNodeTree *nodetree, bNodeTree *grouptree, const char **r_disabled_hint)
{
- bNode *node;
bool valid = true;
/* unspecified node group, generally allowed
* (if anything, should be avoided on operator level)
*/
- if (grouptree == NULL) {
+ if (grouptree == nullptr) {
return true;
}
@@ -110,7 +111,7 @@ bool nodeGroupPoll(bNodeTree *nodetree, bNodeTree *grouptree, const char **r_dis
return false;
}
- for (node = grouptree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &grouptree->nodes) {
if (node->typeinfo->poll_instance &&
!node->typeinfo->poll_instance(node, nodetree, r_disabled_hint)) {
valid = false;
@@ -121,12 +122,15 @@ bool nodeGroupPoll(bNodeTree *nodetree, bNodeTree *grouptree, const char **r_dis
}
/* used for both group nodes and interface nodes */
-static bNodeSocket *group_verify_socket(
- bNodeTree *ntree, bNode *gnode, bNodeSocket *iosock, ListBase *verify_lb, int in_out)
+static bNodeSocket *group_verify_socket(bNodeTree *ntree,
+ bNode *gnode,
+ bNodeSocket *iosock,
+ ListBase *verify_lb,
+ eNodeSocketInOut in_out)
{
bNodeSocket *sock;
- for (sock = verify_lb->first; sock; sock = sock->next) {
+ for (sock = (bNodeSocket *)verify_lb->first; sock; sock = sock->next) {
if (STREQ(sock->identifier, iosock->identifier)) {
break;
}
@@ -163,29 +167,32 @@ static bNodeSocket *group_verify_socket(
}
/* used for both group nodes and interface nodes */
-static void group_verify_socket_list(
- bNodeTree *ntree, bNode *gnode, ListBase *iosock_lb, ListBase *verify_lb, int in_out)
+static void group_verify_socket_list(bNodeTree *ntree,
+ bNode *gnode,
+ ListBase *iosock_lb,
+ ListBase *verify_lb,
+ eNodeSocketInOut in_out)
{
- bNodeSocket *iosock, *sock, *nextsock;
+ bNodeSocket *sock, *nextsock;
/* step by step compare */
- iosock = iosock_lb->first;
+ 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 = verify_lb->first; sock; sock = nextsock) {
+ for (sock = (bNodeSocket *)verify_lb->first; sock; sock = nextsock) {
nextsock = sock->next;
nodeRemoveSocket(ntree, gnode, sock);
}
/* and we put back the verified sockets */
- iosock = iosock_lb->first;
+ iosock = (bNodeSocket *)iosock_lb->first;
for (; iosock; iosock = iosock->next) {
if (iosock->new_sock) {
BLI_addtail(verify_lb, iosock->new_sock);
- iosock->new_sock = NULL;
+ iosock->new_sock = nullptr;
}
}
}
@@ -194,11 +201,11 @@ static void group_verify_socket_list(
void node_group_update(struct bNodeTree *ntree, struct bNode *node)
{
/* check inputs and outputs, and remove or insert them */
- if (node->id == NULL) {
+ if (node->id == nullptr) {
nodeRemoveAllSockets(ntree, node);
}
else if ((ID_IS_LINKED(node->id) && (node->id->tag & LIB_TAG_MISSING))) {
- /* Missing datablock, leave sockets unchanged so that when it comes back
+ /* Missing data-block, leave sockets unchanged so that when it comes back
* the links remain valid. */
}
else {
@@ -227,7 +234,7 @@ static void node_frame_init(bNodeTree *UNUSED(ntree), bNode *node)
void register_node_type_frame(void)
{
/* frame type is used for all tree types, needs dynamic allocation */
- bNodeType *ntype = MEM_callocN(sizeof(bNodeType), "frame node type");
+ bNodeType *ntype = (bNodeType *)MEM_callocN(sizeof(bNodeType), "frame node type");
ntype->free_self = (void (*)(bNodeType *))MEM_freeN;
node_type_base(ntype, NODE_FRAME, "Frame", NODE_CLASS_LAYOUT, NODE_BACKGROUND);
@@ -254,11 +261,11 @@ static void node_reroute_update_internal_links(bNodeTree *ntree, bNode *node)
return;
}
- link = MEM_callocN(sizeof(bNodeLink), "internal node link");
+ link = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "internal node link");
link->fromnode = node;
- link->fromsock = node->inputs.first;
+ link->fromsock = (bNodeSocket *)node->inputs.first;
link->tonode = node;
- link->tosock = node->outputs.first;
+ link->tosock = (bNodeSocket *)node->outputs.first;
/* internal link is always valid */
link->flag |= NODE_LINK_VALID;
BLI_addtail(&node->internal_links, link);
@@ -276,7 +283,7 @@ static void node_reroute_init(bNodeTree *ntree, bNode *node)
void register_node_type_reroute(void)
{
/* frame type is used for all tree types, needs dynamic allocation */
- bNodeType *ntype = MEM_callocN(sizeof(bNodeType), "frame node type");
+ bNodeType *ntype = (bNodeType *)MEM_callocN(sizeof(bNodeType), "frame node type");
ntype->free_self = (void (*)(bNodeType *))MEM_freeN;
node_type_base(ntype, NODE_REROUTE, "Reroute", NODE_CLASS_LAYOUT, 0);
@@ -286,76 +293,37 @@ void register_node_type_reroute(void)
nodeRegisterType(ntype);
}
-static void node_reroute_inherit_type_recursive(bNodeTree *ntree, bNode *node, int flag)
+static void propagate_reroute_type_from_start_socket(
+ bNodeSocket *start_socket,
+ const MultiValueMap<bNodeSocket *, bNodeLink *> &links_map,
+ Map<bNode *, const bNodeSocketType *> &r_reroute_types)
{
- bNodeSocket *input = node->inputs.first;
- bNodeSocket *output = node->outputs.first;
- bNodeLink *link;
- int type = SOCK_FLOAT;
- const char *type_idname = nodeStaticSocketType(type, PROP_NONE);
-
- /* XXX it would be a little bit more efficient to restrict actual updates
- * to reroute nodes connected to an updated node, but there's no reliable flag
- * to indicate updated nodes (node->update is not set on linking).
- */
-
- node->done = 1;
-
- /* recursive update */
- for (link = ntree->links.first; link; link = link->next) {
- bNode *fromnode = link->fromnode;
- bNode *tonode = link->tonode;
- if (!tonode || !fromnode) {
- continue;
+ Stack<bNode *> nodes_to_check;
+ for (bNodeLink *link : links_map.lookup(start_socket)) {
+ if (link->tonode->type == NODE_REROUTE) {
+ nodes_to_check.push(link->tonode);
}
- if (nodeLinkIsHidden(link)) {
- continue;
- }
-
- if (flag & REFINE_FORWARD) {
- if (tonode == node && fromnode->type == NODE_REROUTE && !fromnode->done) {
- node_reroute_inherit_type_recursive(ntree, fromnode, REFINE_FORWARD);
- }
+ if (link->fromnode->type == NODE_REROUTE) {
+ nodes_to_check.push(link->fromnode);
}
- if (flag & REFINE_BACKWARD) {
- if (fromnode == node && tonode->type == NODE_REROUTE && !tonode->done) {
- node_reroute_inherit_type_recursive(ntree, tonode, REFINE_BACKWARD);
- }
- }
- }
-
- /* determine socket type from unambiguous input/output connection if possible */
- if (nodeSocketLinkLimit(input) == 1 && input->link) {
- type = input->link->fromsock->type;
- type_idname = nodeStaticSocketType(type, PROP_NONE);
- }
- else if (nodeSocketLinkLimit(output) == 1 && output->link) {
- type = output->link->tosock->type;
- type_idname = nodeStaticSocketType(type, PROP_NONE);
}
-
- if (input->type != type) {
- bNodeSocket *ninput = nodeAddSocket(ntree, node, SOCK_IN, type_idname, "input", "Input");
- for (link = ntree->links.first; link; link = link->next) {
- if (link->tosock == input) {
- link->tosock = ninput;
- ninput->link = link;
+ const bNodeSocketType *current_type = start_socket->typeinfo;
+ while (!nodes_to_check.is_empty()) {
+ bNode *reroute_node = nodes_to_check.pop();
+ BLI_assert(reroute_node->type == NODE_REROUTE);
+ if (r_reroute_types.add(reroute_node, current_type)) {
+ for (bNodeLink *link : links_map.lookup((bNodeSocket *)reroute_node->inputs.first)) {
+ if (link->fromnode->type == NODE_REROUTE) {
+ nodes_to_check.push(link->fromnode);
+ }
}
- }
- nodeRemoveSocket(ntree, node, input);
- }
-
- if (output->type != type) {
- bNodeSocket *noutput = nodeAddSocket(ntree, node, SOCK_OUT, type_idname, "output", "Output");
- for (link = ntree->links.first; link; link = link->next) {
- if (link->fromsock == output) {
- link->fromsock = noutput;
+ for (bNodeLink *link : links_map.lookup((bNodeSocket *)reroute_node->outputs.first)) {
+ if (link->tonode->type == NODE_REROUTE) {
+ nodes_to_check.push(link->tonode);
+ }
}
}
- nodeRemoveSocket(ntree, node, output);
}
-
- nodeUpdateInternalLinks(ntree, node);
}
/* Global update function for Reroute node types.
@@ -363,16 +331,58 @@ static void node_reroute_inherit_type_recursive(bNodeTree *ntree, bNode *node, i
*/
void ntree_update_reroute_nodes(bNodeTree *ntree)
{
- bNode *node;
+ /* Contains nodes that are linked to at least one reroute node. */
+ Set<bNode *> nodes_linked_with_reroutes;
+ /* Contains all links that are linked to at least one reroute node. */
+ MultiValueMap<bNodeSocket *, bNodeLink *> links_map;
+ /* Build acceleration data structures for the algorithm below. */
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ if (link->fromsock == nullptr || link->tosock == nullptr) {
+ continue;
+ }
+ if (link->fromnode->type != NODE_REROUTE && link->tonode->type != NODE_REROUTE) {
+ continue;
+ }
+ if (link->fromnode->type != NODE_REROUTE) {
+ nodes_linked_with_reroutes.add(link->fromnode);
+ }
+ if (link->tonode->type != NODE_REROUTE) {
+ nodes_linked_with_reroutes.add(link->tonode);
+ }
+ links_map.add(link->fromsock, link);
+ links_map.add(link->tosock, link);
+ }
+
+ /* Will contain the socket type for every linked reroute node. */
+ Map<bNode *, const bNodeSocketType *> reroute_types;
+
+ /* Propagate socket types from left to right. */
+ for (bNode *start_node : nodes_linked_with_reroutes) {
+ LISTBASE_FOREACH (bNodeSocket *, output_socket, &start_node->outputs) {
+ propagate_reroute_type_from_start_socket(output_socket, links_map, reroute_types);
+ }
+ }
- /* clear tags */
- for (node = ntree->nodes.first; node; node = node->next) {
- node->done = 0;
+ /* Propagate socket types from right to left. This affects reroute nodes that haven't been
+ * changed in the the loop above. */
+ for (bNode *start_node : nodes_linked_with_reroutes) {
+ LISTBASE_FOREACH (bNodeSocket *, input_socket, &start_node->inputs) {
+ propagate_reroute_type_from_start_socket(input_socket, links_map, reroute_types);
+ }
}
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == NODE_REROUTE && !node->done) {
- node_reroute_inherit_type_recursive(ntree, node, REFINE_FORWARD | REFINE_BACKWARD);
+ /* Actually update reroute nodes with changed types. */
+ for (const auto &item : reroute_types.items()) {
+ bNode *reroute_node = item.key;
+ const bNodeSocketType *socket_type = item.value;
+ bNodeSocket *input_socket = (bNodeSocket *)reroute_node->inputs.first;
+ bNodeSocket *output_socket = (bNodeSocket *)reroute_node->outputs.first;
+
+ if (input_socket->typeinfo != socket_type) {
+ nodeModifySocketType(ntree, reroute_node, input_socket, socket_type->idname);
+ }
+ if (output_socket->typeinfo != socket_type) {
+ nodeModifySocketType(ntree, reroute_node, output_socket, socket_type->idname);
}
}
}
@@ -393,7 +403,7 @@ static bool node_is_connected_to_output_recursive(bNodeTree *ntree, bNode *node)
}
/* test all connected nodes, first positive find is sufficient to return true */
- for (link = ntree->links.first; link; link = link->next) {
+ for (link = (bNodeLink *)ntree->links.first; link; link = link->next) {
if (link->fromnode == node) {
if (node_is_connected_to_output_recursive(ntree, link->tonode)) {
return true;
@@ -408,7 +418,7 @@ bool BKE_node_is_connected_to_output(bNodeTree *ntree, bNode *node)
bNode *tnode;
/* clear flags */
- for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) {
+ for (tnode = (bNode *)ntree->nodes.first; tnode; tnode = tnode->next) {
tnode->done = 0;
}
@@ -419,9 +429,9 @@ void BKE_node_tree_unlink_id(ID *id, struct bNodeTree *ntree)
{
bNode *node;
- for (node = ntree->nodes.first; node; node = node->next) {
+ for (node = (bNode *)ntree->nodes.first; node; node = node->next) {
if (node->id == id) {
- node->id = NULL;
+ node->id = nullptr;
}
}
}
@@ -440,17 +450,17 @@ static void node_group_input_init(bNodeTree *ntree, bNode *node)
bNodeSocket *node_group_input_find_socket(bNode *node, const char *identifier)
{
bNodeSocket *sock;
- for (sock = node->outputs.first; sock; sock = sock->next) {
+ for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock->next) {
if (STREQ(sock->identifier, identifier)) {
return sock;
}
}
- return NULL;
+ return nullptr;
}
void node_group_input_update(bNodeTree *ntree, bNode *node)
{
- bNodeSocket *extsock = node->outputs.last;
+ bNodeSocket *extsock = (bNodeSocket *)node->outputs.last;
bNodeLink *link, *linknext, *exposelink;
/* Adding a tree socket and verifying will remove the extension socket!
* This list caches the existing links from the extension socket
@@ -460,14 +470,14 @@ void node_group_input_update(bNodeTree *ntree, bNode *node)
/* find links from the extension socket and store them */
BLI_listbase_clear(&tmplinks);
- for (link = ntree->links.first; link; link = linknext) {
+ for (link = (bNodeLink *)ntree->links.first; link; link = linknext) {
linknext = link->next;
if (nodeLinkIsHidden(link)) {
continue;
}
if (link->fromsock == extsock) {
- bNodeLink *tlink = MEM_callocN(sizeof(bNodeLink), "temporary link");
+ bNodeLink *tlink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "temporary link");
*tlink = *link;
BLI_addtail(&tmplinks, tlink);
@@ -476,8 +486,8 @@ void node_group_input_update(bNodeTree *ntree, bNode *node)
}
/* find valid link to expose */
- exposelink = NULL;
- for (link = tmplinks.first; link; link = link->next) {
+ exposelink = nullptr;
+ for (link = (bNodeLink *)tmplinks.first; link; link = link->next) {
/* XXX Multiple sockets can be connected to the extension socket at once,
* in that case the arbitrary first link determines name and type.
* This could be improved by choosing the "best" type among all links,
@@ -498,7 +508,7 @@ void node_group_input_update(bNodeTree *ntree, bNode *node)
newsock = node_group_input_find_socket(node, gsock->identifier);
/* redirect links from the extension socket */
- for (link = tmplinks.first; link; link = link->next) {
+ for (link = (bNodeLink *)tmplinks.first; link; link = link->next) {
nodeAddLink(ntree, node, newsock, link->tonode, link->tosock);
}
}
@@ -518,7 +528,7 @@ void node_group_input_update(bNodeTree *ntree, bNode *node)
void register_node_type_group_input(void)
{
/* used for all tree types, needs dynamic allocation */
- bNodeType *ntype = MEM_callocN(sizeof(bNodeType), "node type");
+ bNodeType *ntype = (bNodeType *)MEM_callocN(sizeof(bNodeType), "node type");
ntype->free_self = (void (*)(bNodeType *))MEM_freeN;
node_type_base(ntype, NODE_GROUP_INPUT, "Group Input", NODE_CLASS_INTERFACE, 0);
@@ -537,17 +547,17 @@ static void node_group_output_init(bNodeTree *ntree, bNode *node)
bNodeSocket *node_group_output_find_socket(bNode *node, const char *identifier)
{
bNodeSocket *sock;
- for (sock = node->inputs.first; sock; sock = sock->next) {
+ for (sock = (bNodeSocket *)node->inputs.first; sock; sock = sock->next) {
if (STREQ(sock->identifier, identifier)) {
return sock;
}
}
- return NULL;
+ return nullptr;
}
void node_group_output_update(bNodeTree *ntree, bNode *node)
{
- bNodeSocket *extsock = node->inputs.last;
+ bNodeSocket *extsock = (bNodeSocket *)node->inputs.last;
bNodeLink *link, *linknext, *exposelink;
/* Adding a tree socket and verifying will remove the extension socket!
* This list caches the existing links to the extension socket
@@ -557,14 +567,14 @@ void node_group_output_update(bNodeTree *ntree, bNode *node)
/* find links to the extension socket and store them */
BLI_listbase_clear(&tmplinks);
- for (link = ntree->links.first; link; link = linknext) {
+ for (link = (bNodeLink *)ntree->links.first; link; link = linknext) {
linknext = link->next;
if (nodeLinkIsHidden(link)) {
continue;
}
if (link->tosock == extsock) {
- bNodeLink *tlink = MEM_callocN(sizeof(bNodeLink), "temporary link");
+ bNodeLink *tlink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "temporary link");
*tlink = *link;
BLI_addtail(&tmplinks, tlink);
@@ -573,8 +583,8 @@ void node_group_output_update(bNodeTree *ntree, bNode *node)
}
/* find valid link to expose */
- exposelink = NULL;
- for (link = tmplinks.first; link; link = link->next) {
+ exposelink = nullptr;
+ for (link = (bNodeLink *)tmplinks.first; link; link = link->next) {
/* XXX Multiple sockets can be connected to the extension socket at once,
* in that case the arbitrary first link determines name and type.
* This could be improved by choosing the "best" type among all links,
@@ -596,7 +606,7 @@ void node_group_output_update(bNodeTree *ntree, bNode *node)
newsock = node_group_output_find_socket(node, gsock->identifier);
/* redirect links to the extension socket */
- for (link = tmplinks.first; link; link = link->next) {
+ for (link = (bNodeLink *)tmplinks.first; link; link = link->next) {
nodeAddLink(ntree, link->fromnode, link->fromsock, node, newsock);
}
}
@@ -616,7 +626,7 @@ void node_group_output_update(bNodeTree *ntree, bNode *node)
void register_node_type_group_output(void)
{
/* used for all tree types, needs dynamic allocation */
- bNodeType *ntype = MEM_callocN(sizeof(bNodeType), "node type");
+ bNodeType *ntype = (bNodeType *)MEM_callocN(sizeof(bNodeType), "node type");
ntype->free_self = (void (*)(bNodeType *))MEM_freeN;
node_type_base(ntype, NODE_GROUP_OUTPUT, "Group Output", NODE_CLASS_INTERFACE, 0);
diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc
index 31260f95242..4334f1b5030 100644
--- a/source/blender/nodes/intern/node_socket.cc
+++ b/source/blender/nodes/intern/node_socket.cc
@@ -872,7 +872,7 @@ static bNodeSocketType *make_socket_type_material()
void register_standard_node_socket_types(void)
{
- /* draw callbacks are set in drawnode.c to avoid bad-level calls */
+ /* Draw callbacks are set in `drawnode.c` to avoid bad-level calls. */
nodeRegisterSocketType(make_socket_type_float(PROP_NONE));
nodeRegisterSocketType(make_socket_type_float(PROP_UNSIGNED));
diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc
index 641d02af902..43c7fbd2599 100644
--- a/source/blender/nodes/intern/node_tree_ref.cc
+++ b/source/blender/nodes/intern/node_tree_ref.cc
@@ -19,6 +19,7 @@
#include "NOD_node_tree_ref.hh"
#include "BLI_dot_export.hh"
+#include "BLI_stack.hh"
namespace blender::nodes {
@@ -473,6 +474,108 @@ bool NodeTreeRef::has_undefined_nodes_or_sockets() const
return false;
}
+bool NodeRef::any_input_is_directly_linked() const
+{
+ for (const SocketRef *socket : inputs_) {
+ if (!socket->directly_linked_sockets().is_empty()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool NodeRef::any_output_is_directly_linked() const
+{
+ for (const SocketRef *socket : outputs_) {
+ if (!socket->directly_linked_sockets().is_empty()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool NodeRef::any_socket_is_directly_linked(eNodeSocketInOut in_out) const
+{
+ if (in_out == SOCK_IN) {
+ return this->any_input_is_directly_linked();
+ }
+ return this->any_output_is_directly_linked();
+}
+
+/**
+ * Sort nodes topologically from left to right or right to left.
+ * In the future the result if this could be cached on #NodeTreeRef.
+ */
+Vector<const NodeRef *> NodeTreeRef::toposort(const ToposortDirection direction) const
+{
+ struct Item {
+ const NodeRef *node;
+ /* Index of the next socket that is checked in the depth-first search. */
+ int socket_index = 0;
+ /* Link index in the next socket that is checked in the depth-first search. */
+ int link_index = 0;
+ };
+
+ Vector<const NodeRef *> toposort;
+ toposort.reserve(nodes_by_id_.size());
+ Array<bool> node_is_done_by_id(nodes_by_id_.size(), false);
+ Stack<Item> nodes_to_check;
+
+ for (const NodeRef *start_node : nodes_by_id_) {
+ if (node_is_done_by_id[start_node->id()]) {
+ /* Ignore nodes that are done already. */
+ continue;
+ }
+ if (start_node->any_socket_is_directly_linked(
+ direction == ToposortDirection::LeftToRight ? SOCK_OUT : SOCK_IN)) {
+ /* Ignore non-start nodes. */
+ continue;
+ }
+
+ /* Do a depth-first search to sort nodes topologically. */
+ nodes_to_check.push({start_node});
+ while (!nodes_to_check.is_empty()) {
+ Item &item = nodes_to_check.peek();
+ const NodeRef &node = *item.node;
+ const Span<const SocketRef *> sockets = node.sockets(
+ direction == ToposortDirection::LeftToRight ? SOCK_IN : SOCK_OUT);
+
+ while (true) {
+ if (item.socket_index == sockets.size()) {
+ /* All sockets have already been visited. */
+ break;
+ }
+ const SocketRef &socket = *sockets[item.socket_index];
+ const Span<const SocketRef *> linked_sockets = socket.directly_linked_sockets();
+ if (item.link_index == linked_sockets.size()) {
+ /* All links connected to this socket have already been visited. */
+ item.socket_index++;
+ item.link_index = 0;
+ continue;
+ }
+ const SocketRef &linked_socket = *linked_sockets[item.link_index];
+ const NodeRef &linked_node = linked_socket.node();
+ if (node_is_done_by_id[linked_node.id()]) {
+ /* The linked node has already been visited. */
+ item.link_index++;
+ continue;
+ }
+ nodes_to_check.push({&linked_node});
+ break;
+ }
+
+ /* If no other element has been pushed, the current node can be pushed to the sorted list. */
+ if (&item == &nodes_to_check.peek()) {
+ node_is_done_by_id[node.id()] = true;
+ toposort.append(&node);
+ nodes_to_check.pop();
+ }
+ }
+ }
+
+ return toposort;
+}
+
std::string NodeTreeRef::to_dot() const
{
dot::DirectedGraph digraph;
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c
index c3a675fcd20..83ee0c2f411 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -201,7 +201,7 @@ void register_node_tree_type_sh(void)
tt->type = NTREE_SHADER;
strcpy(tt->idname, "ShaderNodeTree");
strcpy(tt->ui_name, N_("Shader Editor"));
- tt->ui_icon = 0; /* defined in drawnode.c */
+ tt->ui_icon = 0; /* Defined in `drawnode.c`. */
strcpy(tt->ui_description, N_("Shader nodes"));
tt->foreach_nodeclass = foreach_nodeclass;
diff --git a/source/blender/nodes/shader/nodes/node_shader_brightness.c b/source/blender/nodes/shader/nodes/node_shader_brightness.c
index d8f560277f2..4f375c666de 100644
--- a/source/blender/nodes/shader/nodes/node_shader_brightness.c
+++ b/source/blender/nodes/shader/nodes/node_shader_brightness.c
@@ -19,7 +19,7 @@
#include "node_shader_util.h"
-/* **************** Brigh and contrsast ******************** */
+/* **************** Bright and contrast ******************** */
static bNodeSocketTemplate sh_node_brightcontrast_in[] = {
{SOCK_RGBA, N_("Color"), 1.0f, 1.0f, 1.0f, 1.0f},
diff --git a/source/blender/nodes/shader/nodes/node_shader_clamp.cc b/source/blender/nodes/shader/nodes/node_shader_clamp.cc
index 31d8f8ef15c..e8d4239937f 100644
--- a/source/blender/nodes/shader/nodes/node_shader_clamp.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_clamp.cc
@@ -27,6 +27,7 @@ namespace blender::nodes {
static void sh_node_clamp_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::Float>("Value").min(0.0f).max(1.0f).default_value(1.0f);
b.add_input<decl::Float>("Min").default_value(0.0f).min(-10000.0f).max(10000.0f);
b.add_input<decl::Float>("Max").default_value(1.0f).min(-10000.0f).max(10000.0f);
diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.cc b/source/blender/nodes/shader/nodes/node_shader_curves.cc
index e4ada06133e..8657d9e517d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_curves.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_curves.cc
@@ -27,6 +27,7 @@ namespace blender::nodes {
static void sh_node_curve_vec_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::Float>("Fac").min(0.0f).max(1.0f).default_value(1.0f).subtype(PROP_FACTOR);
b.add_input<decl::Vector>("Vector").min(-1.0f).max(1.0f);
b.add_output<decl::Vector>("Vector");
@@ -342,3 +343,142 @@ void register_node_type_sh_curve_rgb(void)
nodeRegisterType(&ntype);
}
+
+/* **************** CURVE FLOAT ******************** */
+
+namespace blender::nodes {
+
+static void sh_node_curve_float_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>("Factor").min(0.0f).max(1.0f).default_value(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Float>("Value").default_value(1.0f);
+ b.add_output<decl::Float>("Value");
+};
+
+} // namespace blender::nodes
+
+static void node_shader_exec_curve_float(void *UNUSED(data),
+ int UNUSED(thread),
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ bNodeStack **in,
+ bNodeStack **out)
+{
+ float value;
+ float fac;
+
+ nodestack_get_vec(&fac, SOCK_FLOAT, in[0]);
+ nodestack_get_vec(&value, SOCK_FLOAT, in[1]);
+ out[0]->vec[0] = BKE_curvemapping_evaluateF((CurveMapping *)node->storage, 0, value);
+ if (fac != 1.0f) {
+ out[0]->vec[0] = (1.0f - fac) * value + fac * out[0]->vec[0];
+ }
+}
+
+static void node_shader_init_curve_float(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node->storage = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+}
+
+static int gpu_shader_curve_float(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ float *array, layer;
+ int size;
+
+ CurveMapping *cumap = (CurveMapping *)node->storage;
+
+ BKE_curvemapping_table_F(cumap, &array, &size);
+ GPUNodeLink *tex = GPU_color_band(mat, size, array, &layer);
+
+ float ext_xyz[4];
+ float range_x;
+
+ const CurveMap *cm = &cumap->cm[0];
+ ext_xyz[0] = cm->mintable;
+ ext_xyz[2] = cm->maxtable;
+ range_x = 1.0f / max_ff(1e-8f, cm->maxtable - cm->mintable);
+ /* Compute extrapolation gradients. */
+ if ((cumap->flag & CUMA_EXTEND_EXTRAPOLATE) != 0) {
+ ext_xyz[1] = (cm->ext_in[0] != 0.0f) ? (cm->ext_in[1] / (cm->ext_in[0] * range_x)) : 1e8f;
+ ext_xyz[3] = (cm->ext_out[0] != 0.0f) ? (cm->ext_out[1] / (cm->ext_out[0] * range_x)) : 1e8f;
+ }
+ else {
+ ext_xyz[1] = 0.0f;
+ ext_xyz[3] = 0.0f;
+ }
+ return GPU_stack_link(mat,
+ node,
+ "curve_float",
+ in,
+ out,
+ tex,
+ GPU_constant(&layer),
+ GPU_uniform(&range_x),
+ GPU_uniform(ext_xyz));
+}
+
+class CurveFloatFunction : public blender::fn::MultiFunction {
+ private:
+ const CurveMapping &cumap_;
+
+ public:
+ CurveFloatFunction(const CurveMapping &cumap) : cumap_(cumap)
+ {
+ static blender::fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static blender::fn::MFSignature create_signature()
+ {
+ blender::fn::MFSignatureBuilder signature{"Curve Float"};
+ signature.single_input<float>("Factor");
+ signature.single_input<float>("Value");
+ signature.single_output<float>("Value");
+ return signature.build();
+ }
+
+ void call(blender::IndexMask mask,
+ blender::fn::MFParams params,
+ blender::fn::MFContext UNUSED(context)) const override
+ {
+ const blender::VArray<float> &fac = params.readonly_single_input<float>(0, "Factor");
+ const blender::VArray<float> &val_in = params.readonly_single_input<float>(1, "Value");
+ blender::MutableSpan<float> val_out = params.uninitialized_single_output<float>(2, "Value");
+
+ for (int64_t i : mask) {
+ val_out[i] = BKE_curvemapping_evaluateF(&cumap_, 0, val_in[i]);
+ if (fac[i] != 1.0f) {
+ val_out[i] = (1.0f - fac[i]) * val_in[i] + fac[i] * val_out[i];
+ }
+ }
+ }
+};
+
+static void sh_node_curve_float_build_multi_function(
+ blender::nodes::NodeMultiFunctionBuilder &builder)
+{
+ bNode &bnode = builder.node();
+ CurveMapping *cumap = (CurveMapping *)bnode.storage;
+ BKE_curvemapping_init(cumap);
+ builder.construct_and_set_matching_fn<CurveFloatFunction>(*cumap);
+}
+
+void register_node_type_sh_curve_float(void)
+{
+ static bNodeType ntype;
+
+ sh_fn_node_type_base(&ntype, SH_NODE_CURVE_FLOAT, "Float Curve", NODE_CLASS_CONVERTER, 0);
+ ntype.declare = blender::nodes::sh_node_curve_float_declare;
+ node_type_init(&ntype, node_shader_init_curve_float);
+ node_type_size_preset(&ntype, NODE_SIZE_LARGE);
+ node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
+ node_type_exec(&ntype, node_initexec_curves, nullptr, node_shader_exec_curve_float);
+ node_type_gpu(&ntype, gpu_shader_curve_float);
+ ntype.build_multi_function = sh_node_curve_float_build_multi_function;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_hair_info.c b/source/blender/nodes/shader/nodes/node_shader_hair_info.c
index 843185befb6..c721fb9c77a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_hair_info.c
+++ b/source/blender/nodes/shader/nodes/node_shader_hair_info.c
@@ -22,6 +22,7 @@
static bNodeSocketTemplate outputs[] = {
{SOCK_FLOAT, N_("Is Strand"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{SOCK_FLOAT, N_("Intercept"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ {SOCK_FLOAT, N_("Length"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{SOCK_FLOAT, N_("Thickness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{SOCK_VECTOR, N_("Tangent Normal"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
// { SOCK_FLOAT, 0, N_("Fade"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
@@ -35,7 +36,11 @@ static int node_shader_gpu_hair_info(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- return GPU_stack_link(mat, node, "node_hair_info", in, out);
+ /* Length: don't request length if not needed. */
+ static const float zero = 0;
+ GPUNodeLink *length_link = (!out[2].hasoutput) ? GPU_constant(&zero) :
+ GPU_attribute(mat, CD_HAIRLENGTH, "");
+ return GPU_stack_link(mat, node, "node_hair_info", in, out, length_link);
}
/* node type definition */
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 a5f9a24a728..5ea194ddc83 100644
--- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc
@@ -29,6 +29,7 @@ namespace blender::nodes {
static void sh_node_map_range_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::Float>("Value").min(-10000.0f).max(10000.0f).default_value(1.0f);
b.add_input<decl::Float>("From Min").min(-10000.0f).max(10000.0f);
b.add_input<decl::Float>("From Max").min(-10000.0f).max(10000.0f).default_value(1.0f);
diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc
index 80a27b8e6a1..96d1be49c04 100644
--- a/source/blender/nodes/shader/nodes/node_shader_math.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_math.cc
@@ -31,6 +31,7 @@ namespace blender::nodes {
static void sh_node_math_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::Float>("Value").default_value(0.5f).min(-10000.0f).max(10000.0f);
b.add_input<decl::Float>("Value", "Value_001").default_value(0.5f).min(-10000.0f).max(10000.0f);
b.add_input<decl::Float>("Value", "Value_002").default_value(0.5f).min(-10000.0f).max(10000.0f);
diff --git a/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc b/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc
index 860cc260d5d..d4d02e80ada 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc
@@ -27,6 +27,7 @@ namespace blender::nodes {
static void sh_node_mix_rgb_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::Float>("Fac").default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
b.add_input<decl::Color>("Color1").default_value({0.5f, 0.5f, 0.5f, 1.0f});
b.add_input<decl::Color>("Color2").default_value({0.5f, 0.5f, 0.5f, 1.0f});
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc b/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc
index 63be399366f..24c5dcf7ba3 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc
@@ -27,6 +27,7 @@ namespace blender::nodes {
static void sh_node_seprgb_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::Color>("Image").default_value({0.8f, 0.8f, 0.8f, 1.0f});
b.add_output<decl::Float>("R");
b.add_output<decl::Float>("G");
@@ -119,6 +120,7 @@ namespace blender::nodes {
static void sh_node_combrgb_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::Float>("R").min(0.0f).max(1.0f);
b.add_input<decl::Float>("G").min(0.0f).max(1.0f);
b.add_input<decl::Float>("B").min(0.0f).max(1.0f);
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc b/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc
index b4b3c48482f..8ca8fc19521 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc
@@ -27,6 +27,7 @@ namespace blender::nodes {
static void sh_node_sepxyz_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::Vector>("Vector").min(-10000.0f).max(10000.0f);
b.add_output<decl::Float>("X");
b.add_output<decl::Float>("Y");
@@ -103,6 +104,7 @@ namespace blender::nodes {
static void sh_node_combxyz_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::Float>("X").min(-10000.0f).max(10000.0f);
b.add_input<decl::Float>("Y").min(-10000.0f).max(10000.0f);
b.add_input<decl::Float>("Z").min(-10000.0f).max(10000.0f);
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 d33d92f25fd..23f150d8135 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc
@@ -23,6 +23,7 @@ namespace blender::nodes {
static void sh_node_tex_musgrave_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::Vector>("Vector").hide_value();
b.add_input<decl::Float>("W").min(-1000.0f).max(1000.0f);
b.add_input<decl::Float>("Scale").min(-1000.0f).max(1000.0f).default_value(5.0f);
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 1ae6b3a616c..6ffc8979815 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc
@@ -25,7 +25,8 @@ namespace blender::nodes {
static void sh_node_tex_noise_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Vector>("Vector").hide_value();
+ b.is_function_node();
+ b.add_input<decl::Vector>("Vector").implicit_field();
b.add_input<decl::Float>("W").min(-1000.0f).max(1000.0f);
b.add_input<decl::Float>("Scale").min(-1000.0f).max(1000.0f).default_value(5.0f);
b.add_input<decl::Float>("Detail").min(0.0f).max(16.0f).default_value(2.0f);
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 cea7af247c1..e12e5724e8e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc
@@ -23,6 +23,7 @@ namespace blender::nodes {
static void sh_node_tex_voronoi_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::Vector>("Vector").hide_value();
b.add_input<decl::Float>("W").min(-1000.0f).max(1000.0f);
b.add_input<decl::Float>("Scale").min(-1000.0f).max(1000.0f).default_value(5.0f);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc
index bae16e10120..03543e5f7fe 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
@@ -23,6 +23,7 @@ namespace blender::nodes {
static void sh_node_tex_white_noise_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::Vector>("Vector").min(-10000.0f).max(10000.0f);
b.add_input<decl::Float>("W").min(-10000.0f).max(10000.0f);
b.add_output<decl::Float>("Value");
diff --git a/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc b/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc
index 1870caffbb1..d4d08be5d49 100644
--- a/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc
@@ -33,6 +33,7 @@ namespace blender::nodes {
static void sh_node_valtorgb_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::Float>("Fac").default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
b.add_output<decl::Color>("Color");
b.add_output<decl::Float>("Alpha");
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 5b24e8bb72d..f49ff06cef1 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc
@@ -29,6 +29,7 @@ namespace blender::nodes {
static void sh_node_vector_math_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::Vector>("Vector").min(-10000.0f).max(10000.0f);
b.add_input<decl::Vector>("Vector", "Vector_001").min(-10000.0f).max(10000.0f);
b.add_input<decl::Vector>("Vector", "Vector_002").min(-10000.0f).max(10000.0f);
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 e9fd6c4f31e..c9b26fa5199 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
@@ -27,12 +27,13 @@ namespace blender::nodes {
static void sh_node_vector_rotate_declare(NodeDeclarationBuilder &b)
{
+ b.is_function_node();
b.add_input<decl::Vector>("Vector").min(0.0f).max(1.0f).hide_value();
- b.add_input<decl::Vector>("Vector");
+ b.add_input<decl::Vector>("Center");
b.add_input<decl::Vector>("Axis").min(-1.0f).max(1.0f).default_value({0.0f, 0.0f, 1.0f});
b.add_input<decl::Float>("Angle").subtype(PROP_ANGLE);
b.add_input<decl::Vector>("Rotation").subtype(PROP_EULER);
- b.add_output<decl::Vector>("Value");
+ b.add_output<decl::Vector>("Vector");
};
} // namespace blender::nodes
diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c
index 7452007639c..14597050524 100644
--- a/source/blender/nodes/texture/node_texture_tree.c
+++ b/source/blender/nodes/texture/node_texture_tree.c
@@ -169,7 +169,7 @@ void register_node_tree_type_tex(void)
tt->type = NTREE_TEXTURE;
strcpy(tt->idname, "TextureNodeTree");
strcpy(tt->ui_name, N_("Texture Node Editor"));
- tt->ui_icon = 0; /* defined in drawnode.c */
+ tt->ui_icon = 0; /* Defined in `drawnode.c`. */
strcpy(tt->ui_description, N_("Texture nodes"));
tt->foreach_nodeclass = foreach_nodeclass;
diff --git a/source/blender/nodes/texture/nodes/node_texture_curves.c b/source/blender/nodes/texture/nodes/node_texture_curves.c
index 70f7e731720..f61e3f36db5 100644
--- a/source/blender/nodes/texture/nodes/node_texture_curves.c
+++ b/source/blender/nodes/texture/nodes/node_texture_curves.c
@@ -26,7 +26,7 @@
/* **************** CURVE Time ******************** */
-/* custom1 = sfra, custom2 = efra */
+/* custom1 = start-frame, custom2 = end-frame. */
static bNodeSocketTemplate time_outputs[] = {{SOCK_FLOAT, N_("Value")}, {-1, ""}};
static void time_colorfn(