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
path: root/source
diff options
context:
space:
mode:
authorKévin Dietrich <kevin.dietrich@mailoo.org>2021-12-22 15:07:46 +0300
committerKévin Dietrich <kevin.dietrich@mailoo.org>2021-12-22 15:07:46 +0300
commit74138fb2d4ac9f0504c8f9f575bf392b49fc7488 (patch)
treec383efca92710d0a4b3ffce5ad74ac7758f64ce8 /source
parent2529300f691109b9575ea75ae8367209751c3738 (diff)
parentd2bf60cc17a961789d7c415fc3d2af14afa50f62 (diff)
Merge branch 'master' into temp-abc-features
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_action.h22
-rw-r--r--source/blender/blenkernel/BKE_fcurve_driver.h7
-rw-r--r--source/blender/blenkernel/BKE_node.h25
-rw-r--r--source/blender/blenkernel/BKE_node_tree_update.h109
-rw-r--r--source/blender/blenkernel/BKE_undo_system.h2
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/action.c20
-rw-r--r--source/blender/blenkernel/intern/asset_catalog.cc16
-rw-r--r--source/blender/blenkernel/intern/asset_catalog_test.cc38
-rw-r--r--source/blender/blenkernel/intern/blendfile_link_append.c34
-rw-r--r--source/blender/blenkernel/intern/curve.cc69
-rw-r--r--source/blender/blenkernel/intern/curveprofile.cc2
-rw-r--r--source/blender/blenkernel/intern/fcurve_driver.c7
-rw-r--r--source/blender/blenkernel/intern/image.c13
-rw-r--r--source/blender/blenkernel/intern/lib_override.c5
-rw-r--r--source/blender/blenkernel/intern/lib_remap.c2
-rw-r--r--source/blender/blenkernel/intern/linestyle.c3
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.cc10
-rw-r--r--source/blender/blenkernel/intern/movieclip.c13
-rw-r--r--source/blender/blenkernel/intern/node.cc920
-rw-r--r--source/blender/blenkernel/intern/node_tree_update.cc1658
-rw-r--r--source/blender/blenkernel/intern/spline_nurbs.cc4
-rw-r--r--source/blender/blenkernel/intern/volume.cc13
-rw-r--r--source/blender/blenlib/BLI_assert.h1
-rw-r--r--source/blender/blenlib/BLI_color.hh19
-rw-r--r--source/blender/blenlib/BLI_compiler_compat.h2
-rw-r--r--source/blender/blenlib/BLI_delaunay_2d.h2
-rw-r--r--source/blender/blenlib/BLI_dlrbTree.h6
-rw-r--r--source/blender/blenlib/BLI_endian_switch.h2
-rw-r--r--source/blender/blenlib/BLI_endian_switch_inline.h3
-rw-r--r--source/blender/blenlib/BLI_fileops.hh52
-rw-r--r--source/blender/blenlib/BLI_filereader.h12
-rw-r--r--source/blender/blenlib/BLI_ghash.h2
-rw-r--r--source/blender/blenlib/BLI_kdtree_impl.h2
-rw-r--r--source/blender/blenlib/BLI_linklist_lockfree.h11
-rw-r--r--source/blender/blenlib/BLI_listbase.h29
-rw-r--r--source/blender/blenlib/BLI_math_base.h6
-rw-r--r--source/blender/blenlib/BLI_math_bits.h5
-rw-r--r--source/blender/blenlib/BLI_math_geom.h6
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h21
-rw-r--r--source/blender/blenlib/BLI_math_rotation.h30
-rw-r--r--source/blender/blenlib/BLI_math_vector.h2
-rw-r--r--source/blender/blenlib/BLI_mempool.h4
-rw-r--r--source/blender/blenlib/BLI_quadric.h9
-rw-r--r--source/blender/blenlib/BLI_scanfill.h1
-rw-r--r--source/blender/blenlib/BLI_session_uuid.h7
-rw-r--r--source/blender/blenlib/BLI_sort.h2
-rw-r--r--source/blender/blenlib/BLI_sys_types.h2
-rw-r--r--source/blender/blenlib/BLI_system.h10
-rw-r--r--source/blender/blenlib/BLI_task.h2
-rw-r--r--source/blender/blenlib/BLI_threads.h2
-rw-r--r--source/blender/blenlib/BLI_timer.h11
-rw-r--r--source/blender/blenlib/BLI_vector.hh2
-rw-r--r--source/blender/blenlib/BLI_virtual_array.hh4
-rw-r--r--source/blender/blenlib/BLI_virtual_vector_array.hh2
-rw-r--r--source/blender/blenlib/BLI_winstuff.h5
-rw-r--r--source/blender/blenlib/CMakeLists.txt3
-rw-r--r--source/blender/blenlib/intern/fileops.cc51
-rw-r--r--source/blender/blenlib/intern/listbase.c20
-rw-r--r--source/blender/blenlib/intern/task_scheduler.cc6
-rw-r--r--source/blender/blenlib/tests/BLI_fileops_test.cc40
-rw-r--r--source/blender/blenlib/tests/BLI_listbase_test.cc25
-rw-r--r--source/blender/blenlib/tests/BLI_vector_test.cc11
-rw-r--r--source/blender/blenloader/intern/versioning_250.c9
-rw-r--r--source/blender/blenloader/intern/versioning_280.c3
-rw-r--r--source/blender/blenloader/intern/versioning_300.c62
-rw-r--r--source/blender/blenloader/intern/versioning_common.cc20
-rw-r--r--source/blender/blenloader/intern/versioning_common.h2
-rw-r--r--source/blender/blenloader/intern/versioning_cycles.c29
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c5
-rw-r--r--source/blender/blenloader/tests/blendfile_loading_base_test.cc2
-rw-r--r--source/blender/compositor/intern/COM_compositor.cc2
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_build.h6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc4
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc73
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_rna.cc2
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc1
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc14
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_iter.cc9
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc6
-rw-r--r--source/blender/depsgraph/intern/node/deg_node.cc4
-rw-r--r--source/blender/depsgraph/intern/node/deg_node.h2
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_component.cc2
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_component.h1
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_operation.cc3
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_operation.h3
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_shader_fx.c7
-rw-r--r--source/blender/editors/animation/drivers.c10
-rw-r--r--source/blender/editors/animation/keyframes_general.c35
-rw-r--r--source/blender/editors/armature/pose_edit.c2
-rw-r--r--source/blender/editors/armature/pose_lib.c2
-rw-r--r--source/blender/editors/armature/pose_select.c2
-rw-r--r--source/blender/editors/asset/intern/asset_indexer.cc7
-rw-r--r--source/blender/editors/asset/intern/asset_ops.cc8
-rw-r--r--source/blender/editors/asset/intern/asset_temp_id_consumer.cc5
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c12
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h5
-rw-r--r--source/blender/editors/include/ED_node.h22
-rw-r--r--source/blender/editors/interface/interface_ops.c24
-rw-r--r--source/blender/editors/interface/interface_templates.c2
-rw-r--r--source/blender/editors/interface/interface_view.cc4
-rw-r--r--source/blender/editors/object/object_constraint.c8
-rw-r--r--source/blender/editors/object/object_edit.c10
-rw-r--r--source/blender/editors/object/object_hook.c2
-rw-r--r--source/blender/editors/object/object_relations.c4
-rw-r--r--source/blender/editors/object/object_utils.c2
-rw-r--r--source/blender/editors/render/render_internal.c4
-rw-r--r--source/blender/editors/screen/screen_context.c2
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h59
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c45
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c3839
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_brushes.c2847
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h122
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_ops.c1141
-rw-r--r--source/blender/editors/space_file/asset_catalog_tree_view.cc5
-rw-r--r--source/blender/editors/space_info/info_stats.cc3
-rw-r--r--source/blender/editors/space_node/drawnode.cc4
-rw-r--r--source/blender/editors/space_node/link_drag_search.cc10
-rw-r--r--source/blender/editors/space_node/node_add.cc49
-rw-r--r--source/blender/editors/space_node/node_draw.cc50
-rw-r--r--source/blender/editors/space_node/node_edit.cc196
-rw-r--r--source/blender/editors/space_node/node_geometry_attribute_search.cc4
-rw-r--r--source/blender/editors/space_node/node_group.cc42
-rw-r--r--source/blender/editors/space_node/node_intern.hh5
-rw-r--r--source/blender/editors/space_node/node_relationships.cc239
-rw-r--r--source/blender/editors/space_node/node_templates.cc23
-rw-r--r--source/blender/editors/space_node/space_node.cc22
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.c38
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c10
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c15
-rw-r--r--source/blender/editors/space_spreadsheet/space_spreadsheet.cc9
-rw-r--r--source/blender/editors/space_topbar/space_topbar.c55
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_armature.c6
-rw-r--r--source/blender/editors/transform/transform_convert.c4
-rw-r--r--source/blender/editors/transform/transform_convert.h1
-rw-r--r--source/blender/editors/transform/transform_convert_armature.c2
-rw-r--r--source/blender/editors/transform/transform_convert_mask.c7
-rw-r--r--source/blender/editors/transform/transform_convert_node.c3
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer_image.c45
-rw-r--r--source/blender/editors/transform/transform_convert_tracking.c10
-rw-r--r--source/blender/editors/transform/transform_mode_timetranslate.c15
-rw-r--r--source/blender/editors/transform/transform_mode_translate.c7
-rw-r--r--source/blender/editors/transform/transform_orientations.c4
-rw-r--r--source/blender/editors/undo/ed_undo.c87
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c2
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp3
-rw-r--r--source/blender/geometry/intern/realize_instances.cc2
-rw-r--r--source/blender/gpu/GPU_state.h4
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.cc2
-rw-r--r--source/blender/gpu/opengl/gl_state.hh6
-rw-r--r--source/blender/imbuf/intern/transform.cc13
-rw-r--r--source/blender/io/collada/Materials.cpp4
-rw-r--r--source/blender/io/usd/intern/usd_reader_material.cc3
-rw-r--r--source/blender/makesdna/DNA_ID.h3
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h16
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h280
-rw-r--r--source/blender/makesdna/DNA_movieclip_types.h10
-rw-r--r--source/blender/makesdna/DNA_nla_types.h4
-rw-r--r--source/blender/makesdna/DNA_node_types.h118
-rw-r--r--source/blender/makesdna/DNA_object_force_types.h2
-rw-r--r--source/blender/makesdna/DNA_object_types.h48
-rw-r--r--source/blender/makesdna/DNA_particle_types.h47
-rw-r--r--source/blender/makesdna/DNA_pointcloud_types.h2
-rw-r--r--source/blender/makesdna/DNA_rigidbody_types.h16
-rw-r--r--source/blender/makesdna/DNA_scene_types.h55
-rw-r--r--source/blender/makesdna/DNA_screen_types.h8
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h71
-rw-r--r--source/blender/makesdna/DNA_shader_fx_types.h2
-rw-r--r--source/blender/makesdna/DNA_simulation_types.h2
-rw-r--r--source/blender/makesdna/DNA_space_types.h146
-rw-r--r--source/blender/makesdna/DNA_texture_types.h14
-rw-r--r--source/blender/makesdna/DNA_tracking_types.h40
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h13
-rw-r--r--source/blender/makesdna/DNA_view2d_types.h18
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h2
-rw-r--r--source/blender/makesdna/DNA_volume_types.h22
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h30
-rw-r--r--source/blender/makesdna/DNA_workspace_types.h4
-rw-r--r--source/blender/makesdna/intern/dna_utils.h4
-rw-r--r--source/blender/makesrna/intern/rna_color.c2
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c1
-rw-r--r--source/blender/makesrna/intern/rna_image.c2
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c143
-rw-r--r--source/blender/makesrna/intern/rna_scene.c2
-rw-r--r--source/blender/makesrna/intern/rna_texture.c2
-rw-r--r--source/blender/makesrna/intern/rna_tracking.c6
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c2
-rw-r--r--source/blender/modifiers/CMakeLists.txt2
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc7
-rw-r--r--source/blender/modifiers/intern/MOD_weld.cc (renamed from source/blender/modifiers/intern/MOD_weld.c)1169
-rw-r--r--source/blender/nodes/CMakeLists.txt4
-rw-r--r--source/blender/nodes/NOD_geometry.h2
-rw-r--r--source/blender/nodes/NOD_node_declaration.hh9
-rw-r--r--source/blender/nodes/NOD_socket_declarations.hh2
-rw-r--r--source/blender/nodes/NOD_static_types.h4
-rw-r--r--source/blender/nodes/composite/node_composite_tree.cc11
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_denoise.cc2
-rw-r--r--source/blender/nodes/geometry/CMakeLists.txt2
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc32
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc7
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc84
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_image_texture.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc142
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_raycast.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_switch.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_viewer.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc3
-rw-r--r--source/blender/nodes/intern/node_common.cc3
-rw-r--r--source/blender/nodes/intern/node_exec.cc3
-rw-r--r--source/blender/nodes/intern/node_socket.cc8
-rw-r--r--source/blender/nodes/intern/node_tree_ref.cc2
-rw-r--r--source/blender/nodes/intern/node_util.c183
-rw-r--r--source/blender/nodes/shader/node_shader_tree.c38
-rw-r--r--source/blender/nodes/texture/node_texture_tree.c17
-rw-r--r--source/blender/nodes/texture/node_texture_util.c17
-rw-r--r--source/blender/nodes/texture/node_texture_util.h4
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_output.c3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_viewer.c3
-rw-r--r--source/blender/render/intern/pipeline.c8
-rw-r--r--source/blender/sequencer/intern/sequencer.c5
-rw-r--r--source/blender/sequencer/intern/strip_add.c9
-rw-r--r--source/blender/sequencer/intern/strip_edit.c36
-rw-r--r--source/blender/sequencer/intern/strip_time.c4
-rw-r--r--source/blender/sequencer/intern/utils.c2
m---------source/tools0
283 files changed, 8731 insertions, 7350 deletions
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index ea8ee3f93b1..5dd98dbb9a3 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -253,12 +253,28 @@ void BKE_pose_channel_session_uuid_generate(struct bPoseChannel *pchan);
*/
struct bPoseChannel *BKE_pose_channel_find_name(const struct bPose *pose, const char *name);
/**
+ * Checks if the bone is on a visible armature layer
+ *
+ * \return true if on a visible layer, false otherwise.
+ */
+bool BKE_pose_is_layer_visible(const struct bArmature *arm, const struct bPoseChannel *pchan);
+/**
* Find the active pose-channel for an object
- * (we can't just use pose, as layer info is in armature)
*
- * \note #Object, not #bPose is used here, as we need layer info from Armature.
+ * \param check_arm_layer: checks if the bone is on a visible armature layer (this might be skipped
+ * (e.g. for "Show Active" from the Outliner).
+ * \return #bPoseChannel if found or NULL.
+ * \note #Object, not #bPose is used here, as we need info (layer/active bone) from Armature.
+ */
+struct bPoseChannel *BKE_pose_channel_active(struct Object *ob, const bool check_arm_layer);
+/**
+ * Find the active pose-channel for an object if it is on a visible armature layer
+ * (calls #BKE_pose_channel_active with check_arm_layer set to true)
+ *
+ * \return #bPoseChannel if found or NULL.
+ * \note #Object, not #bPose is used here, as we need info (layer/active bone) from Armature.
*/
-struct bPoseChannel *BKE_pose_channel_active(struct Object *ob);
+struct bPoseChannel *BKE_pose_channel_active_if_layer_visible(struct Object *ob);
/**
* Use this when detecting the "other selected bone",
* when we have multiple armatures in pose mode.
diff --git a/source/blender/blenkernel/BKE_fcurve_driver.h b/source/blender/blenkernel/BKE_fcurve_driver.h
index 18676dfcb38..7e4e0ad3c2a 100644
--- a/source/blender/blenkernel/BKE_fcurve_driver.h
+++ b/source/blender/blenkernel/BKE_fcurve_driver.h
@@ -105,6 +105,13 @@ void driver_change_variable_type(struct DriverVar *dvar, int type);
*/
void driver_variable_name_validate(struct DriverVar *dvar);
/**
+ * Ensure the driver variable's name is unique.
+ *
+ * Assumes the driver variable has already been assigned to the driver, so that
+ * the prev/next pointers can be used to find the other variables.
+ */
+void driver_variable_unique_name(struct DriverVar *dvar);
+/**
* Add a new driver variable.
*/
struct DriverVar *driver_add_new_variable(struct ChannelDriver *driver);
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index a2959556810..500d8e2e0ac 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -501,16 +501,13 @@ void ntreeFreeLocalTree(struct bNodeTree *ntree);
struct bNode *ntreeFindType(const struct bNodeTree *ntree, int type);
bool ntreeHasType(const struct bNodeTree *ntree, int type);
bool ntreeHasTree(const struct bNodeTree *ntree, const struct bNodeTree *lookup);
-void ntreeUpdateTree(struct Main *main, struct bNodeTree *ntree);
void ntreeUpdateAllNew(struct Main *main);
-/**
- * \param tree_update_flag: #eNodeTreeUpdate enum.
- */
-void ntreeUpdateAllUsers(struct Main *main, struct ID *id, int tree_update_flag);
+void ntreeUpdateAllUsers(struct Main *main, struct ID *id);
void ntreeGetDependencyList(struct bNodeTree *ntree,
struct bNode ***r_deplist,
int *r_deplist_len);
+void ntreeUpdateNodeLevels(struct bNodeTree *ntree);
/**
* XXX: old trees handle output flags automatically based on special output
@@ -833,10 +830,6 @@ void nodeClearActive(struct bNodeTree *ntree);
void nodeClearActiveID(struct bNodeTree *ntree, short idtype);
struct bNode *nodeGetActiveTexture(struct bNodeTree *ntree);
-void nodeUpdate(struct bNodeTree *ntree, struct bNode *node);
-bool nodeUpdateID(struct bNodeTree *ntree, struct ID *id);
-void nodeUpdateInternalLinks(struct bNodeTree *ntree, struct bNode *node);
-
int nodeSocketIsHidden(const struct bNodeSocket *sock);
void ntreeTagUsedSockets(struct bNodeTree *ntree);
void nodeSetSocketAvailability(struct bNodeTree *ntree,
@@ -960,10 +953,7 @@ bNodePreview *BKE_node_preview_verify(
struct bNodeInstanceHash *previews, bNodeInstanceKey key, int xsize, int ysize, bool create);
bNodePreview *BKE_node_preview_copy(struct bNodePreview *preview);
void BKE_node_preview_free(struct bNodePreview *preview);
-void BKE_node_preview_init_tree(struct bNodeTree *ntree,
- int xsize,
- int ysize,
- bool create_previews);
+void BKE_node_preview_init_tree(struct bNodeTree *ntree, int xsize, int ysize);
void BKE_node_preview_free_tree(struct bNodeTree *ntree);
void BKE_node_preview_remove_unused(struct bNodeTree *ntree);
void BKE_node_preview_clear(struct bNodePreview *preview);
@@ -974,14 +964,6 @@ void BKE_node_preview_merge_tree(struct bNodeTree *to_ntree,
struct bNodeTree *from_ntree,
bool remove_old);
-/**
- * Hack warning! this function is only used for shader previews,
- * and since it gets called multiple times per pixel for Z-transparency we only add the color once.
- * Preview gets cleared before it starts render though.
- */
-void BKE_node_preview_set_pixel(
- struct bNodePreview *preview, const float col[4], int x, int y, bool do_manage);
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -1170,7 +1152,6 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree,
#define SH_NODE_SEPRGB 120
#define SH_NODE_COMBRGB 121
#define SH_NODE_HUE_SAT 122
-#define NODE_DYNAMIC 123
#define SH_NODE_OUTPUT_MATERIAL 124
#define SH_NODE_OUTPUT_WORLD 125
diff --git a/source/blender/blenkernel/BKE_node_tree_update.h b/source/blender/blenkernel/BKE_node_tree_update.h
new file mode 100644
index 00000000000..ebaa56c89c9
--- /dev/null
+++ b/source/blender/blenkernel/BKE_node_tree_update.h
@@ -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.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup bke
+ */
+
+struct bNode;
+struct bNodeSocket;
+struct bNodeTree;
+struct bNodeLink;
+struct Main;
+struct ID;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Tag tree as changed without providing any more information about what has changed exactly.
+ * The update process has to assume that everything may have changed.
+ *
+ * Using one of the methods below to tag the tree after changes is preffered when possible.
+ */
+void BKE_ntree_update_tag_all(struct bNodeTree *ntree);
+
+/**
+ * More specialized tag functions that may result in a more efficient update.
+ */
+
+void BKE_ntree_update_tag_node_property(struct bNodeTree *ntree, struct bNode *node);
+void BKE_ntree_update_tag_node_new(struct bNodeTree *ntree, struct bNode *node);
+void BKE_ntree_update_tag_node_removed(struct bNodeTree *ntree);
+void BKE_ntree_update_tag_node_internal_link(struct bNodeTree *ntree, struct bNode *node);
+
+void BKE_ntree_update_tag_socket_property(struct bNodeTree *ntree, struct bNodeSocket *socket);
+void BKE_ntree_update_tag_socket_new(struct bNodeTree *ntree, struct bNodeSocket *socket);
+void BKE_ntree_update_tag_socket_type(struct bNodeTree *ntree, struct bNodeSocket *socket);
+void BKE_ntree_update_tag_socket_availability(struct bNodeTree *ntree, struct bNodeSocket *socket);
+void BKE_ntree_update_tag_socket_removed(struct bNodeTree *ntree);
+
+void BKE_ntree_update_tag_link_changed(struct bNodeTree *ntree);
+void BKE_ntree_update_tag_link_removed(struct bNodeTree *ntree);
+void BKE_ntree_update_tag_link_added(struct bNodeTree *ntree, struct bNodeLink *link);
+void BKE_ntree_update_tag_link_mute(struct bNodeTree *ntree, struct bNodeLink *link);
+
+/** Used after file loading when run-time data on the tree has not been initialized yet. */
+void BKE_ntree_update_tag_missing_runtime_data(struct bNodeTree *ntree);
+/** Used when the interface sockets/values have changed. */
+void BKE_ntree_update_tag_interface(struct bNodeTree *ntree);
+/** Used when an id data block changed that might be used by nodes that need to be updated. */
+void BKE_ntree_update_tag_id_changed(struct Main *bmain, struct ID *id);
+
+typedef struct NodeTreeUpdateExtraParams {
+ /**
+ * Data passed into the callbacks.
+ */
+ void *user_data;
+
+ /**
+ * Called for every tree that has been changed during the update. This can be used to send
+ * notifiers to trigger redraws or depsgraph updates.
+ */
+ void (*tree_changed_fn)(struct ID *, struct bNodeTree *, void *user_data);
+
+ /**
+ * Called for every tree whose output value may have changed based on the provided update tags.
+ * This can be used to tag the depsgraph if necessary.
+ */
+ void (*tree_output_changed_fn)(struct ID *, struct bNodeTree *, void *user_data);
+} NodeTreeUpdateExtraParams;
+
+/**
+ * Updates #bmain based on changes to node trees.
+ */
+void BKE_ntree_update_main(struct Main *bmain, struct NodeTreeUpdateExtraParams *params);
+
+/**
+ * Same as #BKE_ntree_update_main, but will first only look at the provided tree and only looks
+ * at #bmain when something relevant for other data-blocks changed. This avoids scanning #bmain in
+ * many cases.
+ *
+ * If #bmain is null, only the provided tree is updated. This should only be used in very rare
+ * cases because it may result it incorrectly synced data in DNA.
+ *
+ * If #tree is null, this is the same as calling #BKE_ntree_update_main.
+ */
+void BKE_ntree_update_main_tree(struct Main *bmain,
+ struct bNodeTree *ntree,
+ struct NodeTreeUpdateExtraParams *params);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/blenkernel/BKE_undo_system.h b/source/blender/blenkernel/BKE_undo_system.h
index 6e1f9468ce4..44893a6f030 100644
--- a/source/blender/blenkernel/BKE_undo_system.h
+++ b/source/blender/blenkernel/BKE_undo_system.h
@@ -91,7 +91,7 @@ typedef struct UndoStep {
/** When this is true, undo/memfile read code is allowed to re-use old data-blocks for unchanged
* IDs, and existing depsgraphes. This has to be forbidden in some cases (like renamed IDs). */
bool use_old_bmain_data;
- /** For use by undo systems that accumulate changes (text editor, painting). */
+ /** For use by undo systems that accumulate changes (mesh-sculpt & image-painting). */
bool is_applied;
/* Over alloc 'type->struct_size'. */
} UndoStep;
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index f6e7f1c2473..02aef4ef79e 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -226,6 +226,7 @@ set(SRC
intern/multires_versioning.c
intern/nla.c
intern/node.cc
+ intern/node_tree_update.cc
intern/type_conversions.cc
intern/object.cc
intern/object_deform.c
@@ -420,6 +421,7 @@ set(SRC
BKE_multires.h
BKE_nla.h
BKE_node.h
+ BKE_node_tree_update.h
BKE_object.h
BKE_object_deform.h
BKE_object_facemap.h
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index ddba726ba83..764c043f5ed 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -705,7 +705,12 @@ bool BKE_pose_channels_is_valid(const bPose *pose)
#endif
-bPoseChannel *BKE_pose_channel_active(Object *ob)
+bool BKE_pose_is_layer_visible(const bArmature *arm, const bPoseChannel *pchan)
+{
+ return (pchan->bone->layer & arm->layer);
+}
+
+bPoseChannel *BKE_pose_channel_active(Object *ob, const bool check_arm_layer)
{
bArmature *arm = (ob) ? ob->data : NULL;
bPoseChannel *pchan;
@@ -716,14 +721,21 @@ bPoseChannel *BKE_pose_channel_active(Object *ob)
/* find active */
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if ((pchan->bone) && (pchan->bone == arm->act_bone) && (pchan->bone->layer & arm->layer)) {
- return pchan;
+ if ((pchan->bone) && (pchan->bone == arm->act_bone)) {
+ if (!check_arm_layer || BKE_pose_is_layer_visible(arm, pchan)) {
+ return pchan;
+ }
}
}
return NULL;
}
+bPoseChannel *BKE_pose_channel_active_if_layer_visible(struct Object *ob)
+{
+ return BKE_pose_channel_active(ob, true);
+}
+
bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob)
{
bArmature *arm = (ob) ? ob->data : NULL;
@@ -732,7 +744,7 @@ bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob)
return NULL;
}
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
if (pchan && (pchan->bone->flag & BONE_SELECTED) && PBONE_VISIBLE(arm, pchan->bone)) {
return pchan;
}
diff --git a/source/blender/blenkernel/intern/asset_catalog.cc b/source/blender/blenkernel/intern/asset_catalog.cc
index aec622bb71f..eee1f6287c3 100644
--- a/source/blender/blenkernel/intern/asset_catalog.cc
+++ b/source/blender/blenkernel/intern/asset_catalog.cc
@@ -24,7 +24,7 @@
#include "BKE_asset_catalog.hh"
#include "BKE_asset_library.h"
-#include "BLI_fileops.h"
+#include "BLI_fileops.hh"
#include "BLI_path_util.h"
/* For S_ISREG() and S_ISDIR() on Windows. */
@@ -32,6 +32,10 @@
# include "BLI_winstuff.h"
#endif
+#include "CLG_log.h"
+
+static CLG_LogRef LOG = {"bke.asset_service"};
+
namespace blender::bke {
const CatalogFilePath AssetCatalogService::DEFAULT_CATALOG_FILENAME = "blender_assets.cats.txt";
@@ -311,6 +315,7 @@ void AssetCatalogService::load_from_disk(const CatalogFilePath &file_or_director
BLI_stat_t status;
if (BLI_stat(file_or_directory_path.data(), &status) == -1) {
/* TODO(@sybren): throw an appropriate exception. */
+ CLOG_WARN(&LOG, "path not found: %s", file_or_directory_path.data());
return;
}
@@ -337,6 +342,7 @@ void AssetCatalogService::load_directory_recursive(const CatalogFilePath &direct
if (!BLI_exists(file_path.data())) {
/* No file to be loaded is perfectly fine. */
+ CLOG_INFO(&LOG, 2, "path not found: %s", file_path.data());
return;
}
@@ -824,8 +830,12 @@ void AssetCatalogDefinitionFile::parse_catalog_file(
const CatalogFilePath &catalog_definition_file_path,
AssetCatalogParsedFn catalog_loaded_callback)
{
- std::fstream infile(catalog_definition_file_path);
+ fstream infile(catalog_definition_file_path, std::ios::in);
+ if (!infile.is_open()) {
+ CLOG_ERROR(&LOG, "%s: unable to open file", catalog_definition_file_path.c_str());
+ return;
+ }
bool seen_version_number = false;
std::string line;
while (std::getline(infile, line)) {
@@ -956,7 +966,7 @@ bool AssetCatalogDefinitionFile::write_to_disk_unsafe(const CatalogFilePath &des
return false;
}
- std::ofstream output(dest_file_path);
+ fstream output(dest_file_path, std::ios::out);
/* TODO(@sybren): remember the line ending style that was originally read, then use that to write
* the file again. */
diff --git a/source/blender/blenkernel/intern/asset_catalog_test.cc b/source/blender/blenkernel/intern/asset_catalog_test.cc
index ba8f8716823..3ff7831b19a 100644
--- a/source/blender/blenkernel/intern/asset_catalog_test.cc
+++ b/source/blender/blenkernel/intern/asset_catalog_test.cc
@@ -27,6 +27,8 @@
#include "DNA_asset_types.h"
#include "DNA_userdef_types.h"
+#include "CLG_log.h"
+
#include "testing/testing.h"
namespace blender::bke::tests {
@@ -93,6 +95,18 @@ class AssetCatalogTest : public testing::Test {
CatalogFilePath asset_library_root_;
CatalogFilePath temp_library_path_;
+ static void SetUpTestSuite()
+ {
+ testing::Test::SetUpTestSuite();
+ CLG_init();
+ }
+
+ static void TearDownTestSuite()
+ {
+ CLG_exit();
+ testing::Test::TearDownTestSuite();
+ }
+
void SetUp() override
{
const std::string test_files_dir = blender::tests::flags_test_asset_dir();
@@ -549,6 +563,30 @@ TEST_F(AssetCatalogTest, write_single_file)
/* TODO(@sybren): test ordering of catalogs in the file. */
}
+TEST_F(AssetCatalogTest, read_write_unicode_filepath)
+{
+ TestableAssetCatalogService service(asset_library_root_);
+ const CatalogFilePath load_from_path = asset_library_root_ + "/новый/" +
+ AssetCatalogService::DEFAULT_CATALOG_FILENAME;
+ service.load_from_disk(load_from_path);
+
+ const CatalogFilePath save_to_path = use_temp_path() + "новый.cats.txt";
+ AssetCatalogDefinitionFile *cdf = service.get_catalog_definition_file();
+ ASSERT_NE(nullptr, cdf) << "unable to load " << load_from_path;
+ EXPECT_TRUE(cdf->write_to_disk(save_to_path));
+
+ AssetCatalogService loaded_service(save_to_path);
+ loaded_service.load_from_disk();
+
+ /* Test that the file was loaded correctly. */
+ const bUUID materials_uuid("a2151dff-dead-4f29-b6bc-b2c7d6cccdb4");
+ const AssetCatalog *cat = loaded_service.find_catalog(materials_uuid);
+ ASSERT_NE(nullptr, cat);
+ EXPECT_EQ(materials_uuid, cat->catalog_id);
+ EXPECT_EQ(AssetCatalogPath("Материалы"), cat->path);
+ EXPECT_EQ("Russian Materials", cat->simple_name);
+}
+
TEST_F(AssetCatalogTest, no_writing_empty_files)
{
const CatalogFilePath temp_lib_root = create_temp_path();
diff --git a/source/blender/blenkernel/intern/blendfile_link_append.c b/source/blender/blenkernel/intern/blendfile_link_append.c
index c265a6e2b7d..23e9e6bfbbb 100644
--- a/source/blender/blenkernel/intern/blendfile_link_append.c
+++ b/source/blender/blenkernel/intern/blendfile_link_append.c
@@ -440,6 +440,16 @@ static bool object_in_any_collection(Main *bmain, Object *ob)
return false;
}
+static bool collection_instantiated_by_any_object(Main *bmain, Collection *collection)
+{
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ if (ob->type == OB_EMPTY && ob->instance_collection == collection) {
+ return true;
+ }
+ }
+ return false;
+}
+
static ID *loose_data_instantiate_process_check(LooseDataInstantiateContext *instantiate_context,
BlendfileLinkAppendContextItem *item)
{
@@ -633,12 +643,19 @@ static void loose_data_instantiate_collection_process(
* children.
*/
Collection *collection = (Collection *)id;
+ /* The collection could be linked/appended together with an Empty object instantiating it,
+ * better not instantiate the collection in the viewlayer in that case.
+ *
+ * Can easily happen when copy/pasting such instantiating empty, see T93839. */
+ const bool collection_is_instantiated = collection_instantiated_by_any_object(bmain,
+ collection);
/* Always consider adding collections directly selected by the user. */
- bool do_add_collection = (item->tag & LINK_APPEND_TAG_INDIRECT) == 0;
+ bool do_add_collection = (item->tag & LINK_APPEND_TAG_INDIRECT) == 0 &&
+ !collection_is_instantiated;
/* In linking case, do not enforce instantiating non-directly linked collections/objects.
* This avoids cluttering the ViewLayers, user can instantiate themselves specific collections
* or objects easily from the Outliner if needed. */
- if (!do_add_collection && do_append) {
+ if (!do_add_collection && do_append && !collection_is_instantiated) {
LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) {
Object *ob = coll_ob->ob;
if (!object_in_any_scene(bmain, ob)) {
@@ -726,6 +743,8 @@ static void loose_data_instantiate_object_process(LooseDataInstantiateContext *i
* if you want it do it at the editor level. */
const bool object_set_active = false;
+ const bool is_linking = (lapp_context->params->flag & FILE_LINK) != 0;
+
/* NOTE: For objects we only view_layer-instantiate duplicated objects that are not yet used
* anywhere. */
LinkNode *itemlink;
@@ -736,6 +755,17 @@ static void loose_data_instantiate_object_process(LooseDataInstantiateContext *i
continue;
}
+ /* In linking case, never instantiate stray objects that are not directly linked.
+ *
+ * While this is not ideal (in theory no object should remain un-owned), in case of indirectly
+ * linked objects, the other solution would be to add them to a local collection, which would
+ * make them directly linked. Think for now keeping them indirectly linked is more important.
+ * Ref. T93757.
+ */
+ if (is_linking && (item->tag & LINK_APPEND_TAG_INDIRECT) != 0) {
+ continue;
+ }
+
Object *ob = (Object *)id;
if (object_in_any_collection(bmain, ob)) {
diff --git a/source/blender/blenkernel/intern/curve.cc b/source/blender/blenkernel/intern/curve.cc
index 50b7c15774d..dc2527f9b62 100644
--- a/source/blender/blenkernel/intern/curve.cc
+++ b/source/blender/blenkernel/intern/curve.cc
@@ -43,7 +43,7 @@
#include "DNA_defaults.h"
#include "DNA_material_types.h"
-/* for dereferencing pointers */
+/* For dereferencing pointers. */
#include "DNA_key_types.h"
#include "DNA_object_types.h"
#include "DNA_vfont_types.h"
@@ -1438,7 +1438,7 @@ void BKE_nurb_makeFaces(const Nurb *nu, float *coord_array, int rowstride, int r
jstart = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces4");
jend = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces5");
- /* precalculation of basisv and jstart, jend */
+ /* Pre-calculation of `basisv` and `jstart`, `jend`. */
if (nu->flagv & CU_NURB_CYCLIC) {
cycl = nu->orderv - 1;
}
@@ -2104,10 +2104,10 @@ static void tilt_bezpart(const BezTriple *prevbezt,
}
}
-/* make_bevel_list_3D_* funcs, at a minimum these must
- * fill in the bezp->quat and bezp->dir values */
+/* `make_bevel_list_3D_*` functions, at a minimum these must
+ * fill in the #BevPoint.quat and #BevPoint.dir values. */
-/* utility for make_bevel_list_3D_* funcs */
+/** Utility for `make_bevel_list_3D_*` functions. */
static void bevel_list_calc_bisect(BevList *bl)
{
BevPoint *bevp2, *bevp1, *bevp0;
@@ -2329,14 +2329,14 @@ static void make_bevel_list_3D_minimum_twist(BevList *bl)
/* Need to correct for the start/end points not matching
* do this by calculating the tilt angle difference, then apply
- * the rotation gradually over the entire curve
+ * the rotation gradually over the entire curve.
*
- * note that the split is between last and second last, rather than first/last as youd expect.
+ * Note that the split is between last and second last, rather than first/last as you'd expect.
*
* real order is like this
* 0,1,2,3,4 --> 1,2,3,4,0
*
- * this is why we compare last with second last
+ * This is why we compare last with second last.
*/
float vec_1[3] = {0, 1, 0}, vec_2[3] = {0, 1, 0}, angle, ang_fac, cross_tmp[3];
@@ -2614,14 +2614,13 @@ void BKE_curve_bevelList_free(ListBase *bev)
void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_render)
{
- /*
- * - convert all curves to polys, with indication of resol and flags for double-vertices
- * - possibly; do a smart vertice removal (in case Nurb)
- * - separate in individual blocks with BoundBox
- * - AutoHole detection
+ /* - Convert all curves to polys, with indication of resolution and flags for double-vertices.
+ * - Possibly; do a smart vertex removal (in case #Nurb).
+ * - Separate in individual blocks with #BoundBox.
+ * - Auto-hole detection.
*/
- /* this function needs an object, because of tflag and upflag */
+ /* This function needs an object, because of `tflag` and `upflag`. */
Curve *cu = (Curve *)ob->data;
BezTriple *bezt, *prevbezt;
BPoint *bp;
@@ -2637,7 +2636,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
bool is_editmode = false;
ListBase *bev;
- /* segbevcount alsp requires seglen. */
+ /* segbevcount also requires seglen. */
const bool need_seglen = ELEM(
cu->bevfac1_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE) ||
ELEM(cu->bevfac2_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE);
@@ -2805,10 +2804,10 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
}
}
else {
- /* always do all three, to prevent data hanging around */
+ /* Always do all three, to prevent data hanging around. */
int j;
- /* BevPoint must stay aligned to 4 so sizeof(BevPoint)/sizeof(float) works */
+ /* #BevPoint must stay aligned to 4 so `sizeof(BevPoint) / sizeof(float)` works. */
for (j = 0; j < 3; j++) {
BKE_curve_forward_diff_bezier(prevbezt->vec[1][j],
prevbezt->vec[2][j],
@@ -2819,7 +2818,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
sizeof(BevPoint));
}
- /* if both arrays are nullptr do nothiong */
+ /* If both arrays are `nullptr` do nothing. */
tilt_bezpart(prevbezt,
bezt,
nu,
@@ -2839,7 +2838,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
sizeof(BevPoint));
}
- /* seglen */
+ /* `seglen`. */
if (seglen != nullptr) {
*seglen = 0;
*segbevcount = 0;
@@ -2847,7 +2846,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
bevp0 = bevp;
bevp++;
bevp->offset = len_v3v3(bevp0->vec, bevp->vec);
- /* match seglen and segbevcount to the cleaned up bevel lists (see STEP 2) */
+ /* Match `seglen` and `segbevcount` to the cleaned up bevel lists (see STEP 2). */
if (bevp->offset > threshold) {
*seglen += bevp->offset;
*segbevcount += 1;
@@ -2980,7 +2979,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
continue;
}
- nr = bl->nr - bl->dupe_nr + 1; /* +1 because vectorbezier sets flag too */
+ nr = bl->nr - bl->dupe_nr + 1; /* +1 because vector-bezier sets flag too. */
blnew = (BevList *)MEM_mallocN(sizeof(BevList), "makeBevelList4");
memcpy(blnew, bl, sizeof(BevList));
blnew->bevpoints = (BevPoint *)MEM_calloc_arrayN(nr, sizeof(BevPoint), "makeBevelPoints4");
@@ -2992,7 +2991,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
blnew->seglen = bl->seglen;
blnew->nr = 0;
BLI_remlink(bev, bl);
- BLI_insertlinkbefore(bev, bl->next, blnew); /* to make sure bevlist is tuned with nurblist */
+ BLI_insertlinkbefore(bev, bl->next, blnew); /* Ensure `bevlist` is tuned with `nurblist`. */
bevp0 = bl->bevpoints;
bevp1 = blnew->bevpoints;
nr = bl->nr;
@@ -3114,7 +3113,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
BevPoint *bevp = bl->bevpoints;
unit_qt(bevp->quat);
}
- else if (bl->nr == 2) { /* 2 pnt, treat separate */
+ else if (bl->nr == 2) { /* 2 points, treat separately. */
make_bevel_list_segment_2D(bl);
}
else {
@@ -3129,7 +3128,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
BevPoint *bevp = bl->bevpoints;
unit_qt(bevp->quat);
}
- else if (bl->nr == 2) { /* 2 pnt, treat separate */
+ else if (bl->nr == 2) { /* 2 points, treat separately. */
make_bevel_list_segment_3D(bl);
}
else {
@@ -3321,13 +3320,13 @@ static void calchandleNurb_intern(BezTriple *bezt,
}
if (skip_align ||
- /* when one handle is free, alignming makes no sense, see: T35952 */
+ /* When one handle is free, aligning makes no sense, see: T35952 */
ELEM(HD_FREE, bezt->h1, bezt->h2) ||
- /* also when no handles are aligned, skip this step */
+ /* Also when no handles are aligned, skip this step. */
(!ELEM(HD_ALIGN, bezt->h1, bezt->h2) && !ELEM(HD_ALIGN_DOUBLESIDE, bezt->h1, bezt->h2))) {
- /* handles need to be updated during animation and applying stuff like hooks,
+ /* Handles need to be updated during animation and applying stuff like hooks,
* but in such situations it's quite difficult to distinguish in which order
- * align handles should be aligned so skip them for now */
+ * align handles should be aligned so skip them for now. */
return;
}
@@ -3996,8 +3995,8 @@ void BKE_nurb_handle_smooth_fcurve(BezTriple *bezt, int total, bool cyclic)
}
}
- /* Find continuous subsequences of free auto handles and smooth them, starting at
- * search_base. In cyclic mode these subsequences can span the cycle boundary. */
+ /* Find continuous sub-sequences of free auto handles and smooth them, starting at search_base.
+ * In cyclic mode these sub-sequences can span the cycle boundary. */
int start = search_base, count = 1;
for (int i = 1, j = start + 1; i < total; i++, j++) {
@@ -4189,13 +4188,13 @@ void BKE_nurb_handles_autocalc(Nurb *nu, uint8_t flag)
/* left handle: */
if (flag == 0 || (bezt1->f1 & flag)) {
bezt1->h1 = HD_FREE;
- /* distance too short: vectorhandle */
+ /* Distance too short: vector-handle. */
if (len_squared_v3v3(bezt1->vec[1], bezt0->vec[1]) < eps_sq) {
bezt1->h1 = HD_VECT;
leftsmall = true;
}
else {
- /* aligned handle? */
+ /* Aligned handle? */
if (dist_squared_to_line_v3(bezt1->vec[1], bezt1->vec[0], bezt1->vec[2]) < eps_sq) {
align = true;
bezt1->h1 = HD_ALIGN;
@@ -4209,13 +4208,13 @@ void BKE_nurb_handles_autocalc(Nurb *nu, uint8_t flag)
/* right handle: */
if (flag == 0 || (bezt1->f3 & flag)) {
bezt1->h2 = HD_FREE;
- /* distance too short: vectorhandle */
+ /* Distance too short: vector-handle. */
if (len_squared_v3v3(bezt1->vec[1], bezt2->vec[1]) < eps_sq) {
bezt1->h2 = HD_VECT;
rightsmall = true;
}
else {
- /* aligned handle? */
+ /* Aligned handle? */
if (align) {
bezt1->h2 = HD_ALIGN;
}
@@ -4860,7 +4859,7 @@ bool BKE_nurb_type_convert(Nurb *nu,
int a, c, nr;
if (nu->type == CU_POLY) {
- if (type == CU_BEZIER) { /* To Bezier with vecthandles. */
+ if (type == CU_BEZIER) { /* To Bezier with vector-handles. */
nr = nu->pntsu;
bezt = (BezTriple *)MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2");
nu->bezt = bezt;
diff --git a/source/blender/blenkernel/intern/curveprofile.cc b/source/blender/blenkernel/intern/curveprofile.cc
index 387709fca29..8f387be41d3 100644
--- a/source/blender/blenkernel/intern/curveprofile.cc
+++ b/source/blender/blenkernel/intern/curveprofile.cc
@@ -46,7 +46,7 @@
struct CurveProfile *BKE_curveprofile_add(eCurveProfilePresets preset)
{
- CurveProfile *profile = (CurveProfile *)MEM_callocN(sizeof(CurveProfile), __func__);
+ CurveProfile *profile = MEM_cnew<CurveProfile>(__func__);
BKE_curveprofile_set_defaults(profile);
profile->preset = preset;
diff --git a/source/blender/blenkernel/intern/fcurve_driver.c b/source/blender/blenkernel/intern/fcurve_driver.c
index 5496519e53b..ce30f80ba65 100644
--- a/source/blender/blenkernel/intern/fcurve_driver.c
+++ b/source/blender/blenkernel/intern/fcurve_driver.c
@@ -29,6 +29,7 @@
#include "BLI_alloca.h"
#include "BLI_expr_pylike_eval.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string_utils.h"
#include "BLI_threads.h"
@@ -864,6 +865,12 @@ void driver_variable_name_validate(DriverVar *dvar)
}
}
+void driver_variable_unique_name(DriverVar *dvar)
+{
+ ListBase variables = BLI_listbase_from_link((Link *)dvar);
+ BLI_uniquename(&variables, dvar, dvar->name, '_', offsetof(DriverVar, name), sizeof(dvar->name));
+}
+
DriverVar *driver_add_new_variable(ChannelDriver *driver)
{
DriverVar *dvar;
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index f43cf00a310..edd5073da79 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -84,6 +84,7 @@
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_packedFile.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -3699,16 +3700,8 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
BLI_mutex_unlock(ima->runtime.cache_mutex);
- /* don't use notifiers because they are not 100% sure to succeeded
- * this also makes sure all scenes are accounted for. */
- {
- Scene *scene;
- for (scene = bmain->scenes.first; scene; scene = scene->id.next) {
- if (scene->nodetree) {
- nodeUpdateID(scene->nodetree, &ima->id);
- }
- }
- }
+ BKE_ntree_update_tag_id_changed(bmain, &ima->id);
+ BKE_ntree_update_main(bmain, NULL);
}
/* return renderpass for a given pass index and active view */
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index 83ed0ee4c08..6e1bac71d3f 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -470,8 +470,9 @@ static void lib_override_group_tag_data_object_to_collection_init_collection_pro
}
LinkNodePair **collections_linkedlist_p;
- if (!BLI_ghash_ensure_p(
- data->linked_object_to_instantiating_collections, ob, &collections_linkedlist_p)) {
+ if (!BLI_ghash_ensure_p(data->linked_object_to_instantiating_collections,
+ ob,
+ (void ***)&collections_linkedlist_p)) {
*collections_linkedlist_p = BLI_memarena_calloc(data->mem_arena,
sizeof(**collections_linkedlist_p));
}
diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c
index 3cea0de32ee..9ea85714b4a 100644
--- a/source/blender/blenkernel/intern/lib_remap.c
+++ b/source/blender/blenkernel/intern/lib_remap.c
@@ -346,7 +346,7 @@ static void libblock_remap_data_postprocess_obdata_relink(Main *bmain, Object *o
static void libblock_remap_data_postprocess_nodetree_update(Main *bmain, ID *new_id)
{
/* Update all group nodes using a node group. */
- ntreeUpdateAllUsers(bmain, new_id, 0);
+ ntreeUpdateAllUsers(bmain, new_id);
}
/**
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index ac0dbcb715d..95f41ab4b39 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -50,6 +50,7 @@
#include "BKE_linestyle.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_texture.h"
#include "BLO_read_write.h"
@@ -2085,5 +2086,5 @@ void BKE_linestyle_default_shader(const bContext *C, FreestyleLineStyle *linesty
tosock = BLI_findlink(&output_linestyle->inputs, 0); /* Color */
nodeAddLink(ntree, input_texure, fromsock, output_linestyle, tosock);
- ntreeUpdateTree(CTX_data_main(C), ntree);
+ BKE_ntree_update_main_tree(CTX_data_main(C), ntree, NULL);
}
diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc
index e8054884f26..07c126861f0 100644
--- a/source/blender/blenkernel/intern/mesh_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_convert.cc
@@ -917,7 +917,7 @@ static void curve_to_mesh_eval_ensure(Object &object)
* will have no modifiers. */
Object bevel_object = {{nullptr}};
if (curve.bevobj != nullptr) {
- bevel_object = *curve.bevobj;
+ memcpy(&bevel_object, curve.bevobj, sizeof(bevel_object));
BLI_listbase_clear(&bevel_object.modifiers);
BKE_object_runtime_reset(&bevel_object);
curve.bevobj = &bevel_object;
@@ -926,7 +926,7 @@ static void curve_to_mesh_eval_ensure(Object &object)
/* Same thing for taper. */
Object taper_object = {{nullptr}};
if (curve.taperobj != nullptr) {
- taper_object = *curve.taperobj;
+ memcpy(&taper_object, curve.taperobj, sizeof(taper_object));
BLI_listbase_clear(&taper_object.modifiers);
BKE_object_runtime_reset(&taper_object);
curve.taperobj = &taper_object;
@@ -1065,7 +1065,8 @@ static Mesh *mesh_new_from_mesh_object_with_layers(Depsgraph *depsgraph,
return nullptr;
}
- Object object_for_eval = *object;
+ Object object_for_eval;
+ memcpy(&object_for_eval, object, sizeof(object_for_eval));
if (object_for_eval.runtime.data_orig != nullptr) {
object_for_eval.data = object_for_eval.runtime.data_orig;
}
@@ -1440,7 +1441,8 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
/* mesh_src might depend on mesh_dst, so we need to do everything with a local copy */
/* TODO(Sybren): the above claim came from 2.7x derived-mesh code (DM_to_mesh);
* check whether it is still true with Mesh */
- Mesh tmp = *mesh_dst;
+ Mesh tmp;
+ memcpy(&tmp, mesh_dst, sizeof(tmp));
int totvert, totedge /*, totface */ /* UNUSED */, totloop, totpoly;
bool did_shapekeys = false;
eCDAllocType alloctype = CD_DUPLICATE;
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index fc2e7d0a6a3..b0c93a5614d 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -70,6 +70,7 @@
#include "BKE_main.h"
#include "BKE_movieclip.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_tracking.h"
#include "IMB_imbuf.h"
@@ -1695,17 +1696,7 @@ void BKE_movieclip_reload(Main *bmain, MovieClip *clip)
movieclip_calc_length(clip);
- /* same as for image update -- don't use notifiers because they are not 100% sure to succeeded
- * (node trees which are not currently visible wouldn't be refreshed)
- */
- {
- Scene *scene;
- for (scene = bmain->scenes.first; scene; scene = scene->id.next) {
- if (scene->nodetree) {
- nodeUpdateID(scene->nodetree, &clip->id);
- }
- }
- }
+ BKE_ntree_update_tag_id_changed(bmain, &clip->id);
}
void BKE_movieclip_update_scopes(MovieClip *clip, MovieClipUser *user, MovieClipScopes *scopes)
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index be458ed036e..7121ef20207 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -74,6 +74,7 @@
#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -261,8 +262,7 @@ static void ntree_free_data(ID *id)
/* XXX hack! node trees should not store execution graphs at all.
* This should be removed when old tree types no longer require it.
* Currently the execution data for texture nodes remains in the tree
- * after execution, until the node tree is updated or freed.
- */
+ * after execution, until the node tree is updated or freed. */
if (ntree->execdata) {
switch (ntree->type) {
case NTREE_SHADER:
@@ -278,10 +278,10 @@ static void ntree_free_data(ID *id)
/* XXX not nice, but needed to free localized node groups properly */
free_localized_node_groups(ntree);
- /* unregister associated RNA types */
+ /* Unregister associated RNA types. */
ntreeInterfaceTypeFree(ntree);
- BLI_freelistN(&ntree->links); /* do first, then unlink_node goes fast */
+ BLI_freelistN(&ntree->links);
LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree->nodes) {
node_free_node(ntree, node);
@@ -522,7 +522,6 @@ static void write_node_socket_default_value(BlendWriter *writer, bNodeSocket *so
static void write_node_socket(BlendWriter *writer, bNodeSocket *sock)
{
- /* actual socket writing */
BLO_write_struct(writer, bNodeSocket, sock);
if (sock->prop) {
@@ -533,7 +532,6 @@ static void write_node_socket(BlendWriter *writer, bNodeSocket *sock)
}
static void write_node_socket_interface(BlendWriter *writer, bNodeSocket *sock)
{
- /* actual socket writing */
BLO_write_struct(writer, bNodeSocket, sock);
if (sock->prop) {
@@ -547,8 +545,6 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
{
BKE_id_blend_write(writer, &ntree->id);
- /* for link_list() speed, we write per list */
-
if (ntree->adt) {
BKE_animdata_blend_write(writer, ntree->adt);
}
@@ -572,7 +568,6 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
}
if (node->storage) {
- /* could be handlerized at some point, now only 1 exception still */
if (ELEM(ntree->type, NTREE_SHADER, NTREE_GEOMETRY) &&
ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB, SH_NODE_CURVE_FLOAT)) {
BKE_curvemapping_blend_write(writer, (const CurveMapping *)node->storage);
@@ -646,13 +641,13 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
}
if (node->type == CMP_NODE_OUTPUT_FILE) {
- /* inputs have own storage data */
+ /* Inputs have their own storage data. */
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
BLO_write_struct(writer, NodeImageMultiFileSocket, sock->storage);
}
}
if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_R_LAYERS)) {
- /* write extra socket info */
+ /* Write extra socket info. */
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
BLO_write_struct(writer, NodeImageLayer, sock->storage);
}
@@ -716,6 +711,7 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
ntree->execdata = nullptr;
ntree->field_inferencing_interface = nullptr;
+ BKE_ntree_update_tag_missing_runtime_data(ntree);
BLO_read_data_address(reader, &ntree->adt);
BKE_animdata_blend_read_data(reader, ntree->adt);
@@ -748,7 +744,6 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
}
if (node->storage) {
- /* could be handlerized at some point */
switch (node->type) {
case SH_NODE_CURVE_VEC:
case SH_NODE_CURVE_RGB:
@@ -859,11 +854,6 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
/* TODO: should be dealt by new generic cache handling of IDs... */
ntree->previews = nullptr;
- if (ntree->type == NTREE_GEOMETRY) {
- /* Update field referencing for the geometry nodes modifier. */
- ntree->update |= NTREE_UPDATE_FIELD_INFERENCING;
- }
-
BLO_read_data_address(reader, &ntree->preview);
BKE_previewimg_blend_read(reader, ntree->preview);
@@ -1096,21 +1086,18 @@ static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType
return;
}
bNodeSocketTemplate *sockdef;
- /* bNodeSocket *sock; */ /* UNUSED */
if (ntype->inputs) {
sockdef = ntype->inputs;
while (sockdef->type != -1) {
- /* sock = */ node_add_socket_from_template(ntree, node, sockdef, SOCK_IN);
-
+ node_add_socket_from_template(ntree, node, sockdef, SOCK_IN);
sockdef++;
}
}
if (ntype->outputs) {
sockdef = ntype->outputs;
while (sockdef->type != -1) {
- /* sock = */ node_add_socket_from_template(ntree, node, sockdef, SOCK_OUT);
-
+ node_add_socket_from_template(ntree, node, sockdef, SOCK_OUT);
sockdef++;
}
}
@@ -1168,8 +1155,7 @@ static void node_init(const struct bContext *C, bNodeTree *ntree, bNode *node)
RNA_pointer_create((ID *)ntree, &RNA_Node, node, &ptr);
/* XXX Warning: context can be nullptr in case nodes are added in do_versions.
- * Delayed init is not supported for nodes with context-based `initfunc_api` at the moment.
- */
+ * Delayed init is not supported for nodes with context-based `initfunc_api` at the moment. */
BLI_assert(C != nullptr);
ntype->initfunc_api(C, &ptr);
}
@@ -1190,6 +1176,7 @@ static void ntree_set_typeinfo(bNodeTree *ntree, bNodeTreeType *typeinfo)
/* Deprecated integer type. */
ntree->type = ntree->typeinfo->type;
+ BKE_ntree_update_tag_all(ntree);
}
static void node_set_typeinfo(const struct bContext *C,
@@ -1240,6 +1227,7 @@ static void node_socket_set_typeinfo(bNodeTree *ntree,
ntree->init &= ~NTREE_TYPE_INIT;
}
+ BKE_ntree_update_tag_socket_type(ntree, sock);
}
/* Set specific typeinfo pointers in all node trees on register/unregister */
@@ -1383,18 +1371,6 @@ bNodeType *nodeTypeFind(const char *idname)
return nullptr;
}
-static void free_dynamic_typeinfo(bNodeType *ntype)
-{
- if (ntype->type == NODE_DYNAMIC) {
- if (ntype->inputs) {
- MEM_freeN(ntype->inputs);
- }
- if (ntype->outputs) {
- MEM_freeN(ntype->outputs);
- }
- }
-}
-
/* callback for hash value free function */
static void node_free_type(void *nodetype_v)
{
@@ -1404,11 +1380,6 @@ static void node_free_type(void *nodetype_v)
* or we'd want to update *all* active Mains, which we cannot do anyway currently. */
update_typeinfo(G_MAIN, nullptr, nullptr, nodetype, nullptr, true);
- /* XXX deprecated */
- if (nodetype->type == NODE_DYNAMIC) {
- free_dynamic_typeinfo(nodetype);
- }
-
delete nodetype->fixed_declaration;
nodetype->fixed_declaration = nullptr;
@@ -1580,7 +1551,7 @@ static bNodeSocket *make_socket(bNodeTree *ntree,
/* if no explicit identifier is given, assign a unique identifier based on the name */
BLI_strncpy(auto_identifier, name, sizeof(auto_identifier));
}
- /* make the identifier unique */
+ /* Make the identifier unique. */
BLI_uniquename_cb(
unique_identifier_check, lb, "socket", '_', auto_identifier, sizeof(auto_identifier));
@@ -1749,7 +1720,7 @@ bNodeSocket *nodeAddSocket(bNodeTree *ntree,
BLI_remlink(lb, sock); /* does nothing for new socket */
BLI_addtail(lb, sock);
- node->update |= NODE_UPDATE;
+ BKE_ntree_update_tag_socket_new(ntree, sock);
return sock;
}
@@ -1768,8 +1739,6 @@ bNodeSocket *nodeInsertSocket(bNodeTree *ntree,
BLI_remlink(lb, sock); /* does nothing for new socket */
BLI_insertlinkbefore(lb, next_sock, sock);
- node->update |= NODE_UPDATE;
-
return sock;
}
@@ -2010,10 +1979,7 @@ bNodeSocket *nodeInsertStaticSocket(bNodeTree *ntree,
return sock;
}
-static void node_socket_free(bNodeTree *UNUSED(ntree),
- bNodeSocket *sock,
- bNode *UNUSED(node),
- const bool do_id_user)
+static void node_socket_free(bNodeSocket *sock, const bool do_id_user)
{
if (sock->prop) {
IDP_FreePropertyContent_ex(sock->prop, do_id_user);
@@ -2048,10 +2014,10 @@ void nodeRemoveSocketEx(struct bNodeTree *ntree,
BLI_remlink(&node->inputs, sock);
BLI_remlink(&node->outputs, sock);
- node_socket_free(ntree, sock, node, do_id_user);
+ node_socket_free(sock, do_id_user);
MEM_freeN(sock);
- node->update |= NODE_UPDATE;
+ BKE_ntree_update_tag_socket_removed(ntree);
}
void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node)
@@ -2063,18 +2029,18 @@ void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node)
}
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->inputs) {
- node_socket_free(ntree, sock, node, true);
+ node_socket_free(sock, true);
MEM_freeN(sock);
}
BLI_listbase_clear(&node->inputs);
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->outputs) {
- node_socket_free(ntree, sock, node, true);
+ node_socket_free(sock, true);
MEM_freeN(sock);
}
BLI_listbase_clear(&node->outputs);
- node->update |= NODE_UPDATE;
+ BKE_ntree_update_tag_socket_removed(ntree);
}
bNode *nodeFindNodebyName(bNodeTree *ntree, const char *name)
@@ -2226,7 +2192,7 @@ bNode *nodeAddNode(const struct bContext *C, bNodeTree *ntree, const char *idnam
BLI_strncpy(node->idname, idname, sizeof(node->idname));
node_set_typeinfo(C, ntree, node, nodeTypeFind(idname));
- ntree->update |= NTREE_UPDATE_NODES;
+ BKE_ntree_update_tag_node_new(ntree, node);
return node;
}
@@ -2236,9 +2202,8 @@ bNode *nodeAddStaticNode(const struct bContext *C, bNodeTree *ntree, int type)
const char *idname = nullptr;
NODE_TYPES_BEGIN (ntype) {
- /* do an extra poll here, because some int types are used
- * for multiple node types, this helps find the desired type
- */
+ /* Do an extra poll here, because some int types are used
+ * for multiple node types, this helps find the desired type. */
const char *disabled_hint;
if (ntype->type == type && (!ntype->poll || ntype->poll(ntype, ntree, &disabled_hint))) {
idname = ntype->idname;
@@ -2268,9 +2233,8 @@ static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src,
}
sock_dst->stack_index = 0;
- /* XXX some compositor node (e.g. image, render layers) still store
- * some persistent buffer data here, need to clear this to avoid dangling pointers.
- */
+ /* XXX some compositor nodes (e.g. image, render layers) still store
+ * some persistent buffer data here, need to clear this to avoid dangling pointers. */
sock_dst->cache = nullptr;
}
@@ -2285,7 +2249,7 @@ bNode *BKE_node_copy_ex(bNodeTree *ntree,
*node_dst = *node_src;
- /* can be called for nodes outside a node tree (e.g. clipboard) */
+ /* Can be called for nodes outside a node tree (e.g. clipboard). */
if (ntree) {
if (unique_name) {
nodeUniqueName(ntree, node_dst);
@@ -2352,7 +2316,7 @@ bNode *BKE_node_copy_ex(bNodeTree *ntree,
}
if (ntree) {
- ntree->update |= NTREE_UPDATE_NODES;
+ BKE_ntree_update_tag_node_new(ntree, node_dst);
}
/* Reset the declaration of the new node. */
@@ -2422,7 +2386,7 @@ bNodeLink *nodeAddLink(
{
bNodeLink *link = nullptr;
- /* test valid input */
+ /* Test valid input. */
BLI_assert(fromnode);
BLI_assert(tonode);
@@ -2449,7 +2413,7 @@ bNodeLink *nodeAddLink(
}
if (ntree) {
- ntree->update |= NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_link_added(ntree, link);
}
if (link != nullptr && link->tosock->flag & SOCK_MULTI_INPUT) {
@@ -2461,7 +2425,7 @@ bNodeLink *nodeAddLink(
void nodeRemLink(bNodeTree *ntree, bNodeLink *link)
{
- /* can be called for links outside a node tree (e.g. clipboard) */
+ /* Can be called for links outside a node tree (e.g. clipboard). */
if (ntree) {
BLI_remlink(&ntree->links, link);
}
@@ -2472,7 +2436,7 @@ void nodeRemLink(bNodeTree *ntree, bNodeLink *link)
MEM_freeN(link);
if (ntree) {
- ntree->update |= NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_link_removed(ntree);
}
}
@@ -2572,7 +2536,7 @@ void nodeMuteLinkToggle(bNodeTree *ntree, bNodeLink *link)
}
if (ntree) {
- ntree->update |= NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_link_mute(ntree, link);
}
}
@@ -2583,8 +2547,6 @@ void nodeRemSocketLinks(bNodeTree *ntree, bNodeSocket *sock)
nodeRemLink(ntree, link);
}
}
-
- ntree->update |= NTREE_UPDATE_LINKS;
}
bool nodeLinkIsHidden(const bNodeLink *link)
@@ -2649,7 +2611,7 @@ void nodeInternalRelink(bNodeTree *ntree, bNode *node)
link->flag |= NODE_LINK_MUTED;
}
- ntree->update |= NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_link_changed(ntree);
}
else {
if (link->tosock->flag & SOCK_MULTI_INPUT) {
@@ -2843,8 +2805,11 @@ bool BKE_node_preview_used(const bNode *node)
return (node->typeinfo->flag & NODE_PREVIEW) != 0;
}
-bNodePreview *BKE_node_preview_verify(
- bNodeInstanceHash *previews, bNodeInstanceKey key, int xsize, int ysize, bool create)
+bNodePreview *BKE_node_preview_verify(bNodeInstanceHash *previews,
+ bNodeInstanceKey key,
+ const int xsize,
+ const int ysize,
+ const bool create)
{
bNodePreview *preview = (bNodePreview *)BKE_node_instance_hash_lookup(previews, key);
if (!preview) {
@@ -2901,9 +2866,8 @@ void BKE_node_preview_free(bNodePreview *preview)
static void node_preview_init_tree_recursive(bNodeInstanceHash *previews,
bNodeTree *ntree,
bNodeInstanceKey parent_key,
- int xsize,
- int ysize,
- bool create_previews)
+ const int xsize,
+ const int ysize)
{
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node);
@@ -2912,17 +2876,16 @@ static void node_preview_init_tree_recursive(bNodeInstanceHash *previews,
node->preview_xsize = xsize;
node->preview_ysize = ysize;
- BKE_node_preview_verify(previews, key, xsize, ysize, create_previews);
+ BKE_node_preview_verify(previews, key, xsize, ysize, false);
}
if (node->type == NODE_GROUP && node->id) {
- node_preview_init_tree_recursive(
- previews, (bNodeTree *)node->id, key, xsize, ysize, create_previews);
+ node_preview_init_tree_recursive(previews, (bNodeTree *)node->id, key, xsize, ysize);
}
}
}
-void BKE_node_preview_init_tree(bNodeTree *ntree, int xsize, int ysize, bool create_previews)
+void BKE_node_preview_init_tree(bNodeTree *ntree, int xsize, int ysize)
{
if (!ntree) {
return;
@@ -2932,8 +2895,7 @@ void BKE_node_preview_init_tree(bNodeTree *ntree, int xsize, int ysize, bool cre
ntree->previews = BKE_node_instance_hash_new("node previews");
}
- node_preview_init_tree_recursive(
- ntree->previews, ntree, NODE_INSTANCE_KEY_BASE, xsize, ysize, create_previews);
+ node_preview_init_tree_recursive(ntree->previews, ntree, NODE_INSTANCE_KEY_BASE, xsize, ysize);
}
static void node_preview_tag_used_recursive(bNodeInstanceHash *previews,
@@ -3069,27 +3031,6 @@ void BKE_node_preview_merge_tree(bNodeTree *to_ntree, bNodeTree *from_ntree, boo
}
}
-void BKE_node_preview_set_pixel(
- bNodePreview *preview, const float col[4], int x, int y, bool do_manage)
-{
- if (preview) {
- if (x >= 0 && y >= 0) {
- if (x < preview->xsize && y < preview->ysize) {
- unsigned char *tar = preview->rect + 4 * ((preview->xsize * y) + x);
-
- if (do_manage) {
- linearrgb_to_srgb_uchar4(tar, col);
- }
- else {
- rgba_float_to_uchar(tar, col);
- }
- }
- // else printf("prv out bound x y %d %d\n", x, y);
- }
- // else printf("prv out bound x y %d %d\n", x, y);
- }
-}
-
/* ************** Free stuff ********** */
void nodeUnlinkNode(bNodeTree *ntree, bNode *node)
@@ -3098,9 +3039,6 @@ void nodeUnlinkNode(bNodeTree *ntree, bNode *node)
ListBase *lb;
if (link->fromnode == node) {
lb = &node->outputs;
- if (link->tonode) {
- link->tonode->update |= NODE_UPDATE;
- }
}
else if (link->tonode == node) {
lb = &node->inputs;
@@ -3142,10 +3080,6 @@ static void node_free_node(bNodeTree *ntree, bNode *node)
/* can be called for nodes outside a node tree (e.g. clipboard) */
if (ntree) {
- /* remove all references to this node */
- nodeUnlinkNode(ntree, node);
- node_unlink_attached(ntree, node);
-
BLI_remlink(&ntree->nodes, node);
if (ntree->typeinfo->free_node_cache) {
@@ -3165,12 +3099,12 @@ static void node_free_node(bNodeTree *ntree, bNode *node)
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->inputs) {
/* Remember, no ID user refcount management here! */
- node_socket_free(ntree, sock, node, false);
+ node_socket_free(sock, false);
MEM_freeN(sock);
}
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->outputs) {
/* Remember, no ID user refcount management here! */
- node_socket_free(ntree, sock, node, false);
+ node_socket_free(sock, false);
MEM_freeN(sock);
}
@@ -3189,7 +3123,7 @@ static void node_free_node(bNodeTree *ntree, bNode *node)
MEM_freeN(node);
if (ntree) {
- ntree->update |= NTREE_UPDATE_NODES;
+ BKE_ntree_update_tag_node_removed(ntree);
}
}
@@ -3197,6 +3131,12 @@ void ntreeFreeLocalNode(bNodeTree *ntree, bNode *node)
{
/* For removing nodes while editing localized node trees. */
BLI_assert((ntree->id.tag & LIB_TAG_LOCALIZED) != 0);
+
+ /* These two lines assume the caller might want to free a single node and maintain
+ * a valid state in the node tree. */
+ nodeUnlinkNode(ntree, node);
+ node_unlink_attached(ntree, node);
+
node_free_node(ntree, node);
}
@@ -3241,6 +3181,9 @@ void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user)
}
}
+ nodeUnlinkNode(ntree, node);
+ node_unlink_attached(ntree, node);
+
/* Free node itself. */
node_free_node(ntree, node);
}
@@ -3266,8 +3209,7 @@ static void free_localized_node_groups(bNodeTree *ntree)
/* Only localized node trees store a copy for each node group tree.
* Each node group tree in a localized node tree can be freed,
* since it is a localized copy itself (no risk of accessing free'd
- * data in main, see T37939).
- */
+ * data in main, see T37939). */
if (!(ntree->id.tag & LIB_TAG_LOCALIZED)) {
return;
}
@@ -3463,7 +3405,7 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree)
}
}
- /* ensures only a single output node is enabled */
+ /* Ensures only a single output node is enabled. */
ntreeSetOutput(ntree);
bNode *node_src = (bNode *)ntree->nodes.first;
@@ -3560,12 +3502,11 @@ bNodeSocket *ntreeAddSocketInterface(bNodeTree *ntree,
bNodeSocket *iosock = make_socket_interface(ntree, in_out, idname, name);
if (in_out == SOCK_IN) {
BLI_addtail(&ntree->inputs, iosock);
- ntree->update |= NTREE_UPDATE_GROUP_IN;
}
else if (in_out == SOCK_OUT) {
BLI_addtail(&ntree->outputs, iosock);
- ntree->update |= NTREE_UPDATE_GROUP_OUT;
}
+ BKE_ntree_update_tag_interface(ntree);
return iosock;
}
@@ -3578,12 +3519,11 @@ bNodeSocket *ntreeInsertSocketInterface(bNodeTree *ntree,
bNodeSocket *iosock = make_socket_interface(ntree, in_out, idname, name);
if (in_out == SOCK_IN) {
BLI_insertlinkbefore(&ntree->inputs, next_sock, iosock);
- ntree->update |= NTREE_UPDATE_GROUP_IN;
}
else if (in_out == SOCK_OUT) {
BLI_insertlinkbefore(&ntree->outputs, next_sock, iosock);
- ntree->update |= NTREE_UPDATE_GROUP_OUT;
}
+ BKE_ntree_update_tag_interface(ntree);
return iosock;
}
@@ -3629,7 +3569,7 @@ void ntreeRemoveSocketInterface(bNodeTree *ntree, bNodeSocket *sock)
node_socket_interface_free(ntree, sock, true);
MEM_freeN(sock);
- ntree->update |= NTREE_UPDATE_GROUP;
+ BKE_ntree_update_tag_interface(ntree);
}
/* generates a valid RNA identifier from the node tree name */
@@ -3973,10 +3913,13 @@ int nodeSocketIsHidden(const bNodeSocket *sock)
return ((sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) != 0);
}
-void nodeSetSocketAvailability(bNodeTree *UNUSED(ntree), bNodeSocket *sock, bool is_available)
+void nodeSetSocketAvailability(bNodeTree *ntree, bNodeSocket *sock, bool is_available)
{
- /* #ntree is not needed right now, but it's generally necessary when changing the tree because we
- * want to tag it as changed in the future. */
+ const bool was_available = (sock->flag & SOCK_UNAVAIL) == 0;
+ if (is_available != was_available) {
+ BKE_ntree_update_tag_socket_availability(ntree, sock);
+ }
+
if (is_available) {
sock->flag &= ~SOCK_UNAVAIL;
}
@@ -4428,7 +4371,7 @@ void ntreeGetDependencyList(struct bNodeTree *ntree, struct bNode ***r_deplist,
}
/* only updates node->level for detecting cycles links */
-static void ntree_update_node_level(bNodeTree *ntree)
+void ntreeUpdateNodeLevels(bNodeTree *ntree)
{
/* first clear tag */
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
@@ -4463,749 +4406,42 @@ void ntreeTagUsedSockets(bNodeTree *ntree)
}
}
-static void ntree_update_link_pointers(bNodeTree *ntree)
-{
- /* first clear data */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
- sock->link = nullptr;
- }
- }
-
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- link->tosock->link = link;
- }
-
- ntreeTagUsedSockets(ntree);
-}
-
-static void ntree_validate_links(bNodeTree *ntree)
-{
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- link->flag |= NODE_LINK_VALID;
- if (link->fromnode && link->tonode && link->fromnode->level <= link->tonode->level) {
- link->flag &= ~NODE_LINK_VALID;
- }
- else if (ntree->typeinfo->validate_link) {
- if (!ntree->typeinfo->validate_link((eNodeSocketDatatype)link->fromsock->type,
- (eNodeSocketDatatype)link->tosock->type)) {
- link->flag &= ~NODE_LINK_VALID;
- }
- }
- }
-}
-
void ntreeUpdateAllNew(Main *main)
{
+ Vector<bNodeTree *> new_ntrees;
+
/* Update all new node trees on file read or append, to add/remove sockets
* in groups nodes if the group changed, and handle any update flags that
* might have been set in file reading or versioning. */
FOREACH_NODETREE_BEGIN (main, ntree, owner_id) {
if (owner_id->tag & LIB_TAG_NEW) {
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->typeinfo->group_update_func) {
- node->typeinfo->group_update_func(ntree, node);
- }
- }
-
- ntreeUpdateTree(nullptr, ntree);
+ BKE_ntree_update_tag_all(ntree);
}
}
FOREACH_NODETREE_END;
+ BKE_ntree_update_main(main, nullptr);
}
-namespace blender::bke::node_field_inferencing {
-
-static bool is_field_socket_type(eNodeSocketDatatype type)
-{
- return ELEM(type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA);
-}
-
-static bool is_field_socket_type(const SocketRef &socket)
-{
- return is_field_socket_type((eNodeSocketDatatype)socket.typeinfo()->type);
-}
-
-static bool update_field_inferencing(bNodeTree &btree);
-
-static InputSocketFieldType get_interface_input_field_type(const NodeRef &node,
- const InputSocketRef &socket)
-{
- if (!is_field_socket_type(socket)) {
- return InputSocketFieldType::None;
- }
- if (node.is_reroute_node()) {
- return InputSocketFieldType::IsSupported;
- }
- if (node.is_group_output_node()) {
- /* Outputs always support fields when the data type is correct. */
- return InputSocketFieldType::IsSupported;
- }
- if (node.is_undefined()) {
- return InputSocketFieldType::None;
- }
-
- const NodeDeclaration *node_decl = node.declaration();
-
- /* Node declarations should be implemented for nodes involved here. */
- BLI_assert(node_decl != nullptr);
-
- /* Get the field type from the declaration. */
- const SocketDeclaration &socket_decl = *node_decl->inputs()[socket.index()];
- const InputSocketFieldType field_type = socket_decl.input_field_type();
- if (field_type == InputSocketFieldType::Implicit) {
- return field_type;
- }
- if (node_decl->is_function_node()) {
- /* In a function node, every socket supports fields. */
- return InputSocketFieldType::IsSupported;
- }
- return field_type;
-}
-
-static OutputFieldDependency get_interface_output_field_dependency(const NodeRef &node,
- const OutputSocketRef &socket)
-{
- if (!is_field_socket_type(socket)) {
- /* Non-field sockets always output data. */
- return OutputFieldDependency::ForDataSource();
- }
- if (node.is_reroute_node()) {
- /* The reroute just forwards what is passed in. */
- return OutputFieldDependency::ForDependentField();
- }
- if (node.is_group_input_node()) {
- /* Input nodes get special treatment in #determine_group_input_states. */
- return OutputFieldDependency::ForDependentField();
- }
- if (node.is_undefined()) {
- return OutputFieldDependency::ForDataSource();
- }
-
- const NodeDeclaration *node_decl = node.declaration();
-
- /* Node declarations should be implemented for nodes involved here. */
- BLI_assert(node_decl != nullptr);
-
- if (node_decl->is_function_node()) {
- /* In a generic function node, all outputs depend on all inputs. */
- return OutputFieldDependency::ForDependentField();
- }
-
- /* Use the socket declaration. */
- const SocketDeclaration &socket_decl = *node_decl->outputs()[socket.index()];
- return socket_decl.output_field_dependency();
-}
-
-static FieldInferencingInterface get_dummy_field_inferencing_interface(const NodeRef &node)
-{
- FieldInferencingInterface inferencing_interface;
- inferencing_interface.inputs.append_n_times(InputSocketFieldType::None, node.inputs().size());
- inferencing_interface.outputs.append_n_times(OutputFieldDependency::ForDataSource(),
- node.outputs().size());
- return inferencing_interface;
-}
-
-/**
- * Retrieves information about how the node interacts with fields.
- * In the future, this information can be stored in the node declaration. This would allow this
- * function to return a reference, making it more efficient.
- */
-static FieldInferencingInterface get_node_field_inferencing_interface(const NodeRef &node)
-{
- /* Node groups already reference all required information, so just return that. */
- if (node.is_group_node()) {
- bNodeTree *group = (bNodeTree *)node.bnode()->id;
- if (group == nullptr) {
- return FieldInferencingInterface();
- }
- if (!ntreeIsRegistered(group)) {
- /* This can happen when there is a linked node group that was not found (see T92799). */
- return get_dummy_field_inferencing_interface(node);
- }
- if (group->field_inferencing_interface == nullptr) {
- /* Update group recursively. */
- update_field_inferencing(*group);
- }
- return *group->field_inferencing_interface;
- }
-
- FieldInferencingInterface inferencing_interface;
- for (const InputSocketRef *input_socket : node.inputs()) {
- inferencing_interface.inputs.append(get_interface_input_field_type(node, *input_socket));
- }
-
- for (const OutputSocketRef *output_socket : node.outputs()) {
- inferencing_interface.outputs.append(
- get_interface_output_field_dependency(node, *output_socket));
- }
- return inferencing_interface;
-}
-
-/**
- * This struct contains information for every socket. The values are propagated through the
- * network.
- */
-struct SocketFieldState {
- /* This socket starts a new field. */
- bool is_field_source = false;
- /* This socket can never become a field, because the node itself does not support it. */
- bool is_always_single = false;
- /* This socket is currently a single value. It could become a field though. */
- bool is_single = true;
- /* This socket is required to be a single value. This can be because the node itself only
- * supports this socket to be a single value, or because a node afterwards requires this to be a
- * single value. */
- bool requires_single = false;
-};
-
-static Vector<const InputSocketRef *> gather_input_socket_dependencies(
- const OutputFieldDependency &field_dependency, const NodeRef &node)
-{
- const OutputSocketFieldType type = field_dependency.field_type();
- Vector<const InputSocketRef *> input_sockets;
- switch (type) {
- case OutputSocketFieldType::FieldSource:
- case OutputSocketFieldType::None: {
- break;
- }
- case OutputSocketFieldType::DependentField: {
- /* This output depends on all inputs. */
- input_sockets.extend(node.inputs());
- break;
- }
- case OutputSocketFieldType::PartiallyDependent: {
- /* This output depends only on a few inputs. */
- for (const int i : field_dependency.linked_input_indices()) {
- input_sockets.append(&node.input(i));
- }
- break;
- }
- }
- return input_sockets;
-}
-
-/**
- * Check what the group output socket depends on. Potentially traverses the node tree
- * to figure out if it is always a field or if it depends on any group inputs.
- */
-static OutputFieldDependency find_group_output_dependencies(
- const InputSocketRef &group_output_socket,
- const Span<SocketFieldState> field_state_by_socket_id)
-{
- if (!is_field_socket_type(group_output_socket)) {
- return OutputFieldDependency::ForDataSource();
- }
-
- /* Use a Set here instead of an array indexed by socket id, because we my only need to look at
- * very few sockets. */
- Set<const InputSocketRef *> handled_sockets;
- Stack<const InputSocketRef *> sockets_to_check;
-
- handled_sockets.add(&group_output_socket);
- sockets_to_check.push(&group_output_socket);
-
- /* Keeps track of group input indices that are (indirectly) connected to the output. */
- Vector<int> linked_input_indices;
-
- while (!sockets_to_check.is_empty()) {
- const InputSocketRef *input_socket = sockets_to_check.pop();
-
- for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) {
- const NodeRef &origin_node = origin_socket->node();
- const SocketFieldState &origin_state = field_state_by_socket_id[origin_socket->id()];
-
- if (origin_state.is_field_source) {
- if (origin_node.is_group_input_node()) {
- /* Found a group input that the group output depends on. */
- linked_input_indices.append_non_duplicates(origin_socket->index());
- }
- else {
- /* Found a field source that is not the group input. So the output is always a field. */
- return OutputFieldDependency::ForFieldSource();
- }
- }
- else if (!origin_state.is_single) {
- const FieldInferencingInterface inferencing_interface =
- get_node_field_inferencing_interface(origin_node);
- const OutputFieldDependency &field_dependency =
- inferencing_interface.outputs[origin_socket->index()];
-
- /* Propagate search further to the left. */
- for (const InputSocketRef *origin_input_socket :
- gather_input_socket_dependencies(field_dependency, origin_node)) {
- if (!origin_input_socket->is_available()) {
- continue;
- }
- if (!field_state_by_socket_id[origin_input_socket->id()].is_single) {
- if (handled_sockets.add(origin_input_socket)) {
- sockets_to_check.push(origin_input_socket);
- }
- }
- }
- }
- }
- }
- return OutputFieldDependency::ForPartiallyDependentField(std::move(linked_input_indices));
-}
-
-static void propagate_data_requirements_from_right_to_left(
- const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id)
-{
- const NodeTreeRef::ToposortResult toposort_result = tree.toposort(
- NodeTreeRef::ToposortDirection::RightToLeft);
-
- for (const NodeRef *node : toposort_result.sorted_nodes) {
- const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface(
- *node);
-
- for (const OutputSocketRef *output_socket : node->outputs()) {
- SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
-
- const OutputFieldDependency &field_dependency =
- inferencing_interface.outputs[output_socket->index()];
-
- if (field_dependency.field_type() == OutputSocketFieldType::FieldSource) {
- continue;
- }
- if (field_dependency.field_type() == OutputSocketFieldType::None) {
- state.requires_single = true;
- state.is_always_single = true;
- continue;
- }
-
- /* The output is required to be a single value when it is connected to any input that does
- * not support fields. */
- for (const InputSocketRef *target_socket : output_socket->directly_linked_sockets()) {
- if (target_socket->is_available()) {
- state.requires_single |= field_state_by_socket_id[target_socket->id()].requires_single;
- }
- }
-
- if (state.requires_single) {
- bool any_input_is_field_implicitly = false;
- const Vector<const InputSocketRef *> connected_inputs = gather_input_socket_dependencies(
- field_dependency, *node);
- for (const InputSocketRef *input_socket : connected_inputs) {
- if (!input_socket->is_available()) {
- continue;
- }
- if (inferencing_interface.inputs[input_socket->index()] ==
- InputSocketFieldType::Implicit) {
- if (!input_socket->is_logically_linked()) {
- any_input_is_field_implicitly = true;
- break;
- }
- }
- }
- if (any_input_is_field_implicitly) {
- /* This output isn't a single value actually. */
- state.requires_single = false;
- }
- else {
- /* If the output is required to be a single value, the connected inputs in the same node
- * must not be fields as well. */
- for (const InputSocketRef *input_socket : connected_inputs) {
- field_state_by_socket_id[input_socket->id()].requires_single = true;
- }
- }
- }
- }
-
- /* Some inputs do not require fields independent of what the outputs are connected to. */
- for (const InputSocketRef *input_socket : node->inputs()) {
- SocketFieldState &state = field_state_by_socket_id[input_socket->id()];
- if (inferencing_interface.inputs[input_socket->index()] == InputSocketFieldType::None) {
- state.requires_single = true;
- state.is_always_single = true;
- }
- }
- }
-}
-
-static void determine_group_input_states(
- const NodeTreeRef &tree,
- FieldInferencingInterface &new_inferencing_interface,
- const MutableSpan<SocketFieldState> field_state_by_socket_id)
-{
- {
- /* Non-field inputs never support fields. */
- int index;
- LISTBASE_FOREACH_INDEX (bNodeSocket *, group_input, &tree.btree()->inputs, index) {
- if (!is_field_socket_type((eNodeSocketDatatype)group_input->type)) {
- new_inferencing_interface.inputs[index] = InputSocketFieldType::None;
- }
- }
- }
- /* Check if group inputs are required to be single values, because they are (indirectly)
- * connected to some socket that does not support fields. */
- for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) {
- for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) {
- SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
- if (state.requires_single) {
- new_inferencing_interface.inputs[output_socket->index()] = InputSocketFieldType::None;
- }
- }
- }
- /* If an input does not support fields, this should be reflected in all Group Input nodes. */
- for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) {
- for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) {
- SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
- const bool supports_field = new_inferencing_interface.inputs[output_socket->index()] !=
- InputSocketFieldType::None;
- if (supports_field) {
- state.is_single = false;
- state.is_field_source = true;
- }
- else {
- state.requires_single = true;
- }
- }
- SocketFieldState &dummy_socket_state = field_state_by_socket_id[node->outputs().last()->id()];
- dummy_socket_state.requires_single = true;
- }
-}
-
-static void propagate_field_status_from_left_to_right(
- const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id)
-{
- const NodeTreeRef::ToposortResult toposort_result = tree.toposort(
- NodeTreeRef::ToposortDirection::LeftToRight);
-
- for (const NodeRef *node : toposort_result.sorted_nodes) {
- if (node->is_group_input_node()) {
- continue;
- }
-
- const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface(
- *node);
-
- /* Update field state of input sockets, also taking into account linked origin sockets. */
- for (const InputSocketRef *input_socket : node->inputs()) {
- SocketFieldState &state = field_state_by_socket_id[input_socket->id()];
- if (state.is_always_single) {
- state.is_single = true;
- continue;
- }
- state.is_single = true;
- if (input_socket->directly_linked_sockets().is_empty()) {
- if (inferencing_interface.inputs[input_socket->index()] ==
- InputSocketFieldType::Implicit) {
- state.is_single = false;
- }
- }
- else {
- for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) {
- if (!field_state_by_socket_id[origin_socket->id()].is_single) {
- state.is_single = false;
- break;
- }
- }
- }
- }
-
- /* Update field state of output sockets, also taking into account input sockets. */
- for (const OutputSocketRef *output_socket : node->outputs()) {
- SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
- const OutputFieldDependency &field_dependency =
- inferencing_interface.outputs[output_socket->index()];
-
- switch (field_dependency.field_type()) {
- case OutputSocketFieldType::None: {
- state.is_single = true;
- break;
- }
- case OutputSocketFieldType::FieldSource: {
- state.is_single = false;
- state.is_field_source = true;
- break;
- }
- case OutputSocketFieldType::PartiallyDependent:
- case OutputSocketFieldType::DependentField: {
- for (const InputSocketRef *input_socket :
- gather_input_socket_dependencies(field_dependency, *node)) {
- if (!input_socket->is_available()) {
- continue;
- }
- if (!field_state_by_socket_id[input_socket->id()].is_single) {
- state.is_single = false;
- break;
- }
- }
- break;
- }
- }
- }
- }
-}
-
-static void determine_group_output_states(const NodeTreeRef &tree,
- FieldInferencingInterface &new_inferencing_interface,
- const Span<SocketFieldState> field_state_by_socket_id)
-{
- for (const NodeRef *group_output_node : tree.nodes_by_type("NodeGroupOutput")) {
- /* Ignore inactive group output nodes. */
- if (!(group_output_node->bnode()->flag & NODE_DO_OUTPUT)) {
- continue;
- }
- /* Determine dependencies of all group outputs. */
- for (const InputSocketRef *group_output_socket : group_output_node->inputs().drop_back(1)) {
- OutputFieldDependency field_dependency = find_group_output_dependencies(
- *group_output_socket, field_state_by_socket_id);
- new_inferencing_interface.outputs[group_output_socket->index()] = std::move(
- field_dependency);
- }
- break;
- }
-}
-
-static void update_socket_shapes(const NodeTreeRef &tree,
- const Span<SocketFieldState> field_state_by_socket_id)
-{
- const eNodeSocketDisplayShape requires_data_shape = SOCK_DISPLAY_SHAPE_CIRCLE;
- const eNodeSocketDisplayShape data_but_can_be_field_shape = SOCK_DISPLAY_SHAPE_DIAMOND_DOT;
- const eNodeSocketDisplayShape is_field_shape = SOCK_DISPLAY_SHAPE_DIAMOND;
-
- auto get_shape_for_state = [&](const SocketFieldState &state) {
- if (state.is_always_single) {
- return requires_data_shape;
- }
- if (!state.is_single) {
- return is_field_shape;
- }
- if (state.requires_single) {
- return requires_data_shape;
- }
- return data_but_can_be_field_shape;
- };
-
- for (const InputSocketRef *socket : tree.input_sockets()) {
- bNodeSocket *bsocket = socket->bsocket();
- const SocketFieldState &state = field_state_by_socket_id[socket->id()];
- bsocket->display_shape = get_shape_for_state(state);
- }
- for (const OutputSocketRef *socket : tree.output_sockets()) {
- bNodeSocket *bsocket = socket->bsocket();
- const SocketFieldState &state = field_state_by_socket_id[socket->id()];
- bsocket->display_shape = get_shape_for_state(state);
- }
-}
-
-static bool update_field_inferencing(bNodeTree &btree)
-{
- using namespace blender::nodes;
- if (btree.type != NTREE_GEOMETRY) {
- return false;
- }
-
- /* Create new inferencing interface for this node group. */
- FieldInferencingInterface *new_inferencing_interface = new FieldInferencingInterface();
- new_inferencing_interface->inputs.resize(BLI_listbase_count(&btree.inputs),
- InputSocketFieldType::IsSupported);
- new_inferencing_interface->outputs.resize(BLI_listbase_count(&btree.outputs),
- OutputFieldDependency::ForDataSource());
-
- /* Create #NodeTreeRef to accelerate various queries on the node tree (e.g. linked sockets). */
- const NodeTreeRef tree{&btree};
-
- /* Keep track of the state of all sockets. The index into this array is #SocketRef::id(). */
- Array<SocketFieldState> field_state_by_socket_id(tree.sockets().size());
-
- propagate_data_requirements_from_right_to_left(tree, field_state_by_socket_id);
- determine_group_input_states(tree, *new_inferencing_interface, field_state_by_socket_id);
- propagate_field_status_from_left_to_right(tree, field_state_by_socket_id);
- determine_group_output_states(tree, *new_inferencing_interface, field_state_by_socket_id);
- update_socket_shapes(tree, field_state_by_socket_id);
-
- /* Update the previous group interface. */
- const bool group_interface_changed = btree.field_inferencing_interface == nullptr ||
- *btree.field_inferencing_interface !=
- *new_inferencing_interface;
- delete btree.field_inferencing_interface;
- btree.field_inferencing_interface = new_inferencing_interface;
-
- return group_interface_changed;
-}
-
-} // namespace blender::bke::node_field_inferencing
-
-void ntreeUpdateAllUsers(Main *main, ID *id, const int tree_update_flag)
+void ntreeUpdateAllUsers(Main *main, ID *id)
{
if (id == nullptr) {
return;
}
+ bool need_update = false;
+
/* Update all users of ngroup, to add/remove sockets as needed. */
FOREACH_NODETREE_BEGIN (main, ntree, owner_id) {
- bool need_update = false;
-
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->id == id) {
- if (node->typeinfo->group_update_func) {
- node->typeinfo->group_update_func(ntree, node);
- }
-
+ BKE_ntree_update_tag_node_property(ntree, node);
need_update = true;
}
}
-
- if (need_update) {
- ntree->update |= tree_update_flag;
- ntreeUpdateTree(tree_update_flag ? main : nullptr, ntree);
- }
}
FOREACH_NODETREE_END;
-
- if (GS(id->name) == ID_NT) {
- bNodeTree *ngroup = (bNodeTree *)id;
- if (ngroup->type == NTREE_GEOMETRY && (ngroup->update & NTREE_UPDATE_GROUP)) {
- LISTBASE_FOREACH (Object *, object, &main->objects) {
- LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
- if (md->type == eModifierType_Nodes) {
- NodesModifierData *nmd = (NodesModifierData *)md;
- if (nmd->node_group == ngroup) {
- MOD_nodes_update_interface(object, nmd);
- }
- }
- }
- }
- }
- }
-}
-
-void ntreeUpdateTree(Main *bmain, bNodeTree *ntree)
-{
- if (!ntree) {
- return;
- }
-
- /* Avoid re-entrant updates, can be caused by RNA update callbacks. */
- if (ntree->is_updating) {
- return;
- }
- ntree->is_updating = true;
-
- if (ntree->update & (NTREE_UPDATE_LINKS | NTREE_UPDATE_NODES)) {
- /* set the bNodeSocket->link pointers */
- ntree_update_link_pointers(ntree);
- }
-
- /* update individual nodes */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- /* node tree update tags override individual node update flags */
- if ((node->update & NODE_UPDATE) || (ntree->update & NTREE_UPDATE)) {
- if (node->typeinfo->updatefunc) {
- node->typeinfo->updatefunc(ntree, node);
- }
-
- nodeUpdateInternalLinks(ntree, node);
- }
- }
-
- /* generic tree update callback */
- if (ntree->typeinfo->update) {
- ntree->typeinfo->update(ntree);
- }
- /* XXX this should be moved into the tree type update callback for tree supporting node groups.
- * Currently the node tree interface is still a generic feature of the base NodeTree type.
- */
- if (ntree->update & NTREE_UPDATE_GROUP) {
- ntreeInterfaceTypeUpdate(ntree);
- }
-
- int tree_user_update_flag = 0;
-
- if (ntree->update & NTREE_UPDATE) {
- /* If the field interface of this node tree has changed, all node trees using
- * this group will need to recalculate their interface as well. */
- if (blender::bke::node_field_inferencing::update_field_inferencing(*ntree)) {
- tree_user_update_flag |= NTREE_UPDATE_FIELD_INFERENCING;
- }
- }
-
- if (bmain) {
- ntreeUpdateAllUsers(bmain, &ntree->id, tree_user_update_flag);
- }
-
- if (ntree->update & (NTREE_UPDATE_LINKS | NTREE_UPDATE_NODES)) {
- /* node updates can change sockets or links, repeat link pointer update afterward */
- ntree_update_link_pointers(ntree);
-
- /* update the node level from link dependencies */
- ntree_update_node_level(ntree);
-
- /* check link validity */
- ntree_validate_links(ntree);
- }
-
- /* clear update flags */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- node->update = 0;
- }
- ntree->update = 0;
-
- ntree->is_updating = false;
-}
-
-void nodeUpdate(bNodeTree *ntree, bNode *node)
-{
- /* Avoid re-entrant updates, can be caused by RNA update callbacks. */
- if (ntree->is_updating) {
- return;
- }
- ntree->is_updating = true;
-
- if (node->typeinfo->updatefunc) {
- node->typeinfo->updatefunc(ntree, node);
- }
-
- nodeUpdateInternalLinks(ntree, node);
-
- /* clear update flag */
- node->update = 0;
-
- ntree->is_updating = false;
-}
-
-bool nodeUpdateID(bNodeTree *ntree, ID *id)
-{
- bool changed = false;
-
- if (ELEM(nullptr, id, ntree)) {
- return changed;
- }
-
- /* Avoid re-entrant updates, can be caused by RNA update callbacks. */
- if (ntree->is_updating) {
- return changed;
- }
- ntree->is_updating = true;
-
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->id == id) {
- changed = true;
- node->update |= NODE_UPDATE_ID;
- if (node->typeinfo->updatefunc) {
- node->typeinfo->updatefunc(ntree, node);
- }
- /* clear update flag */
- node->update = 0;
- }
- }
-
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- nodeUpdateInternalLinks(ntree, node);
- }
-
- ntree->is_updating = false;
- return changed;
-}
-
-void nodeUpdateInternalLinks(bNodeTree *ntree, bNode *node)
-{
- BLI_freelistN(&node->internal_links);
- if (!node->typeinfo->no_muting) {
- node_internal_links_create(ntree, node);
+ if (need_update) {
+ BKE_ntree_update_main(main, nullptr);
}
}
diff --git a/source/blender/blenkernel/intern/node_tree_update.cc b/source/blender/blenkernel/intern/node_tree_update.cc
new file mode 100644
index 00000000000..427fac747dc
--- /dev/null
+++ b/source/blender/blenkernel/intern/node_tree_update.cc
@@ -0,0 +1,1658 @@
+/*
+ * 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_map.hh"
+#include "BLI_multi_value_map.hh"
+#include "BLI_noise.hh"
+#include "BLI_set.hh"
+#include "BLI_stack.hh"
+#include "BLI_vector_set.hh"
+
+#include "DNA_anim_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_node_types.h"
+
+#include "BKE_anim_data.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
+
+#include "MOD_nodes.h"
+
+#include "NOD_node_declaration.hh"
+#include "NOD_node_tree_ref.hh"
+
+#include "DEG_depsgraph_query.h"
+
+using namespace blender::nodes;
+
+/**
+ * These flags are used by the `changed_flag` field in #bNodeTree, #bNode and #bNodeSocket.
+ * This enum is not part of the public api. It should be used through the `BKE_ntree_update_tag_*`
+ * api.
+ */
+enum eNodeTreeChangedFlag {
+ NTREE_CHANGED_NOTHING = 0,
+ NTREE_CHANGED_ANY = (1 << 1),
+ NTREE_CHANGED_NODE_PROPERTY = (1 << 2),
+ NTREE_CHANGED_NODE_OUTPUT = (1 << 3),
+ NTREE_CHANGED_INTERFACE = (1 << 4),
+ NTREE_CHANGED_LINK = (1 << 5),
+ NTREE_CHANGED_REMOVED_NODE = (1 << 6),
+ NTREE_CHANGED_REMOVED_SOCKET = (1 << 7),
+ NTREE_CHANGED_SOCKET_PROPERTY = (1 << 8),
+ NTREE_CHANGED_INTERNAL_LINK = (1 << 9),
+ NTREE_CHANGED_ALL = -1,
+};
+
+static void add_tree_tag(bNodeTree *ntree, const eNodeTreeChangedFlag flag)
+{
+ ntree->changed_flag |= flag;
+}
+
+static void add_node_tag(bNodeTree *ntree, bNode *node, const eNodeTreeChangedFlag flag)
+{
+ add_tree_tag(ntree, flag);
+ node->changed_flag |= flag;
+}
+
+static void add_socket_tag(bNodeTree *ntree, bNodeSocket *socket, const eNodeTreeChangedFlag flag)
+{
+ add_tree_tag(ntree, flag);
+ socket->changed_flag |= flag;
+}
+
+namespace blender::bke {
+
+namespace node_field_inferencing {
+
+static bool is_field_socket_type(eNodeSocketDatatype type)
+{
+ return ELEM(type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA);
+}
+
+static bool is_field_socket_type(const SocketRef &socket)
+{
+ return is_field_socket_type((eNodeSocketDatatype)socket.typeinfo()->type);
+}
+
+static InputSocketFieldType get_interface_input_field_type(const NodeRef &node,
+ const InputSocketRef &socket)
+{
+ if (!is_field_socket_type(socket)) {
+ return InputSocketFieldType::None;
+ }
+ if (node.is_reroute_node()) {
+ return InputSocketFieldType::IsSupported;
+ }
+ if (node.is_group_output_node()) {
+ /* Outputs always support fields when the data type is correct. */
+ return InputSocketFieldType::IsSupported;
+ }
+ if (node.is_undefined()) {
+ return InputSocketFieldType::None;
+ }
+
+ const NodeDeclaration *node_decl = node.declaration();
+
+ /* Node declarations should be implemented for nodes involved here. */
+ BLI_assert(node_decl != nullptr);
+
+ /* Get the field type from the declaration. */
+ const SocketDeclaration &socket_decl = *node_decl->inputs()[socket.index()];
+ const InputSocketFieldType field_type = socket_decl.input_field_type();
+ if (field_type == InputSocketFieldType::Implicit) {
+ return field_type;
+ }
+ if (node_decl->is_function_node()) {
+ /* In a function node, every socket supports fields. */
+ return InputSocketFieldType::IsSupported;
+ }
+ return field_type;
+}
+
+static OutputFieldDependency get_interface_output_field_dependency(const NodeRef &node,
+ const OutputSocketRef &socket)
+{
+ if (!is_field_socket_type(socket)) {
+ /* Non-field sockets always output data. */
+ return OutputFieldDependency::ForDataSource();
+ }
+ if (node.is_reroute_node()) {
+ /* The reroute just forwards what is passed in. */
+ return OutputFieldDependency::ForDependentField();
+ }
+ if (node.is_group_input_node()) {
+ /* Input nodes get special treatment in #determine_group_input_states. */
+ return OutputFieldDependency::ForDependentField();
+ }
+ if (node.is_undefined()) {
+ return OutputFieldDependency::ForDataSource();
+ }
+
+ const NodeDeclaration *node_decl = node.declaration();
+
+ /* Node declarations should be implemented for nodes involved here. */
+ BLI_assert(node_decl != nullptr);
+
+ if (node_decl->is_function_node()) {
+ /* In a generic function node, all outputs depend on all inputs. */
+ return OutputFieldDependency::ForDependentField();
+ }
+
+ /* Use the socket declaration. */
+ const SocketDeclaration &socket_decl = *node_decl->outputs()[socket.index()];
+ return socket_decl.output_field_dependency();
+}
+
+static FieldInferencingInterface get_dummy_field_inferencing_interface(const NodeRef &node)
+{
+ FieldInferencingInterface inferencing_interface;
+ inferencing_interface.inputs.append_n_times(InputSocketFieldType::None, node.inputs().size());
+ inferencing_interface.outputs.append_n_times(OutputFieldDependency::ForDataSource(),
+ node.outputs().size());
+ return inferencing_interface;
+}
+
+/**
+ * Retrieves information about how the node interacts with fields.
+ * In the future, this information can be stored in the node declaration. This would allow this
+ * function to return a reference, making it more efficient.
+ */
+static FieldInferencingInterface get_node_field_inferencing_interface(const NodeRef &node)
+{
+ /* Node groups already reference all required information, so just return that. */
+ if (node.is_group_node()) {
+ bNodeTree *group = (bNodeTree *)node.bnode()->id;
+ if (group == nullptr) {
+ return FieldInferencingInterface();
+ }
+ if (!ntreeIsRegistered(group)) {
+ /* This can happen when there is a linked node group that was not found (see T92799). */
+ return get_dummy_field_inferencing_interface(node);
+ }
+ if (group->field_inferencing_interface == nullptr) {
+ /* This shouldn't happen because referenced node groups should always be updated first. */
+ BLI_assert_unreachable();
+ }
+ return *group->field_inferencing_interface;
+ }
+
+ FieldInferencingInterface inferencing_interface;
+ for (const InputSocketRef *input_socket : node.inputs()) {
+ inferencing_interface.inputs.append(get_interface_input_field_type(node, *input_socket));
+ }
+
+ for (const OutputSocketRef *output_socket : node.outputs()) {
+ inferencing_interface.outputs.append(
+ get_interface_output_field_dependency(node, *output_socket));
+ }
+ return inferencing_interface;
+}
+
+/**
+ * This struct contains information for every socket. The values are propagated through the
+ * network.
+ */
+struct SocketFieldState {
+ /* This socket starts a new field. */
+ bool is_field_source = false;
+ /* This socket can never become a field, because the node itself does not support it. */
+ bool is_always_single = false;
+ /* This socket is currently a single value. It could become a field though. */
+ bool is_single = true;
+ /* This socket is required to be a single value. This can be because the node itself only
+ * supports this socket to be a single value, or because a node afterwards requires this to be a
+ * single value. */
+ bool requires_single = false;
+};
+
+static Vector<const InputSocketRef *> gather_input_socket_dependencies(
+ const OutputFieldDependency &field_dependency, const NodeRef &node)
+{
+ const OutputSocketFieldType type = field_dependency.field_type();
+ Vector<const InputSocketRef *> input_sockets;
+ switch (type) {
+ case OutputSocketFieldType::FieldSource:
+ case OutputSocketFieldType::None: {
+ break;
+ }
+ case OutputSocketFieldType::DependentField: {
+ /* This output depends on all inputs. */
+ input_sockets.extend(node.inputs());
+ break;
+ }
+ case OutputSocketFieldType::PartiallyDependent: {
+ /* This output depends only on a few inputs. */
+ for (const int i : field_dependency.linked_input_indices()) {
+ input_sockets.append(&node.input(i));
+ }
+ break;
+ }
+ }
+ return input_sockets;
+}
+
+/**
+ * Check what the group output socket depends on. Potentially traverses the node tree
+ * to figure out if it is always a field or if it depends on any group inputs.
+ */
+static OutputFieldDependency find_group_output_dependencies(
+ const InputSocketRef &group_output_socket,
+ const Span<SocketFieldState> field_state_by_socket_id)
+{
+ if (!is_field_socket_type(group_output_socket)) {
+ return OutputFieldDependency::ForDataSource();
+ }
+
+ /* Use a Set here instead of an array indexed by socket id, because we my only need to look at
+ * very few sockets. */
+ Set<const InputSocketRef *> handled_sockets;
+ Stack<const InputSocketRef *> sockets_to_check;
+
+ handled_sockets.add(&group_output_socket);
+ sockets_to_check.push(&group_output_socket);
+
+ /* Keeps track of group input indices that are (indirectly) connected to the output. */
+ Vector<int> linked_input_indices;
+
+ while (!sockets_to_check.is_empty()) {
+ const InputSocketRef *input_socket = sockets_to_check.pop();
+
+ for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) {
+ const NodeRef &origin_node = origin_socket->node();
+ const SocketFieldState &origin_state = field_state_by_socket_id[origin_socket->id()];
+
+ if (origin_state.is_field_source) {
+ if (origin_node.is_group_input_node()) {
+ /* Found a group input that the group output depends on. */
+ linked_input_indices.append_non_duplicates(origin_socket->index());
+ }
+ else {
+ /* Found a field source that is not the group input. So the output is always a field. */
+ return OutputFieldDependency::ForFieldSource();
+ }
+ }
+ else if (!origin_state.is_single) {
+ const FieldInferencingInterface inferencing_interface =
+ get_node_field_inferencing_interface(origin_node);
+ const OutputFieldDependency &field_dependency =
+ inferencing_interface.outputs[origin_socket->index()];
+
+ /* Propagate search further to the left. */
+ for (const InputSocketRef *origin_input_socket :
+ gather_input_socket_dependencies(field_dependency, origin_node)) {
+ if (!origin_input_socket->is_available()) {
+ continue;
+ }
+ if (!field_state_by_socket_id[origin_input_socket->id()].is_single) {
+ if (handled_sockets.add(origin_input_socket)) {
+ sockets_to_check.push(origin_input_socket);
+ }
+ }
+ }
+ }
+ }
+ }
+ return OutputFieldDependency::ForPartiallyDependentField(std::move(linked_input_indices));
+}
+
+static void propagate_data_requirements_from_right_to_left(
+ const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id)
+{
+ const NodeTreeRef::ToposortResult toposort_result = tree.toposort(
+ NodeTreeRef::ToposortDirection::RightToLeft);
+
+ for (const NodeRef *node : toposort_result.sorted_nodes) {
+ const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface(
+ *node);
+
+ for (const OutputSocketRef *output_socket : node->outputs()) {
+ SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
+
+ const OutputFieldDependency &field_dependency =
+ inferencing_interface.outputs[output_socket->index()];
+
+ if (field_dependency.field_type() == OutputSocketFieldType::FieldSource) {
+ continue;
+ }
+ if (field_dependency.field_type() == OutputSocketFieldType::None) {
+ state.requires_single = true;
+ state.is_always_single = true;
+ continue;
+ }
+
+ /* The output is required to be a single value when it is connected to any input that does
+ * not support fields. */
+ for (const InputSocketRef *target_socket : output_socket->directly_linked_sockets()) {
+ if (target_socket->is_available()) {
+ state.requires_single |= field_state_by_socket_id[target_socket->id()].requires_single;
+ }
+ }
+
+ if (state.requires_single) {
+ bool any_input_is_field_implicitly = false;
+ const Vector<const InputSocketRef *> connected_inputs = gather_input_socket_dependencies(
+ field_dependency, *node);
+ for (const InputSocketRef *input_socket : connected_inputs) {
+ if (!input_socket->is_available()) {
+ continue;
+ }
+ if (inferencing_interface.inputs[input_socket->index()] ==
+ InputSocketFieldType::Implicit) {
+ if (!input_socket->is_logically_linked()) {
+ any_input_is_field_implicitly = true;
+ break;
+ }
+ }
+ }
+ if (any_input_is_field_implicitly) {
+ /* This output isn't a single value actually. */
+ state.requires_single = false;
+ }
+ else {
+ /* If the output is required to be a single value, the connected inputs in the same node
+ * must not be fields as well. */
+ for (const InputSocketRef *input_socket : connected_inputs) {
+ field_state_by_socket_id[input_socket->id()].requires_single = true;
+ }
+ }
+ }
+ }
+
+ /* Some inputs do not require fields independent of what the outputs are connected to. */
+ for (const InputSocketRef *input_socket : node->inputs()) {
+ SocketFieldState &state = field_state_by_socket_id[input_socket->id()];
+ if (inferencing_interface.inputs[input_socket->index()] == InputSocketFieldType::None) {
+ state.requires_single = true;
+ state.is_always_single = true;
+ }
+ }
+ }
+}
+
+static void determine_group_input_states(
+ const NodeTreeRef &tree,
+ FieldInferencingInterface &new_inferencing_interface,
+ const MutableSpan<SocketFieldState> field_state_by_socket_id)
+{
+ {
+ /* Non-field inputs never support fields. */
+ int index;
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, group_input, &tree.btree()->inputs, index) {
+ if (!is_field_socket_type((eNodeSocketDatatype)group_input->type)) {
+ new_inferencing_interface.inputs[index] = InputSocketFieldType::None;
+ }
+ }
+ }
+ /* Check if group inputs are required to be single values, because they are (indirectly)
+ * connected to some socket that does not support fields. */
+ for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) {
+ for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) {
+ SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
+ if (state.requires_single) {
+ new_inferencing_interface.inputs[output_socket->index()] = InputSocketFieldType::None;
+ }
+ }
+ }
+ /* If an input does not support fields, this should be reflected in all Group Input nodes. */
+ for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) {
+ for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) {
+ SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
+ const bool supports_field = new_inferencing_interface.inputs[output_socket->index()] !=
+ InputSocketFieldType::None;
+ if (supports_field) {
+ state.is_single = false;
+ state.is_field_source = true;
+ }
+ else {
+ state.requires_single = true;
+ }
+ }
+ SocketFieldState &dummy_socket_state = field_state_by_socket_id[node->outputs().last()->id()];
+ dummy_socket_state.requires_single = true;
+ }
+}
+
+static void propagate_field_status_from_left_to_right(
+ const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id)
+{
+ const NodeTreeRef::ToposortResult toposort_result = tree.toposort(
+ NodeTreeRef::ToposortDirection::LeftToRight);
+
+ for (const NodeRef *node : toposort_result.sorted_nodes) {
+ if (node->is_group_input_node()) {
+ continue;
+ }
+
+ const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface(
+ *node);
+
+ /* Update field state of input sockets, also taking into account linked origin sockets. */
+ for (const InputSocketRef *input_socket : node->inputs()) {
+ SocketFieldState &state = field_state_by_socket_id[input_socket->id()];
+ if (state.is_always_single) {
+ state.is_single = true;
+ continue;
+ }
+ state.is_single = true;
+ if (input_socket->directly_linked_sockets().is_empty()) {
+ if (inferencing_interface.inputs[input_socket->index()] ==
+ InputSocketFieldType::Implicit) {
+ state.is_single = false;
+ }
+ }
+ else {
+ for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) {
+ if (!field_state_by_socket_id[origin_socket->id()].is_single) {
+ state.is_single = false;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Update field state of output sockets, also taking into account input sockets. */
+ for (const OutputSocketRef *output_socket : node->outputs()) {
+ SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
+ const OutputFieldDependency &field_dependency =
+ inferencing_interface.outputs[output_socket->index()];
+
+ switch (field_dependency.field_type()) {
+ case OutputSocketFieldType::None: {
+ state.is_single = true;
+ break;
+ }
+ case OutputSocketFieldType::FieldSource: {
+ state.is_single = false;
+ state.is_field_source = true;
+ break;
+ }
+ case OutputSocketFieldType::PartiallyDependent:
+ case OutputSocketFieldType::DependentField: {
+ for (const InputSocketRef *input_socket :
+ gather_input_socket_dependencies(field_dependency, *node)) {
+ if (!input_socket->is_available()) {
+ continue;
+ }
+ if (!field_state_by_socket_id[input_socket->id()].is_single) {
+ state.is_single = false;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void determine_group_output_states(const NodeTreeRef &tree,
+ FieldInferencingInterface &new_inferencing_interface,
+ const Span<SocketFieldState> field_state_by_socket_id)
+{
+ for (const NodeRef *group_output_node : tree.nodes_by_type("NodeGroupOutput")) {
+ /* Ignore inactive group output nodes. */
+ if (!(group_output_node->bnode()->flag & NODE_DO_OUTPUT)) {
+ continue;
+ }
+ /* Determine dependencies of all group outputs. */
+ for (const InputSocketRef *group_output_socket : group_output_node->inputs().drop_back(1)) {
+ OutputFieldDependency field_dependency = find_group_output_dependencies(
+ *group_output_socket, field_state_by_socket_id);
+ new_inferencing_interface.outputs[group_output_socket->index()] = std::move(
+ field_dependency);
+ }
+ break;
+ }
+}
+
+static void update_socket_shapes(const NodeTreeRef &tree,
+ const Span<SocketFieldState> field_state_by_socket_id)
+{
+ const eNodeSocketDisplayShape requires_data_shape = SOCK_DISPLAY_SHAPE_CIRCLE;
+ const eNodeSocketDisplayShape data_but_can_be_field_shape = SOCK_DISPLAY_SHAPE_DIAMOND_DOT;
+ const eNodeSocketDisplayShape is_field_shape = SOCK_DISPLAY_SHAPE_DIAMOND;
+
+ auto get_shape_for_state = [&](const SocketFieldState &state) {
+ if (state.is_always_single) {
+ return requires_data_shape;
+ }
+ if (!state.is_single) {
+ return is_field_shape;
+ }
+ if (state.requires_single) {
+ return requires_data_shape;
+ }
+ return data_but_can_be_field_shape;
+ };
+
+ for (const InputSocketRef *socket : tree.input_sockets()) {
+ bNodeSocket *bsocket = socket->bsocket();
+ const SocketFieldState &state = field_state_by_socket_id[socket->id()];
+ bsocket->display_shape = get_shape_for_state(state);
+ }
+ for (const OutputSocketRef *socket : tree.output_sockets()) {
+ bNodeSocket *bsocket = socket->bsocket();
+ const SocketFieldState &state = field_state_by_socket_id[socket->id()];
+ bsocket->display_shape = get_shape_for_state(state);
+ }
+}
+
+static bool update_field_inferencing(const NodeTreeRef &tree)
+{
+ bNodeTree &btree = *tree.btree();
+
+ /* Create new inferencing interface for this node group. */
+ FieldInferencingInterface *new_inferencing_interface = new FieldInferencingInterface();
+ new_inferencing_interface->inputs.resize(BLI_listbase_count(&btree.inputs),
+ InputSocketFieldType::IsSupported);
+ new_inferencing_interface->outputs.resize(BLI_listbase_count(&btree.outputs),
+ OutputFieldDependency::ForDataSource());
+
+ /* Keep track of the state of all sockets. The index into this array is #SocketRef::id(). */
+ Array<SocketFieldState> field_state_by_socket_id(tree.sockets().size());
+
+ propagate_data_requirements_from_right_to_left(tree, field_state_by_socket_id);
+ determine_group_input_states(tree, *new_inferencing_interface, field_state_by_socket_id);
+ propagate_field_status_from_left_to_right(tree, field_state_by_socket_id);
+ determine_group_output_states(tree, *new_inferencing_interface, field_state_by_socket_id);
+ update_socket_shapes(tree, field_state_by_socket_id);
+
+ /* Update the previous group interface. */
+ const bool group_interface_changed = btree.field_inferencing_interface == nullptr ||
+ *btree.field_inferencing_interface !=
+ *new_inferencing_interface;
+ delete btree.field_inferencing_interface;
+ btree.field_inferencing_interface = new_inferencing_interface;
+
+ return group_interface_changed;
+}
+
+} // namespace node_field_inferencing
+
+/**
+ * Common datatype priorities, works for compositor, shader and texture nodes alike
+ * defines priority of datatype connection based on output type (to):
+ * `< 0`: never connect these types.
+ * `>= 0`: priority of connection (higher values chosen first).
+ */
+static int get_internal_link_type_priority(const bNodeSocketType *from, const bNodeSocketType *to)
+{
+ switch (to->type) {
+ case SOCK_RGBA:
+ switch (from->type) {
+ case SOCK_RGBA:
+ return 4;
+ case SOCK_FLOAT:
+ return 3;
+ case SOCK_INT:
+ return 2;
+ case SOCK_BOOLEAN:
+ return 1;
+ }
+ return -1;
+ case SOCK_VECTOR:
+ switch (from->type) {
+ case SOCK_VECTOR:
+ return 4;
+ case SOCK_FLOAT:
+ return 3;
+ case SOCK_INT:
+ return 2;
+ case SOCK_BOOLEAN:
+ return 1;
+ }
+ return -1;
+ case SOCK_FLOAT:
+ switch (from->type) {
+ case SOCK_FLOAT:
+ return 5;
+ case SOCK_INT:
+ return 4;
+ case SOCK_BOOLEAN:
+ return 3;
+ case SOCK_RGBA:
+ return 2;
+ case SOCK_VECTOR:
+ return 1;
+ }
+ return -1;
+ case SOCK_INT:
+ switch (from->type) {
+ case SOCK_INT:
+ return 5;
+ case SOCK_FLOAT:
+ return 4;
+ case SOCK_BOOLEAN:
+ return 3;
+ case SOCK_RGBA:
+ return 2;
+ case SOCK_VECTOR:
+ return 1;
+ }
+ return -1;
+ case SOCK_BOOLEAN:
+ switch (from->type) {
+ case SOCK_BOOLEAN:
+ return 5;
+ case SOCK_INT:
+ return 4;
+ case SOCK_FLOAT:
+ return 3;
+ case SOCK_RGBA:
+ return 2;
+ case SOCK_VECTOR:
+ return 1;
+ }
+ return -1;
+ }
+
+ /* The rest of the socket types only allow an internal link if both the input and output socket
+ * have the same type. If the sockets are custom, we check the idname instead. */
+ if (to->type == from->type && (to->type != SOCK_CUSTOM || STREQ(to->idname, from->idname))) {
+ return 1;
+ }
+
+ return -1;
+}
+
+using TreeNodePair = std::pair<bNodeTree *, bNode *>;
+using ObjectModifierPair = std::pair<Object *, ModifierData *>;
+using NodeSocketPair = std::pair<bNode *, bNodeSocket *>;
+
+/**
+ * Cache common data about node trees from the #Main database that is expensive to retrieve on
+ * demand every time.
+ */
+struct NodeTreeRelations {
+ private:
+ Main *bmain_;
+ std::optional<Vector<bNodeTree *>> all_trees_;
+ std::optional<Map<bNodeTree *, ID *>> owner_ids_;
+ std::optional<MultiValueMap<bNodeTree *, TreeNodePair>> group_node_users_;
+ std::optional<MultiValueMap<bNodeTree *, ObjectModifierPair>> modifiers_users_;
+
+ public:
+ NodeTreeRelations(Main *bmain) : bmain_(bmain)
+ {
+ }
+
+ void ensure_all_trees()
+ {
+ if (all_trees_.has_value()) {
+ return;
+ }
+ all_trees_.emplace();
+ owner_ids_.emplace();
+ if (bmain_ == nullptr) {
+ return;
+ }
+
+ FOREACH_NODETREE_BEGIN (bmain_, ntree, id) {
+ all_trees_->append(ntree);
+ if (&ntree->id != id) {
+ owner_ids_->add_new(ntree, id);
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
+
+ void ensure_owner_ids()
+ {
+ this->ensure_all_trees();
+ }
+
+ void ensure_group_node_users()
+ {
+ if (group_node_users_.has_value()) {
+ return;
+ }
+ group_node_users_.emplace();
+ if (bmain_ == nullptr) {
+ return;
+ }
+
+ this->ensure_all_trees();
+
+ for (bNodeTree *ntree : *all_trees_) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->id == nullptr) {
+ continue;
+ }
+ ID *id = node->id;
+ if (GS(id->name) == ID_NT) {
+ bNodeTree *group = (bNodeTree *)id;
+ group_node_users_->add(group, {ntree, node});
+ }
+ }
+ }
+ }
+
+ void ensure_modifier_users()
+ {
+ if (modifiers_users_.has_value()) {
+ return;
+ }
+ modifiers_users_.emplace();
+ if (bmain_ == nullptr) {
+ return;
+ }
+
+ LISTBASE_FOREACH (Object *, object, &bmain_->objects) {
+ LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
+ if (md->type == eModifierType_Nodes) {
+ NodesModifierData *nmd = (NodesModifierData *)md;
+ if (nmd->node_group != nullptr) {
+ modifiers_users_->add(nmd->node_group, {object, md});
+ }
+ }
+ }
+ }
+ }
+
+ Span<ObjectModifierPair> get_modifier_users(bNodeTree *ntree)
+ {
+ BLI_assert(modifiers_users_.has_value());
+ return modifiers_users_->lookup(ntree);
+ }
+
+ Span<TreeNodePair> get_group_node_users(bNodeTree *ntree)
+ {
+ BLI_assert(group_node_users_.has_value());
+ return group_node_users_->lookup(ntree);
+ }
+
+ ID *get_owner_id(bNodeTree *ntree)
+ {
+ BLI_assert(owner_ids_.has_value());
+ return owner_ids_->lookup_default(ntree, &ntree->id);
+ }
+};
+
+struct TreeUpdateResult {
+ bool interface_changed = false;
+ bool output_changed = false;
+};
+
+class NodeTreeMainUpdater {
+ private:
+ Main *bmain_;
+ NodeTreeUpdateExtraParams *params_;
+ Map<bNodeTree *, TreeUpdateResult> update_result_by_tree_;
+ NodeTreeRelations relations_;
+
+ public:
+ NodeTreeMainUpdater(Main *bmain, NodeTreeUpdateExtraParams *params)
+ : bmain_(bmain), params_(params), relations_(bmain)
+ {
+ }
+
+ void update()
+ {
+ Vector<bNodeTree *> changed_ntrees;
+ FOREACH_NODETREE_BEGIN (bmain_, ntree, id) {
+ if (ntree->changed_flag != NTREE_CHANGED_NOTHING) {
+ changed_ntrees.append(ntree);
+ }
+ }
+ FOREACH_NODETREE_END;
+ this->update_rooted(changed_ntrees);
+ }
+
+ void update_rooted(Span<bNodeTree *> root_ntrees)
+ {
+ if (root_ntrees.is_empty()) {
+ return;
+ }
+
+ bool is_single_tree_update = false;
+
+ if (root_ntrees.size() == 1) {
+ bNodeTree *ntree = root_ntrees[0];
+ if (ntree->changed_flag == NTREE_CHANGED_NOTHING) {
+ return;
+ }
+ const TreeUpdateResult result = this->update_tree(*ntree);
+ update_result_by_tree_.add_new(ntree, result);
+ if (!result.interface_changed && !result.output_changed) {
+ is_single_tree_update = true;
+ }
+ }
+
+ if (!is_single_tree_update) {
+ Vector<bNodeTree *> ntrees_in_order = this->get_tree_update_order(root_ntrees);
+ for (bNodeTree *ntree : ntrees_in_order) {
+ if (ntree->changed_flag == NTREE_CHANGED_NOTHING) {
+ continue;
+ }
+ if (!update_result_by_tree_.contains(ntree)) {
+ const TreeUpdateResult result = this->update_tree(*ntree);
+ update_result_by_tree_.add_new(ntree, result);
+ }
+ const TreeUpdateResult result = update_result_by_tree_.lookup(ntree);
+ Span<TreeNodePair> dependent_trees = relations_.get_group_node_users(ntree);
+ if (result.output_changed) {
+ for (const TreeNodePair &pair : dependent_trees) {
+ add_node_tag(pair.first, pair.second, NTREE_CHANGED_NODE_OUTPUT);
+ }
+ }
+ if (result.interface_changed) {
+ for (const TreeNodePair &pair : dependent_trees) {
+ add_node_tag(pair.first, pair.second, NTREE_CHANGED_NODE_PROPERTY);
+ }
+ }
+ }
+ }
+
+ for (const auto item : update_result_by_tree_.items()) {
+ bNodeTree *ntree = item.key;
+ const TreeUpdateResult &result = item.value;
+
+ this->reset_changed_flags(*ntree);
+
+ if (result.interface_changed) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ relations_.ensure_modifier_users();
+ for (const ObjectModifierPair &pair : relations_.get_modifier_users(ntree)) {
+ Object *object = pair.first;
+ ModifierData *md = pair.second;
+
+ if (md->type == eModifierType_Nodes) {
+ MOD_nodes_update_interface(object, (NodesModifierData *)md);
+ }
+ }
+ }
+ }
+
+ if (params_) {
+ relations_.ensure_owner_ids();
+ ID *id = relations_.get_owner_id(ntree);
+ if (params_->tree_changed_fn) {
+ params_->tree_changed_fn(id, ntree, params_->user_data);
+ }
+ if (params_->tree_output_changed_fn && result.output_changed) {
+ params_->tree_output_changed_fn(id, ntree, params_->user_data);
+ }
+ }
+ }
+ }
+
+ private:
+ enum class ToposortMark {
+ None,
+ Temporary,
+ Permanent,
+ };
+
+ using ToposortMarkMap = Map<bNodeTree *, ToposortMark>;
+
+ /**
+ * Finds all trees that depend on the given trees (through node groups). Then those trees are
+ * ordered such that all trees used by one tree come before it.
+ */
+ Vector<bNodeTree *> get_tree_update_order(Span<bNodeTree *> root_ntrees)
+ {
+ relations_.ensure_group_node_users();
+
+ Set<bNodeTree *> trees_to_update = get_trees_to_update(root_ntrees);
+
+ Vector<bNodeTree *> sorted_ntrees;
+
+ ToposortMarkMap marks;
+ for (bNodeTree *ntree : trees_to_update) {
+ marks.add_new(ntree, ToposortMark::None);
+ }
+ for (bNodeTree *ntree : trees_to_update) {
+ if (marks.lookup(ntree) == ToposortMark::None) {
+ const bool cycle_detected = !this->get_tree_update_order__visit_recursive(
+ ntree, marks, sorted_ntrees);
+ /* This should be prevented by higher level operators. */
+ BLI_assert(!cycle_detected);
+ UNUSED_VARS_NDEBUG(cycle_detected);
+ }
+ }
+
+ std::reverse(sorted_ntrees.begin(), sorted_ntrees.end());
+
+ return sorted_ntrees;
+ }
+
+ bool get_tree_update_order__visit_recursive(bNodeTree *ntree,
+ ToposortMarkMap &marks,
+ Vector<bNodeTree *> &sorted_ntrees)
+ {
+ ToposortMark &mark = marks.lookup(ntree);
+ if (mark == ToposortMark::Permanent) {
+ return true;
+ }
+ if (mark == ToposortMark::Temporary) {
+ /* There is a dependency cycle. */
+ return false;
+ }
+
+ mark = ToposortMark::Temporary;
+
+ for (const TreeNodePair &pair : relations_.get_group_node_users(ntree)) {
+ this->get_tree_update_order__visit_recursive(pair.first, marks, sorted_ntrees);
+ }
+ sorted_ntrees.append(ntree);
+
+ mark = ToposortMark::Permanent;
+ return true;
+ }
+
+ Set<bNodeTree *> get_trees_to_update(Span<bNodeTree *> root_ntrees)
+ {
+ relations_.ensure_group_node_users();
+
+ Set<bNodeTree *> reachable_trees;
+ VectorSet<bNodeTree *> trees_to_check = root_ntrees;
+
+ while (!trees_to_check.is_empty()) {
+ bNodeTree *ntree = trees_to_check.pop();
+ if (reachable_trees.add(ntree)) {
+ for (const TreeNodePair &pair : relations_.get_group_node_users(ntree)) {
+ trees_to_check.add(pair.first);
+ }
+ }
+ }
+
+ return reachable_trees;
+ }
+
+ TreeUpdateResult update_tree(bNodeTree &ntree)
+ {
+ TreeUpdateResult result;
+
+ /* Use a #NodeTreeRef to speedup certain queries. It is rebuilt whenever the node tree topology
+ * changes, which typically happens zero or one times during the entire update of the node
+ * tree. */
+ std::unique_ptr<NodeTreeRef> tree_ref;
+ this->ensure_tree_ref(ntree, tree_ref);
+
+ this->update_socket_link_and_use(*tree_ref);
+ this->update_individual_nodes(ntree, tree_ref);
+ this->update_internal_links(ntree, tree_ref);
+ this->update_generic_callback(ntree, tree_ref);
+ this->remove_unused_previews_when_necessary(ntree);
+
+ this->ensure_tree_ref(ntree, tree_ref);
+ if (ntree.type == NTREE_GEOMETRY) {
+ if (node_field_inferencing::update_field_inferencing(*tree_ref)) {
+ result.interface_changed = true;
+ }
+ }
+
+ result.output_changed = this->check_if_output_changed(*tree_ref);
+
+ this->update_socket_link_and_use(*tree_ref);
+ this->update_node_levels(ntree);
+ this->update_link_validation(ntree);
+
+ if (ntree.type == NTREE_TEXTURE) {
+ ntreeTexCheckCyclics(&ntree);
+ }
+
+ if (ntree.changed_flag & NTREE_CHANGED_INTERFACE || ntree.changed_flag & NTREE_CHANGED_ANY) {
+ result.interface_changed = true;
+ }
+
+ if (result.interface_changed) {
+ ntreeInterfaceTypeUpdate(&ntree);
+ }
+
+ return result;
+ }
+
+ void ensure_tree_ref(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref)
+ {
+ if (!tree_ref) {
+ tree_ref = std::make_unique<NodeTreeRef>(&ntree);
+ }
+ }
+
+ void update_socket_link_and_use(const NodeTreeRef &tree)
+ {
+ for (const InputSocketRef *socket : tree.input_sockets()) {
+ bNodeSocket *bsocket = socket->bsocket();
+ if (socket->directly_linked_links().is_empty()) {
+ bsocket->link = nullptr;
+ }
+ else {
+ bsocket->link = socket->directly_linked_links()[0]->blink();
+ }
+ }
+
+ this->update_socket_used_tags(tree);
+ }
+
+ void update_socket_used_tags(const NodeTreeRef &tree)
+ {
+ for (const SocketRef *socket : tree.sockets()) {
+ bNodeSocket *bsocket = socket->bsocket();
+ bsocket->flag &= ~SOCK_IN_USE;
+ for (const LinkRef *link : socket->directly_linked_links()) {
+ if (!link->is_muted()) {
+ bsocket->flag |= SOCK_IN_USE;
+ break;
+ }
+ }
+ }
+ }
+
+ void update_individual_nodes(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref)
+ {
+ /* Iterate over nodes instead of #NodeTreeRef, because the #tree_ref might be outdated after
+ * some update functions. */
+ LISTBASE_FOREACH (bNode *, bnode, &ntree.nodes) {
+ this->ensure_tree_ref(ntree, tree_ref);
+ const NodeRef &node = *tree_ref->find_node(*bnode);
+ if (this->should_update_individual_node(node)) {
+ const uint32_t old_changed_flag = ntree.changed_flag;
+ ntree.changed_flag = NTREE_CHANGED_NOTHING;
+
+ /* This may set #ntree.changed_flag which is detected below. */
+ this->update_individual_node(node);
+
+ if (ntree.changed_flag != NTREE_CHANGED_NOTHING) {
+ /* The tree ref is outdated and needs to be rebuilt. Generally, only very few update
+ * functions change the node. Typically zero or one nodes change after an update. */
+ tree_ref.reset();
+ }
+ ntree.changed_flag |= old_changed_flag;
+ }
+ }
+ }
+
+ bool should_update_individual_node(const NodeRef &node)
+ {
+ bNodeTree &ntree = *node.btree();
+ bNode &bnode = *node.bnode();
+ if (ntree.changed_flag & NTREE_CHANGED_ANY) {
+ return true;
+ }
+ if (bnode.changed_flag & NTREE_CHANGED_NODE_PROPERTY) {
+ return true;
+ }
+ if (ntree.changed_flag & NTREE_CHANGED_LINK) {
+ /* Node groups currently always rebuilt their sockets when they are updated.
+ * So avoid calling the update method when no new link was added to it. */
+ if (node.is_group_input_node()) {
+ if (node.outputs().last()->is_directly_linked()) {
+ return true;
+ }
+ }
+ else if (node.is_group_output_node()) {
+ if (node.inputs().last()->is_directly_linked()) {
+ return true;
+ }
+ }
+ else {
+ /* Currently we have no way to tell if a node needs to be updated when a link changed. */
+ return true;
+ }
+ }
+ if (ntree.changed_flag & NTREE_CHANGED_INTERFACE) {
+ if (node.is_group_input_node() || node.is_group_output_node()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void update_individual_node(const NodeRef &node)
+ {
+ bNodeTree &ntree = *node.btree();
+ bNode &bnode = *node.bnode();
+ bNodeType &ntype = *bnode.typeinfo;
+ if (ntype.group_update_func) {
+ ntype.group_update_func(&ntree, &bnode);
+ }
+ if (ntype.updatefunc) {
+ ntype.updatefunc(&ntree, &bnode);
+ }
+ }
+
+ void update_internal_links(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref)
+ {
+ bool any_internal_links_updated = false;
+ this->ensure_tree_ref(ntree, tree_ref);
+ for (const NodeRef *node : tree_ref->nodes()) {
+ if (!this->should_update_individual_node(*node)) {
+ continue;
+ }
+ /* Find all expected internal links. */
+ Vector<std::pair<bNodeSocket *, bNodeSocket *>> expected_internal_links;
+ for (const OutputSocketRef *output_socket : node->outputs()) {
+ if (!output_socket->is_available()) {
+ continue;
+ }
+ if (!output_socket->is_directly_linked()) {
+ continue;
+ }
+ if (output_socket->bsocket()->flag & SOCK_NO_INTERNAL_LINK) {
+ continue;
+ }
+ const InputSocketRef *input_socket = this->find_internally_linked_input(output_socket);
+ if (input_socket != nullptr) {
+ expected_internal_links.append({input_socket->bsocket(), output_socket->bsocket()});
+ }
+ }
+ /* rebuilt internal links if they have changed. */
+ if (node->internal_links().size() != expected_internal_links.size()) {
+ this->update_internal_links_in_node(ntree, *node->bnode(), expected_internal_links);
+ any_internal_links_updated = true;
+ }
+ else {
+ for (auto &item : expected_internal_links) {
+ const bNodeSocket *from_socket = item.first;
+ const bNodeSocket *to_socket = item.second;
+ bool found = false;
+ for (const InternalLinkRef *internal_link : node->internal_links()) {
+ if (from_socket == internal_link->from().bsocket() &&
+ to_socket == internal_link->to().bsocket()) {
+ found = true;
+ }
+ }
+ if (!found) {
+ this->update_internal_links_in_node(ntree, *node->bnode(), expected_internal_links);
+ any_internal_links_updated = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (any_internal_links_updated) {
+ tree_ref.reset();
+ }
+ }
+
+ const InputSocketRef *find_internally_linked_input(const OutputSocketRef *output_socket)
+ {
+ const InputSocketRef *selected_socket = nullptr;
+ int selected_priority = -1;
+ bool selected_is_linked = false;
+ for (const InputSocketRef *input_socket : output_socket->node().inputs()) {
+ if (!input_socket->is_available()) {
+ continue;
+ }
+ if (input_socket->bsocket()->flag & SOCK_NO_INTERNAL_LINK) {
+ continue;
+ }
+ const int priority = get_internal_link_type_priority(input_socket->bsocket()->typeinfo,
+ output_socket->bsocket()->typeinfo);
+ if (priority < 0) {
+ continue;
+ }
+ const bool is_linked = input_socket->is_directly_linked();
+ const bool is_preferred = priority > selected_priority || (is_linked && !selected_is_linked);
+ if (!is_preferred) {
+ continue;
+ }
+ selected_socket = input_socket;
+ selected_priority = priority;
+ selected_is_linked = is_linked;
+ }
+ return selected_socket;
+ }
+
+ void update_internal_links_in_node(bNodeTree &ntree,
+ bNode &node,
+ Span<std::pair<bNodeSocket *, bNodeSocket *>> links)
+ {
+ BLI_freelistN(&node.internal_links);
+ for (const auto &item : links) {
+ bNodeSocket *from_socket = item.first;
+ bNodeSocket *to_socket = item.second;
+ bNodeLink *link = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), __func__);
+ link->fromnode = &node;
+ link->fromsock = from_socket;
+ link->tonode = &node;
+ link->tosock = to_socket;
+ link->flag |= NODE_LINK_VALID;
+ BLI_addtail(&node.internal_links, link);
+ }
+ BKE_ntree_update_tag_node_internal_link(&ntree, &node);
+ }
+
+ void update_generic_callback(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref)
+ {
+ if (ntree.typeinfo->update == nullptr) {
+ return;
+ }
+
+ /* Reset the changed_flag to allow detecting when the update callback changed the node tree. */
+ const uint32_t old_changed_flag = ntree.changed_flag;
+ ntree.changed_flag = NTREE_CHANGED_NOTHING;
+
+ ntree.typeinfo->update(&ntree);
+
+ if (ntree.changed_flag != NTREE_CHANGED_NOTHING) {
+ /* The tree ref is outdated and needs to be rebuilt. */
+ tree_ref.reset();
+ }
+ ntree.changed_flag |= old_changed_flag;
+ }
+
+ void remove_unused_previews_when_necessary(bNodeTree &ntree)
+ {
+ /* Don't trigger preview removal when only those flags are set. */
+ const uint32_t allowed_flags = NTREE_CHANGED_LINK | NTREE_CHANGED_SOCKET_PROPERTY |
+ NTREE_CHANGED_NODE_PROPERTY | NTREE_CHANGED_NODE_OUTPUT |
+ NTREE_CHANGED_INTERFACE;
+ if ((ntree.changed_flag & allowed_flags) == ntree.changed_flag) {
+ return;
+ }
+ BKE_node_preview_remove_unused(&ntree);
+ }
+
+ void update_node_levels(bNodeTree &ntree)
+ {
+ ntreeUpdateNodeLevels(&ntree);
+ }
+
+ void update_link_validation(bNodeTree &ntree)
+ {
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
+ link->flag |= NODE_LINK_VALID;
+ if (link->fromnode && link->tonode && link->fromnode->level <= link->tonode->level) {
+ link->flag &= ~NODE_LINK_VALID;
+ }
+ else if (ntree.typeinfo->validate_link) {
+ const eNodeSocketDatatype from_type = static_cast<eNodeSocketDatatype>(
+ link->fromsock->type);
+ const eNodeSocketDatatype to_type = static_cast<eNodeSocketDatatype>(link->tosock->type);
+ if (!ntree.typeinfo->validate_link(from_type, to_type)) {
+ link->flag &= ~NODE_LINK_VALID;
+ }
+ }
+ }
+ }
+
+ bool check_if_output_changed(const NodeTreeRef &tree)
+ {
+ bNodeTree &btree = *tree.btree();
+
+ /* Compute a hash that represents the node topology connected to the output. This always has to
+ * be updated even if it is not used to detect changes right now. Otherwise
+ * #btree.output_topology_hash will go out of date. */
+ const Vector<const SocketRef *> tree_output_sockets = this->find_output_sockets(tree);
+ const uint32_t old_topology_hash = btree.output_topology_hash;
+ const uint32_t new_topology_hash = this->get_combined_socket_topology_hash(
+ tree, tree_output_sockets);
+ btree.output_topology_hash = new_topology_hash;
+
+ if (const AnimData *adt = BKE_animdata_from_id(&btree.id)) {
+ /* Drivers may copy values in the node tree around arbitrarily and may cause the output to
+ * change even if it wouldn't without drivers. Only some special drivers like `frame/5` can
+ * be used without causing updates all the time currently. In the future we could try to
+ * handle other drivers better as well.
+ * Note that this optimization only works in practice when the depsgraph didn't also get a
+ * copy-on-write tag for the node tree (which happens when changing node properties). It does
+ * work in a few situations like adding reroutes and duplicating nodes though. */
+ LISTBASE_FOREACH (const FCurve *, fcurve, &adt->drivers) {
+ const ChannelDriver *driver = fcurve->driver;
+ const StringRef expression = driver->expression;
+ if (expression.startswith("frame")) {
+ const StringRef remaining_expression = expression.drop_known_prefix("frame");
+ if (remaining_expression.find_first_not_of(" */+-0123456789.") == StringRef::not_found) {
+ continue;
+ }
+ }
+ /* Unrecognized driver, assume that the output always changes. */
+ return true;
+ }
+ }
+
+ if (btree.changed_flag & NTREE_CHANGED_ANY) {
+ return true;
+ }
+
+ if (old_topology_hash != new_topology_hash) {
+ return true;
+ }
+
+ /* The topology hash can only be used when only topology-changing operations have been done. */
+ if (btree.changed_flag ==
+ (btree.changed_flag & (NTREE_CHANGED_LINK | NTREE_CHANGED_REMOVED_NODE))) {
+ if (old_topology_hash == new_topology_hash) {
+ return false;
+ }
+ }
+
+ if (!this->check_if_socket_outputs_changed_based_on_flags(tree, tree_output_sockets)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ Vector<const SocketRef *> find_output_sockets(const NodeTreeRef &tree)
+ {
+ Vector<const SocketRef *> sockets;
+ for (const NodeRef *node : tree.nodes()) {
+ const bNode *bnode = node->bnode();
+ if (bnode->typeinfo->nclass != NODE_CLASS_OUTPUT && bnode->type != NODE_GROUP_OUTPUT) {
+ continue;
+ }
+ for (const InputSocketRef *socket : node->inputs()) {
+ if (socket->idname() != "NodeSocketVirtual") {
+ sockets.append(socket);
+ }
+ }
+ }
+ return sockets;
+ }
+
+ /**
+ * Computes a hash that changes when the node tree topology connected to an output node changes.
+ * Adding reroutes does not have an effect on the hash.
+ */
+ uint32_t get_combined_socket_topology_hash(const NodeTreeRef &tree,
+ Span<const SocketRef *> sockets)
+ {
+ Array<uint32_t> hashes = this->get_socket_topology_hashes(tree, sockets);
+ uint32_t combined_hash = 0;
+ for (uint32_t hash : hashes) {
+ combined_hash = noise::hash(combined_hash, hash);
+ }
+ return combined_hash;
+ }
+
+ Array<uint32_t> get_socket_topology_hashes(const NodeTreeRef &tree,
+ Span<const SocketRef *> sockets)
+ {
+ Array<std::optional<uint32_t>> hash_by_socket_id(tree.sockets().size());
+ Stack<const SocketRef *> sockets_to_check = sockets;
+
+ while (!sockets_to_check.is_empty()) {
+ const SocketRef &in_out_socket = *sockets_to_check.peek();
+ const NodeRef &node = in_out_socket.node();
+
+ if (hash_by_socket_id[in_out_socket.id()].has_value()) {
+ sockets_to_check.pop();
+ /* Socket is handled already. */
+ continue;
+ }
+
+ if (in_out_socket.is_input()) {
+ /* For input sockets, first compute the hashes of all linked sockets. */
+ const InputSocketRef &socket = in_out_socket.as_input();
+ bool all_origins_computed = true;
+ for (const OutputSocketRef *origin_socket : socket.logically_linked_sockets()) {
+ if (!hash_by_socket_id[origin_socket->id()].has_value()) {
+ sockets_to_check.push(origin_socket);
+ all_origins_computed = false;
+ }
+ }
+ if (!all_origins_computed) {
+ continue;
+ }
+ /* When the hashes for the linked sockets are ready, combine them into a hash for the input
+ * socket. */
+ const uint64_t socket_ptr = (uintptr_t)socket.bsocket();
+ uint32_t socket_hash = noise::hash(socket_ptr, socket_ptr >> 32);
+ for (const OutputSocketRef *origin_socket : socket.logically_linked_sockets()) {
+ const uint32_t origin_socket_hash = *hash_by_socket_id[origin_socket->id()];
+ socket_hash = noise::hash(socket_hash, origin_socket_hash);
+ }
+ hash_by_socket_id[socket.id()] = socket_hash;
+ sockets_to_check.pop();
+ }
+ else {
+ /* For output sockets, first compute the hashes of all available input sockets. */
+ const OutputSocketRef &socket = in_out_socket.as_output();
+ bool all_available_inputs_computed = true;
+ for (const InputSocketRef *input_socket : node.inputs()) {
+ if (input_socket->is_available()) {
+ if (!hash_by_socket_id[input_socket->id()].has_value()) {
+ sockets_to_check.push(input_socket);
+ all_available_inputs_computed = false;
+ }
+ }
+ }
+ if (!all_available_inputs_computed) {
+ continue;
+ }
+ /* When all input socket hashes have been computed, combine them into a hash for the output
+ * socket. */
+ const uint64_t socket_ptr = (uintptr_t)socket.bsocket();
+ uint32_t socket_hash = noise::hash(socket_ptr, socket_ptr >> 32);
+ for (const InputSocketRef *input_socket : node.inputs()) {
+ if (input_socket->is_available()) {
+ const uint32_t input_socket_hash = *hash_by_socket_id[input_socket->id()];
+ socket_hash = noise::hash(socket_hash, input_socket_hash);
+ }
+ }
+ hash_by_socket_id[socket.id()] = socket_hash;
+ sockets_to_check.pop();
+ }
+ }
+
+ /* Create output array. */
+ Array<uint32_t> hashes(sockets.size());
+ for (const int i : sockets.index_range()) {
+ hashes[i] = *hash_by_socket_id[sockets[i]->id()];
+ }
+ return hashes;
+ }
+
+ /**
+ * Returns true when any of the provided sockets changed its values. A change is detected by
+ * checking the #changed_flag on connected sockets and nodes.
+ */
+ bool check_if_socket_outputs_changed_based_on_flags(const NodeTreeRef &tree,
+ Span<const SocketRef *> sockets)
+ {
+ /* Avoid visiting the same socket twice when multiple links point to the same socket. */
+ Array<bool> pushed_by_socket_id(tree.sockets().size(), false);
+ Stack<const SocketRef *> sockets_to_check = sockets;
+
+ for (const SocketRef *socket : sockets) {
+ pushed_by_socket_id[socket->id()] = true;
+ }
+
+ while (!sockets_to_check.is_empty()) {
+ const SocketRef &in_out_socket = *sockets_to_check.pop();
+ const bNode &bnode = *in_out_socket.node().bnode();
+ const bNodeSocket &bsocket = *in_out_socket.bsocket();
+ if (bsocket.changed_flag != NTREE_CHANGED_NOTHING) {
+ return true;
+ }
+ if (bnode.changed_flag != NTREE_CHANGED_NOTHING) {
+ const bool only_unused_internal_link_changed = (bnode.flag & NODE_MUTED) == 0 &&
+ bnode.changed_flag ==
+ NTREE_CHANGED_INTERNAL_LINK;
+ if (!only_unused_internal_link_changed) {
+ return true;
+ }
+ }
+ if (in_out_socket.is_input()) {
+ const InputSocketRef &socket = in_out_socket.as_input();
+ for (const OutputSocketRef *origin_socket : socket.logically_linked_sockets()) {
+ bool &pushed = pushed_by_socket_id[origin_socket->id()];
+ if (!pushed) {
+ sockets_to_check.push(origin_socket);
+ pushed = true;
+ }
+ }
+ }
+ else {
+ const OutputSocketRef &socket = in_out_socket.as_output();
+ for (const InputSocketRef *input_socket : socket.node().inputs()) {
+ if (input_socket->is_available()) {
+ bool &pushed = pushed_by_socket_id[input_socket->id()];
+ if (!pushed) {
+ sockets_to_check.push(input_socket);
+ pushed = true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ void reset_changed_flags(bNodeTree &ntree)
+ {
+ ntree.changed_flag = NTREE_CHANGED_NOTHING;
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
+ node->changed_flag = NTREE_CHANGED_NOTHING;
+ node->update = 0;
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ socket->changed_flag = NTREE_CHANGED_NOTHING;
+ }
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
+ socket->changed_flag = NTREE_CHANGED_NOTHING;
+ }
+ }
+ }
+};
+
+} // namespace blender::bke
+
+void BKE_ntree_update_tag_all(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_ANY);
+}
+
+void BKE_ntree_update_tag_node_property(bNodeTree *ntree, bNode *node)
+{
+ add_node_tag(ntree, node, NTREE_CHANGED_NODE_PROPERTY);
+}
+
+void BKE_ntree_update_tag_node_new(bNodeTree *ntree, bNode *node)
+{
+ add_node_tag(ntree, node, NTREE_CHANGED_NODE_PROPERTY);
+}
+
+void BKE_ntree_update_tag_socket_property(bNodeTree *ntree, bNodeSocket *socket)
+{
+ add_socket_tag(ntree, socket, NTREE_CHANGED_SOCKET_PROPERTY);
+}
+
+void BKE_ntree_update_tag_socket_new(bNodeTree *ntree, bNodeSocket *socket)
+{
+ add_socket_tag(ntree, socket, NTREE_CHANGED_SOCKET_PROPERTY);
+}
+
+void BKE_ntree_update_tag_socket_removed(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_REMOVED_SOCKET);
+}
+
+void BKE_ntree_update_tag_socket_type(bNodeTree *ntree, bNodeSocket *socket)
+{
+ add_socket_tag(ntree, socket, NTREE_CHANGED_SOCKET_PROPERTY);
+}
+
+void BKE_ntree_update_tag_socket_availability(bNodeTree *ntree, bNodeSocket *socket)
+{
+ add_socket_tag(ntree, socket, NTREE_CHANGED_SOCKET_PROPERTY);
+}
+
+void BKE_ntree_update_tag_node_removed(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_REMOVED_NODE);
+}
+
+void BKE_ntree_update_tag_node_internal_link(bNodeTree *ntree, bNode *node)
+{
+ add_node_tag(ntree, node, NTREE_CHANGED_INTERNAL_LINK);
+}
+
+void BKE_ntree_update_tag_link_changed(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_LINK);
+}
+
+void BKE_ntree_update_tag_link_removed(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_LINK);
+}
+
+void BKE_ntree_update_tag_link_added(bNodeTree *ntree, bNodeLink *UNUSED(link))
+{
+ add_tree_tag(ntree, NTREE_CHANGED_LINK);
+}
+
+void BKE_ntree_update_tag_link_mute(bNodeTree *ntree, bNodeLink *UNUSED(link))
+{
+ add_tree_tag(ntree, NTREE_CHANGED_LINK);
+}
+
+void BKE_ntree_update_tag_missing_runtime_data(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_ALL);
+}
+
+void BKE_ntree_update_tag_interface(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_INTERFACE);
+}
+
+void BKE_ntree_update_tag_id_changed(Main *bmain, ID *id)
+{
+ FOREACH_NODETREE_BEGIN (bmain, ntree, ntree_id) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->id == id) {
+ node->update |= NODE_UPDATE_ID;
+ add_node_tag(ntree, node, NTREE_CHANGED_NODE_PROPERTY);
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
+}
+
+/**
+ * Protect from recursive calls into the updating function. Some node update functions might
+ * trigger this from Python or in other cases.
+ *
+ * This could be added to #Main, but given that there is generally only one #Main, that's not
+ * really worth it now.
+ */
+static bool is_updating = false;
+
+void BKE_ntree_update_main(Main *bmain, NodeTreeUpdateExtraParams *params)
+{
+ if (is_updating) {
+ return;
+ }
+
+ is_updating = true;
+ blender::bke::NodeTreeMainUpdater updater{bmain, params};
+ updater.update();
+ is_updating = false;
+}
+
+void BKE_ntree_update_main_tree(Main *bmain, bNodeTree *ntree, NodeTreeUpdateExtraParams *params)
+{
+ if (ntree == nullptr) {
+ BKE_ntree_update_main(bmain, params);
+ return;
+ }
+
+ if (is_updating) {
+ return;
+ }
+
+ is_updating = true;
+ blender::bke::NodeTreeMainUpdater updater{bmain, params};
+ updater.update_rooted({ntree});
+ is_updating = false;
+}
diff --git a/source/blender/blenkernel/intern/spline_nurbs.cc b/source/blender/blenkernel/intern/spline_nurbs.cc
index 69afb82baa8..e9d4ba7c7ef 100644
--- a/source/blender/blenkernel/intern/spline_nurbs.cc
+++ b/source/blender/blenkernel/intern/spline_nurbs.cc
@@ -257,13 +257,13 @@ void NURBSpline::calculate_knots() const
Span<float> NURBSpline::knots() const
{
if (!knots_dirty_) {
- BLI_assert(knots_.size() == this->size() + order_);
+ BLI_assert(knots_.size() == this->knots_size());
return knots_;
}
std::lock_guard lock{knots_mutex_};
if (!knots_dirty_) {
- BLI_assert(knots_.size() == this->size() + order_);
+ BLI_assert(knots_.size() == this->knots_size());
return knots_;
}
diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc
index 130aa957491..63807f90334 100644
--- a/source/blender/blenkernel/intern/volume.cc
+++ b/source/blender/blenkernel/intern/volume.cc
@@ -537,7 +537,7 @@ static void volume_copy_data(Main *UNUSED(bmain),
#ifdef WITH_OPENVDB
if (volume_src->runtime.grids) {
const VolumeGridVector &grids_src = *(volume_src->runtime.grids);
- volume_dst->runtime.grids = OBJECT_GUARDED_NEW(VolumeGridVector, grids_src);
+ volume_dst->runtime.grids = MEM_new<VolumeGridVector>(__func__, grids_src);
}
#endif
@@ -551,7 +551,8 @@ static void volume_free_data(ID *id)
BKE_volume_batch_cache_free(volume);
MEM_SAFE_FREE(volume->mat);
#ifdef WITH_OPENVDB
- OBJECT_GUARDED_SAFE_DELETE(volume->runtime.grids, VolumeGridVector);
+ MEM_delete(volume->runtime.grids);
+ volume->runtime.grids = nullptr;
#endif
}
@@ -683,7 +684,7 @@ void BKE_volume_init_grids(Volume *volume)
{
#ifdef WITH_OPENVDB
if (volume->runtime.grids == nullptr) {
- volume->runtime.grids = OBJECT_GUARDED_NEW(VolumeGridVector);
+ volume->runtime.grids = MEM_new<VolumeGridVector>(__func__);
}
#else
UNUSED_VARS(volume);
@@ -1129,16 +1130,16 @@ void BKE_volume_grids_backup_restore(Volume *volume, VolumeGridVector *grids, co
if (!grids->is_loaded()) {
/* No grids loaded in CoW datablock, nothing lost by discarding. */
- OBJECT_GUARDED_DELETE(grids, VolumeGridVector);
+ MEM_delete(grids);
}
else if (!STREQ(volume->filepath, filepath)) {
/* Filepath changed, discard grids from CoW datablock. */
- OBJECT_GUARDED_DELETE(grids, VolumeGridVector);
+ MEM_delete(grids);
}
else {
/* Keep grids from CoW datablock. We might still unload them a little
* later in BKE_volume_eval_geometry if the frame changes. */
- OBJECT_GUARDED_DELETE(volume->runtime.grids, VolumeGridVector);
+ MEM_delete(volume->runtime.grids);
volume->runtime.grids = grids;
}
#else
diff --git a/source/blender/blenlib/BLI_assert.h b/source/blender/blenlib/BLI_assert.h
index 6019f0f3566..e32a19cfc25 100644
--- a/source/blender/blenlib/BLI_assert.h
+++ b/source/blender/blenlib/BLI_assert.h
@@ -30,6 +30,7 @@ extern "C" {
#endif
/* Utility functions. */
+
void _BLI_assert_print_pos(const char *file, const int line, const char *function, const char *id);
void _BLI_assert_print_extra(const char *str);
void _BLI_assert_print_backtrace(void);
diff --git a/source/blender/blenlib/BLI_color.hh b/source/blender/blenlib/BLI_color.hh
index d93bd7f6f76..dce625777b9 100644
--- a/source/blender/blenlib/BLI_color.hh
+++ b/source/blender/blenlib/BLI_color.hh
@@ -73,27 +73,27 @@ namespace blender {
* - Add non RGB spaces/storages ColorXyz.
*/
-/* Enumeration containing the different alpha modes. */
+/** Enumeration containing the different alpha modes. */
enum class eAlpha {
- /* Color and alpha are unassociated. */
+ /** Color and alpha are unassociated. */
Straight,
- /* Color and alpha are associated. */
+ /** Color and alpha are associated. */
Premultiplied,
};
std::ostream &operator<<(std::ostream &stream, const eAlpha &space);
-/* Enumeration containing internal spaces. */
+/** Enumeration containing internal spaces. */
enum class eSpace {
- /* Blender theme color space (sRGB). */
+ /** Blender theme color space (sRGB). */
Theme,
- /* Blender internal scene linear color space (maps to SceneReference role in OCIO). */
+ /** Blender internal scene linear color space (maps to SceneReference role in OCIO). */
SceneLinear,
- /* Blender internal scene linear color space compressed to be stored in 4 uint8_t. */
+ /** Blender internal scene linear color space compressed to be stored in 4 uint8_t. */
SceneLinearByteEncoded,
};
std::ostream &operator<<(std::ostream &stream, const eSpace &space);
-/* Template class to store RGBA values with different precision, space and alpha association. */
+/** Template class to store RGBA values with different precision, space and alpha association. */
template<typename ChannelStorageType, eSpace Space, eAlpha Alpha> class ColorRGBA {
public:
ChannelStorageType r, g, b, a;
@@ -153,11 +153,13 @@ template<typename ChannelStorageType, eSpace Space, eAlpha Alpha> class ColorRGB
};
/* Forward declarations of concrete color classes. */
+
template<eAlpha Alpha> class ColorSceneLinear4f;
template<eAlpha Alpha> class ColorSceneLinearByteEncoded4b;
template<typename ChannelStorageType> class ColorTheme4;
/* Forward declaration of precision conversion methods. */
+
BLI_INLINE ColorTheme4<float> BLI_color_convert_to_theme4f(const ColorTheme4<uint8_t> &srgb4b);
BLI_INLINE ColorTheme4<uint8_t> BLI_color_convert_to_theme4b(const ColorTheme4<float> &srgb4f);
@@ -354,6 +356,7 @@ BLI_color_convert_to_theme4b(const ColorSceneLinear4f<eAlpha::Straight> &scene_l
}
/* Internal roles. For convenience to shorten the type names and hide complexity. */
+
using ColorGeometry4f = ColorSceneLinear4f<eAlpha::Premultiplied>;
using ColorGeometry4b = ColorSceneLinearByteEncoded4b<eAlpha::Premultiplied>;
diff --git a/source/blender/blenlib/BLI_compiler_compat.h b/source/blender/blenlib/BLI_compiler_compat.h
index bd8f84cedd6..023fea3853e 100644
--- a/source/blender/blenlib/BLI_compiler_compat.h
+++ b/source/blender/blenlib/BLI_compiler_compat.h
@@ -34,7 +34,7 @@
#if (defined(__GNUC__) || defined(__clang__)) && defined(__cplusplus)
extern "C++" {
-/* Some magic to be sure we don't have reference in the type. */
+/** Some magic to be sure we don't have reference in the type. */
template<typename T> static inline T decltype_helper(T x)
{
return x;
diff --git a/source/blender/blenlib/BLI_delaunay_2d.h b/source/blender/blenlib/BLI_delaunay_2d.h
index 658dcadadce..db0df95499f 100644
--- a/source/blender/blenlib/BLI_delaunay_2d.h
+++ b/source/blender/blenlib/BLI_delaunay_2d.h
@@ -222,7 +222,7 @@ void BLI_delaunay_2d_cdt_free(CDT_result *result);
namespace blender::meshintersect {
-/* vec2<Arith_t> is a 2d vector with Arith_t as the type for coordinates. */
+/** #vec2<Arith_t> is a 2d vector with #Arith_t as the type for coordinates. */
template<typename Arith_t> struct vec2_impl;
template<> struct vec2_impl<double> {
typedef double2 type;
diff --git a/source/blender/blenlib/BLI_dlrbTree.h b/source/blender/blenlib/BLI_dlrbTree.h
index 72f18244d5b..3cf849efaef 100644
--- a/source/blender/blenlib/BLI_dlrbTree.h
+++ b/source/blender/blenlib/BLI_dlrbTree.h
@@ -40,7 +40,7 @@ extern "C" {
/** \name Base Structs
* \{ */
-/* Basic Layout for a Node */
+/** Basic Layout for a Node. */
typedef struct DLRBT_Node {
/* ListBase capabilities */
struct DLRBT_Node *next, *prev;
@@ -53,7 +53,7 @@ typedef struct DLRBT_Node {
/* ... for nice alignment, next item should usually be a char too... */
} DLRBT_Node;
-/* Red/Black defines for tree_col */
+/** Red/Black defines for tree_col. */
typedef enum eDLRBT_Colors {
DLRBT_BLACK = 0,
DLRBT_RED,
@@ -61,7 +61,7 @@ typedef enum eDLRBT_Colors {
/* -------- */
-/* The Tree Data */
+/** The Tree Data. */
typedef struct DLRBT_Tree {
/* ListBase capabilities */
void *first, *last; /* these should be based on DLRBT_Node-s */
diff --git a/source/blender/blenlib/BLI_endian_switch.h b/source/blender/blenlib/BLI_endian_switch.h
index b512133b34c..e6ccbe4629a 100644
--- a/source/blender/blenlib/BLI_endian_switch.h
+++ b/source/blender/blenlib/BLI_endian_switch.h
@@ -30,6 +30,7 @@ extern "C" {
#endif
/* BLI_endian_switch_inline.h */
+
BLI_INLINE void BLI_endian_switch_int16(short *val) ATTR_NONNULL(1);
BLI_INLINE void BLI_endian_switch_uint16(unsigned short *val) ATTR_NONNULL(1);
BLI_INLINE void BLI_endian_switch_int32(int *val) ATTR_NONNULL(1);
@@ -40,6 +41,7 @@ BLI_INLINE void BLI_endian_switch_uint64(uint64_t *val) ATTR_NONNULL(1);
BLI_INLINE void BLI_endian_switch_double(double *val) ATTR_NONNULL(1);
/* endian_switch.c */
+
void BLI_endian_switch_int16_array(short *val, const int size) ATTR_NONNULL(1);
void BLI_endian_switch_uint16_array(unsigned short *val, const int size) ATTR_NONNULL(1);
void BLI_endian_switch_int32_array(int *val, const int size) ATTR_NONNULL(1);
diff --git a/source/blender/blenlib/BLI_endian_switch_inline.h b/source/blender/blenlib/BLI_endian_switch_inline.h
index ec4cfe4801a..31be7fd47e4 100644
--- a/source/blender/blenlib/BLI_endian_switch_inline.h
+++ b/source/blender/blenlib/BLI_endian_switch_inline.h
@@ -33,6 +33,7 @@ extern "C" {
* use bit shifting instead. */
/* *** 16 *** */
+
BLI_INLINE void BLI_endian_switch_int16(short *val)
{
BLI_endian_switch_uint16((unsigned short *)val);
@@ -48,6 +49,7 @@ BLI_INLINE void BLI_endian_switch_uint16(unsigned short *val)
}
/* *** 32 *** */
+
BLI_INLINE void BLI_endian_switch_int32(int *val)
{
BLI_endian_switch_uint32((unsigned int *)val);
@@ -67,6 +69,7 @@ BLI_INLINE void BLI_endian_switch_float(float *val)
}
/* *** 64 *** */
+
BLI_INLINE void BLI_endian_switch_int64(int64_t *val)
{
BLI_endian_switch_uint64((uint64_t *)val);
diff --git a/source/blender/blenlib/BLI_fileops.hh b/source/blender/blenlib/BLI_fileops.hh
new file mode 100644
index 00000000000..c69b1983c59
--- /dev/null
+++ b/source/blender/blenlib/BLI_fileops.hh
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup bli
+ * \brief File and directory operations.
+ */
+
+#pragma once
+
+#ifndef __cplusplus
+# error This is a C++ header
+#endif
+
+#include "BLI_fileops.h"
+#include "BLI_string_ref.hh"
+
+#include <fstream>
+#include <string>
+
+namespace blender {
+
+/**
+ * std::fstream subclass that handles UTF-16 encoding on Windows.
+ *
+ * For documentation, see https://en.cppreference.com/w/cpp/io/basic_fstream
+ */
+class fstream : public std::fstream {
+ public:
+ fstream() = default;
+ explicit fstream(const char *filepath,
+ std::ios_base::openmode mode = ios_base::in | ios_base::out);
+ explicit fstream(const std::string &filepath,
+ std::ios_base::openmode mode = ios_base::in | ios_base::out);
+
+ void open(StringRefNull filepath, ios_base::openmode mode = ios_base::in | ios_base::out);
+};
+
+} // namespace blender
diff --git a/source/blender/blenlib/BLI_filereader.h b/source/blender/blenlib/BLI_filereader.h
index da223cddf40..f232ad72cc4 100644
--- a/source/blender/blenlib/BLI_filereader.h
+++ b/source/blender/blenlib/BLI_filereader.h
@@ -47,7 +47,7 @@ typedef ssize_t (*FileReaderReadFn)(struct FileReader *reader, void *buffer, siz
typedef off64_t (*FileReaderSeekFn)(struct FileReader *reader, off64_t offset, int whence);
typedef void (*FileReaderCloseFn)(struct FileReader *reader);
-/* General structure for all FileReaders, implementations add custom fields at the end. */
+/** General structure for all #FileReaders, implementations add custom fields at the end. */
typedef struct FileReader {
FileReaderReadFn read;
FileReaderSeekFn seek;
@@ -64,16 +64,16 @@ typedef struct FileReader {
* take over the base FileReader and will clean it up when their clean() is called.
*/
-/* Create FileReader from raw file descriptor. */
+/** Create #FileReader from raw file descriptor. */
FileReader *BLI_filereader_new_file(int filedes) ATTR_WARN_UNUSED_RESULT;
-/* Create FileReader from raw file descriptor using memory-mapped IO. */
+/** Create #FileReader from raw file descriptor using memory-mapped IO. */
FileReader *BLI_filereader_new_mmap(int filedes) ATTR_WARN_UNUSED_RESULT;
-/* Create FileReader from a region of memory. */
+/** Create #FileReader from a region of memory. */
FileReader *BLI_filereader_new_memory(const void *data, size_t len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
-/* Create FileReader from applying `Zstd` decompression on an underlying file. */
+/** Create #FileReader from applying `Zstd` decompression on an underlying file. */
FileReader *BLI_filereader_new_zstd(FileReader *base) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-/* Create FileReader from applying `Gzip` decompression on an underlying file. */
+/** Create #FileReader from applying `Gzip` decompression on an underlying file. */
FileReader *BLI_filereader_new_gzip(FileReader *base) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h
index 0194f9aad40..fca705535a3 100644
--- a/source/blender/blenlib/BLI_ghash.h
+++ b/source/blender/blenlib/BLI_ghash.h
@@ -450,7 +450,7 @@ void *BLI_gset_pop_key(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT;
/* rely on inline api for now */
-/* so we can cast but compiler sees as different */
+/** Use a GSet specific type so we can cast but compiler sees as different */
typedef struct GSetIterator {
GHashIterator _ghi
#if defined(__GNUC__) && !defined(__clang__)
diff --git a/source/blender/blenlib/BLI_kdtree_impl.h b/source/blender/blenlib/BLI_kdtree_impl.h
index 26a22fc2ac4..35dbf141c92 100644
--- a/source/blender/blenlib/BLI_kdtree_impl.h
+++ b/source/blender/blenlib/BLI_kdtree_impl.h
@@ -74,7 +74,7 @@ int BLI_kdtree_nd_(calc_duplicates_fast)(const KDTree *tree,
int BLI_kdtree_nd_(deduplicate)(KDTree *tree);
-/* Versions of find/range search that take a squared distance callback to support bias. */
+/** Versions of find/range search that take a squared distance callback to support bias. */
int BLI_kdtree_nd_(find_nearest_n_with_len_squared_cb)(
const KDTree *tree,
const float co[KD_DIMS],
diff --git a/source/blender/blenlib/BLI_linklist_lockfree.h b/source/blender/blenlib/BLI_linklist_lockfree.h
index 142fa1cf243..d2083bdd44e 100644
--- a/source/blender/blenlib/BLI_linklist_lockfree.h
+++ b/source/blender/blenlib/BLI_linklist_lockfree.h
@@ -48,18 +48,19 @@ typedef void (*LockfreeeLinkNodeFreeFP)(void *link);
/* NOTE: These functions are NOT safe for use from threads. */
/* NOTE: !!! I REPEAT: DO NOT USE THEM WITHOUT EXTERNAL LOCK !!! */
-/* Make list ready for lock-free access. */
+/** Make list ready for lock-free access. */
void BLI_linklist_lockfree_init(LockfreeLinkList *list);
-/* Completely free the whole list, it is NOT re-usable after this. */
+/** Completely free the whole list, it is NOT re-usable after this. */
void BLI_linklist_lockfree_free(LockfreeLinkList *list, LockfreeeLinkNodeFreeFP free_func);
-/* Remove all the elements from the list, keep it usable for further
- * inserts.
+/**
+ * Remove all the elements from the list, keep it usable for further inserts.
*/
void BLI_linklist_lockfree_clear(LockfreeLinkList *list, LockfreeeLinkNodeFreeFP free_func);
-/* Begin iteration of lock-free linked list, starting with a
+/**
+ * Begin iteration of lock-free linked list, starting with a
* first user=defined node. Will ignore the dummy node.
*/
LockfreeLinkNode *BLI_linklist_lockfree_begin(LockfreeLinkList *list);
diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h
index 7d808d339e9..a2a6e958213 100644
--- a/source/blender/blenlib/BLI_listbase.h
+++ b/source/blender/blenlib/BLI_listbase.h
@@ -46,6 +46,11 @@ int BLI_findstringindex(const struct ListBase *listbase,
const char *id,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Return a ListBase representing the entire list the given Link is in.
+ */
+ListBase BLI_listbase_from_link(struct Link *some_link);
+
/* Find forwards. */
/**
@@ -279,6 +284,23 @@ BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
}
/**
+ * Equality check for ListBase.
+ *
+ * This only shallowly compares the ListBase itself (so the first/last
+ * pointers), and does not do any equality checks on the list items.
+ */
+BLI_INLINE bool BLI_listbase_equal(const struct ListBase *a, const struct ListBase *b)
+{
+ if (a == NULL) {
+ return b == NULL;
+ }
+ if (b == NULL) {
+ return false;
+ }
+ return a->first == b->first && a->last == b->last;
+}
+
+/**
* Create a generic list node containing link to provided data.
*/
struct LinkData *BLI_genericNodeN(void *data);
@@ -353,3 +375,10 @@ struct LinkData *BLI_genericNodeN(void *data);
#ifdef __cplusplus
}
#endif
+
+#ifdef __cplusplus
+BLI_INLINE bool operator==(const ListBase &a, const ListBase &b)
+{
+ return BLI_listbase_equal(&a, &b);
+}
+#endif
diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index 83822481112..6c82bd89e64 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -76,8 +76,7 @@
#if defined(__GNUC__)
# define NAN_FLT __builtin_nanf("")
-#else
-/* evil quiet NaN definition */
+#else /* evil quiet NaN definition */
static const int NAN_INT = 0x7FC00000;
# define NAN_FLT (*((float *)(&NAN_INT)))
#endif
@@ -97,7 +96,8 @@ extern "C" {
/******************************* Float ******************************/
-/* powf is really slow for raising to integer powers. */
+/* `powf` is really slow for raising to integer powers. */
+
MINLINE float pow2f(float x);
MINLINE float pow3f(float x);
MINLINE float pow4f(float x);
diff --git a/source/blender/blenlib/BLI_math_bits.h b/source/blender/blenlib/BLI_math_bits.h
index e881f1a0e4e..70a54879446 100644
--- a/source/blender/blenlib/BLI_math_bits.h
+++ b/source/blender/blenlib/BLI_math_bits.h
@@ -28,24 +28,29 @@ extern "C" {
#endif
/* Search the value from LSB to MSB for a set bit. Returns index of this bit. */
+
MINLINE int bitscan_forward_i(int a);
MINLINE unsigned int bitscan_forward_uint(unsigned int a);
MINLINE unsigned int bitscan_forward_uint64(unsigned long long a);
/* Similar to above, but also clears the bit. */
+
MINLINE int bitscan_forward_clear_i(int *a);
MINLINE unsigned int bitscan_forward_clear_uint(unsigned int *a);
/* Search the value from MSB to LSB for a set bit. Returns index of this bit. */
+
MINLINE int bitscan_reverse_i(int a);
MINLINE unsigned int bitscan_reverse_uint(unsigned int a);
MINLINE unsigned int bitscan_reverse_uint64(unsigned long long a);
/* Similar to above, but also clears the bit. */
+
MINLINE int bitscan_reverse_clear_i(int *a);
MINLINE unsigned int bitscan_reverse_clear_uint(unsigned int *a);
/* NOTE: Those functions returns 2 to the power of index of highest order bit. */
+
MINLINE unsigned int highest_order_bit_uint(unsigned int n);
MINLINE unsigned short highest_order_bit_s(unsigned short n);
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index 55d118d17de..c2a5ffafa64 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -441,7 +441,9 @@ void isect_seg_seg_v3(const float a0[3],
float r_a[3],
float r_b[3]);
-/* intersect Line-Line, shorts */
+/**
+ * Intersect Line-Line, integer.
+ */
int isect_seg_seg_v2_int(const int v1[2], const int v2[2], const int v3[2], const int v4[2]);
/**
* Get intersection point of two 2D segments.
@@ -929,7 +931,7 @@ void interp_weights_quad_v3(float w[4],
void interp_weights_poly_v3(float w[], float v[][3], const int n, const float co[3]);
void interp_weights_poly_v2(float w[], float v[][2], const int n, const float co[2]);
-/* (x1, v1)(t1=0)------(x2, v2)(t2=1), 0<t<1 --> (x, v)(t) */
+/** `(x1, v1)(t1=0)------(x2, v2)(t2=1), 0<t<1 --> (x, v)(t)`. */
void interp_cubic_v3(float x[3],
float v[3],
const float x1[3],
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index 3d8fe6f564a..90b74e2f504 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -56,16 +56,18 @@ void copy_m4_m2(float m1[4][4], const float m2[2][2]);
void copy_m4_m4_db(double m1[4][4], const double m2[4][4]);
/* double->float */
+
void copy_m3_m3d(float m1[3][3], const double m2[3][3]);
/* float->double */
+
void copy_m3d_m3(double m1[3][3], const float m2[3][3]);
void copy_m4d_m4(double m1[4][4], const float m2[4][4]);
void swap_m3m3(float m1[3][3], float m2[3][3]);
void swap_m4m4(float m1[4][4], float m2[4][4]);
-/* Build index shuffle matrix */
+/** Build index shuffle matrix. */
void shuffle_m4(float R[4][4], const int index[4]);
/** \} */
@@ -112,7 +114,8 @@ void mul_m4db_m4db_m4fl_uniq(double R[4][4], const double A[4][4], const float B
void mul_m4_m4_pre(float R[4][4], const float A[4][4]);
void mul_m4_m4_post(float R[4][4], const float B[4][4]);
-/* mul_m3_series */
+/* Implement #mul_m3_series macro. */
+
void _va_mul_m3_series_3(float R[3][3], const float M1[3][3], const float M2[3][3]) ATTR_NONNULL();
void _va_mul_m3_series_4(float R[3][3],
const float M1[3][3],
@@ -153,7 +156,9 @@ void _va_mul_m3_series_9(float R[3][3],
const float M6[3][3],
const float M7[3][3],
const float M8[3][3]) ATTR_NONNULL();
-/* mul_m4_series */
+
+/* Implement #mul_m4_series macro. */
+
void _va_mul_m4_series_3(float R[4][4], const float M1[4][4], const float M2[4][4]) ATTR_NONNULL();
void _va_mul_m4_series_4(float R[4][4],
const float M1[4][4],
@@ -266,11 +271,13 @@ bool invert_m4_m4(float R[4][4], const float A[4][4]);
*/
bool invert_m4_m4_fallback(float R[4][4], const float A[4][4]);
-/* double arithmetic (mixed float/double) */
+/* Double arithmetic (mixed float/double). */
+
void mul_m4_v4d(const float M[4][4], double r[4]);
void mul_v4d_m4v4d(double r[4], const float M[4][4], const double v[4]);
-/* double matrix functions (no mixing types) */
+/* Double matrix functions (no mixing types). */
+
void mul_v3_m3v3_db(double r[3], const double M[3][3], const double a[3]);
void mul_m3_v3_db(const double M[3][3], double r[3]);
@@ -282,7 +289,9 @@ void mul_m3_v3_db(const double M[3][3], double r[3]);
void transpose_m3(float R[3][3]);
void transpose_m3_m3(float R[3][3], const float M[3][3]);
-/* seems obscure but in-fact a common operation */
+/**
+ * \note Seems obscure but in-fact a common operation.
+ */
void transpose_m3_m4(float R[3][3], const float M[4][4]);
void transpose_m4(float R[4][4]);
void transpose_m4_m4(float R[4][4], const float M[4][4]);
diff --git a/source/blender/blenlib/BLI_math_rotation.h b/source/blender/blenlib/BLI_math_rotation.h
index 5e72d502262..8106251684d 100644
--- a/source/blender/blenlib/BLI_math_rotation.h
+++ b/source/blender/blenlib/BLI_math_rotation.h
@@ -57,7 +57,8 @@ void unit_axis_angle(float axis[3], float *angle);
void unit_qt(float q[4]);
void copy_qt_qt(float q[4], const float a[4]);
-/* arithmetic */
+/* Arithmetic. */
+
void mul_qt_qtqt(float q[4], const float a[4], const float b[4]);
/**
* \note
@@ -106,7 +107,8 @@ float dot_qtqt(const float a[4], const float b[4]);
float normalize_qt(float q[4]);
float normalize_qt_qt(float r[4], const float q[4]);
-/* comparison */
+/* Comparison. */
+
bool is_zero_qt(const float q[4]);
/* interpolation */
@@ -122,7 +124,8 @@ void interp_dot_slerp(const float t, const float cosom, float r_w[2]);
void interp_qt_qtqt(float q[4], const float a[4], const float b[4], const float t);
void add_qt_qtqt(float q[4], const float a[4], const float b[4], const float t);
-/* conversion */
+/* Conversion. */
+
void quat_to_mat3(float mat[3][3], const float q[4]);
void quat_to_mat4(float mat[4][4], const float q[4]);
@@ -188,7 +191,8 @@ float angle_signed_qtqt(const float q1[4], const float q2[4]);
*/
void mat3_to_quat_is_ok(float q[4], const float mat[3][3]);
-/* other */
+/* Other. */
+
void print_qt(const char *str, const float q[4]);
#define print_qt_id(q) print_qt(STRINGIFY(q), q)
@@ -199,7 +203,8 @@ void print_qt(const char *str, const float q[4]);
/** \name Axis Angle
* \{ */
-/* conversion */
+/* Conversion. */
+
void axis_angle_normalized_to_quat(float r[4], const float axis[3], const float angle);
void axis_angle_to_quat(float r[4], const float axis[3], const float angle);
/**
@@ -271,32 +276,25 @@ void expmap_to_quat(float r[4], const float expmap[3]);
/** \name XYZ Eulers
* \{ */
-/* XYZ order. */
void eul_to_quat(float quat[4], const float eul[3]);
-/* XYZ order */
void eul_to_mat3(float mat[3][3], const float eul[3]);
-/* XYZ order */
void eul_to_mat4(float mat[4][4], const float eul[3]);
-/* XYZ order */
void mat3_normalized_to_eul(float eul[3], const float mat[3][3]);
-/* XYZ order */
void mat4_normalized_to_eul(float eul[3], const float mat[4][4]);
void mat3_to_eul(float eul[3], const float mat[3][3]);
void mat4_to_eul(float eul[3], const float mat[4][4]);
-/* XYZ order */
void quat_to_eul(float eul[3], const float quat[4]);
-/* XYZ order */
void mat3_normalized_to_compatible_eul(float eul[3], const float old[3], float mat[3][3]);
void mat3_to_compatible_eul(float eul[3], const float old[3], float mat[3][3]);
void quat_to_compatible_eul(float eul[3], const float oldrot[3], const float quat[4]);
-/* order independent! */
-void compatible_eul(float eul[3], const float old[3]);
-
-/* XYZ order */
void rotate_eul(float eul[3], const char axis, const float angle);
+/* Order independent. */
+
+void compatible_eul(float eul[3], const float old[3]);
+
void add_eul_euleul(float r_eul[3], float a[3], float b[3], const short order);
void sub_eul_euleul(float r_eul[3], float a[3], float b[3], const short order);
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index 8f955076baf..61090e30f7b 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -79,7 +79,9 @@ MINLINE void copy_v4_v4_char(char r[4], const char a[4]);
MINLINE void copy_v2_v2_short(short r[2], const short a[2]);
MINLINE void copy_v3_v3_short(short r[3], const short a[3]);
MINLINE void copy_v4_v4_short(short r[4], const short a[4]);
+
/* int */
+
MINLINE void zero_v3_int(int r[3]);
MINLINE void copy_v2_v2_int(int r[2], const int a[2]);
MINLINE void copy_v3_v3_int(int r[3], const int a[3]);
diff --git a/source/blender/blenlib/BLI_mempool.h b/source/blender/blenlib/BLI_mempool.h
index d6abae36e00..a3cf2a77646 100644
--- a/source/blender/blenlib/BLI_mempool.h
+++ b/source/blender/blenlib/BLI_mempool.h
@@ -103,14 +103,14 @@ void BLI_mempool_set_memory_debug(void);
* \note this may easy to produce bugs with.
*/
-/* Private structure. */
+/** \note Private structure. */
typedef struct BLI_mempool_iter {
BLI_mempool *pool;
struct BLI_mempool_chunk *curchunk;
unsigned int curindex;
} BLI_mempool_iter;
-/* flag */
+/** #BLI_mempool.flag */
enum {
BLI_MEMPOOL_NOP = 0,
/** allow iterating on this mempool.
diff --git a/source/blender/blenlib/BLI_quadric.h b/source/blender/blenlib/BLI_quadric.h
index fdb7d1e67ac..450653a20ea 100644
--- a/source/blender/blenlib/BLI_quadric.h
+++ b/source/blender/blenlib/BLI_quadric.h
@@ -31,18 +31,21 @@ typedef struct Quadric {
double a2, ab, ac, ad, b2, bc, bd, c2, cd, d2;
} Quadric;
-/* conversion */
+/* Conversion. */
+
void BLI_quadric_from_plane(Quadric *q, const double v[4]);
void BLI_quadric_to_vector_v3(const Quadric *q, double v[3]);
void BLI_quadric_clear(Quadric *q);
-/* math */
+/* Math operations. */
+
void BLI_quadric_add_qu_qu(Quadric *a, const Quadric *b);
void BLI_quadric_add_qu_ququ(Quadric *r, const Quadric *a, const Quadric *b);
void BLI_quadric_mul(Quadric *a, const double scalar);
-/* solve */
+/* Solve. */
+
double BLI_quadric_evaluate(const Quadric *q, const double v[3]);
bool BLI_quadric_optimize(const Quadric *q, double v[3], const double epsilon);
diff --git a/source/blender/blenlib/BLI_scanfill.h b/source/blender/blenlib/BLI_scanfill.h
index 744d30397d4..ec7fa8f27a0 100644
--- a/source/blender/blenlib/BLI_scanfill.h
+++ b/source/blender/blenlib/BLI_scanfill.h
@@ -91,6 +91,7 @@ typedef struct ScanFillFace {
} ScanFillFace;
/* scanfill.c */
+
struct ScanFillVert *BLI_scanfill_vert_add(ScanFillContext *sf_ctx, const float vec[3]);
struct ScanFillEdge *BLI_scanfill_edge_add(ScanFillContext *sf_ctx,
struct ScanFillVert *v1,
diff --git a/source/blender/blenlib/BLI_session_uuid.h b/source/blender/blenlib/BLI_session_uuid.h
index 887044e9b54..29e291add5a 100644
--- a/source/blender/blenlib/BLI_session_uuid.h
+++ b/source/blender/blenlib/BLI_session_uuid.h
@@ -33,18 +33,19 @@ extern "C" {
#include "DNA_session_uuid_types.h"
-/* Generate new UUID which is unique throughout the Blender session. */
+/** Generate new UUID which is unique throughout the Blender session. */
SessionUUID BLI_session_uuid_generate(void);
-/* Check whether the UUID is properly generated. */
+/** Check whether the UUID is properly generated. */
bool BLI_session_uuid_is_generated(const SessionUUID *uuid);
-/* Check whether two UUIDs are identical. */
+/** Check whether two UUIDs are identical. */
bool BLI_session_uuid_is_equal(const SessionUUID *lhs, const SessionUUID *rhs);
uint64_t BLI_session_uuid_hash_uint64(const SessionUUID *uuid);
/* Utility functions to make it possible to create GHash/GSet with UUID as a key. */
+
uint BLI_session_uuid_ghash_hash(const void *uuid_v);
bool BLI_session_uuid_ghash_compare(const void *lhs_v, const void *rhs_v);
diff --git a/source/blender/blenlib/BLI_sort.h b/source/blender/blenlib/BLI_sort.h
index 969816086e2..31a052eb79d 100644
--- a/source/blender/blenlib/BLI_sort.h
+++ b/source/blender/blenlib/BLI_sort.h
@@ -30,7 +30,7 @@
# define BLI_qsort_r qsort_r
#endif
-/* Quick sort re-entrant */
+/** Quick sort (re-entrant). */
typedef int (*BLI_sort_cmp_t)(const void *a, const void *b, void *ctx);
void BLI_qsort_r(void *a, size_t n, size_t es, BLI_sort_cmp_t cmp, void *thunk)
diff --git a/source/blender/blenlib/BLI_sys_types.h b/source/blender/blenlib/BLI_sys_types.h
index 2740e3740f2..95327ff33b8 100644
--- a/source/blender/blenlib/BLI_sys_types.h
+++ b/source/blender/blenlib/BLI_sys_types.h
@@ -72,8 +72,8 @@ typedef uint64_t u_int64_t;
#include <stddef.h> /* size_t define */
#ifndef __cplusplus
+/* The <uchar.h> standard header is missing on some systems. */
# if defined(__APPLE__) || defined(__NetBSD__)
-/* The <uchar.h> standard header is missing on macOS. */
typedef unsigned int char32_t;
# else
# include <uchar.h>
diff --git a/source/blender/blenlib/BLI_system.h b/source/blender/blenlib/BLI_system.h
index 0d5b2e6e2df..2e5e07d8407 100644
--- a/source/blender/blenlib/BLI_system.h
+++ b/source/blender/blenlib/BLI_system.h
@@ -30,7 +30,7 @@ int BLI_cpu_support_sse2(void);
int BLI_cpu_support_sse41(void);
void BLI_system_backtrace(FILE *fp);
-/* Get CPU brand, result is to be MEM_freeN()-ed. */
+/** Get CPU brand, result is to be MEM_freeN()-ed. */
char *BLI_cpu_brand_string(void);
/**
@@ -45,15 +45,19 @@ char *BLI_cpu_brand_string(void);
*/
void BLI_hostname_get(char *buffer, size_t bufsize);
-/* Get maximum addressable memory in megabytes. */
+/** Get maximum addressable memory in megabytes. */
size_t BLI_system_memory_max_in_megabytes(void);
+/** Get maximum addressable memory in megabytes (clamped to #INT_MAX). */
int BLI_system_memory_max_in_megabytes_int(void);
/* For `getpid`. */
#ifdef WIN32
# define BLI_SYSTEM_PID_H <process.h>
-/* void* since we really do not want to drag Windows.h in to get the proper typedef. */
+/**
+ * \note Use `void *` for `exception` since we really do not want to drag Windows.h
+ * in to get the proper `typedef`.
+ */
void BLI_windows_handle_exception(void *exception);
#else
diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h
index a67de2e2910..616237bc261 100644
--- a/source/blender/blenlib/BLI_task.h
+++ b/source/blender/blenlib/BLI_task.h
@@ -303,7 +303,7 @@ void BLI_task_parallel_mempool(struct BLI_mempool *mempool,
TaskParallelMempoolFunc func,
const TaskParallelSettings *settings);
-/* TODO(sergey): Think of a better place for this. */
+/** TODO(sergey): Think of a better place for this. */
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
{
memset(settings, 0, sizeof(*settings));
diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h
index 6e60430ea38..7bae16f25ef 100644
--- a/source/blender/blenlib/BLI_threads.h
+++ b/source/blender/blenlib/BLI_threads.h
@@ -31,7 +31,7 @@
extern "C" {
#endif
-/* for tables, button in UI, etc */
+/** For tables, button in UI, etc. */
#define BLENDER_MAX_THREADS 1024
struct ListBase;
diff --git a/source/blender/blenlib/BLI_timer.h b/source/blender/blenlib/BLI_timer.h
index c219b5502f3..b1cc8d5514f 100644
--- a/source/blender/blenlib/BLI_timer.h
+++ b/source/blender/blenlib/BLI_timer.h
@@ -29,8 +29,11 @@
extern "C" {
#endif
-/* ret < 0: the timer will be removed.
- * ret >= 0: the timer will be called again in ret seconds */
+/**
+ * \return A value of:
+ * - < 0: the timer will be removed.
+ * - >= 0: the timer will be called again in this number of seconds.
+ */
typedef double (*BLI_timer_func)(uintptr_t uuid, void *user_data);
typedef void (*BLI_timer_data_free)(uintptr_t uuid, void *user_data);
@@ -45,10 +48,10 @@ void BLI_timer_register(uintptr_t uuid,
bool BLI_timer_is_registered(uintptr_t uuid);
-/* Returns False when the timer does not exist (anymore). */
+/** Returns False when the timer does not exist (anymore). */
bool BLI_timer_unregister(uintptr_t uuid);
-/* Execute all registered functions that are due. */
+/** Execute all registered functions that are due. */
void BLI_timer_execute(void);
void BLI_timer_free(void);
diff --git a/source/blender/blenlib/BLI_vector.hh b/source/blender/blenlib/BLI_vector.hh
index d2b94a6d8ef..4ac48f259cf 100644
--- a/source/blender/blenlib/BLI_vector.hh
+++ b/source/blender/blenlib/BLI_vector.hh
@@ -637,7 +637,7 @@ class Vector {
* Insert values at the beginning of the vector. The has to move all the other elements, so it
* has a linear running time.
*/
- void prepend(const T &&value)
+ void prepend(const T &value)
{
this->insert(0, value);
}
diff --git a/source/blender/blenlib/BLI_virtual_array.hh b/source/blender/blenlib/BLI_virtual_array.hh
index 5103ac4b668..3ed9f14712e 100644
--- a/source/blender/blenlib/BLI_virtual_array.hh
+++ b/source/blender/blenlib/BLI_virtual_array.hh
@@ -44,7 +44,7 @@
namespace blender {
-/* Forward declarations for generic virtual arrays. */
+/** Forward declarations for generic virtual arrays. */
namespace fn {
class GVArray;
class GVMutableArray;
@@ -194,7 +194,7 @@ template<typename T> class VArrayImpl {
}
};
-/* Similar to #VArrayImpl, but adds methods that allow modifying the referenced elements. */
+/** Similar to #VArrayImpl, but adds methods that allow modifying the referenced elements. */
template<typename T> class VMutableArrayImpl : public VArrayImpl<T> {
public:
using VArrayImpl<T>::VArrayImpl;
diff --git a/source/blender/blenlib/BLI_virtual_vector_array.hh b/source/blender/blenlib/BLI_virtual_vector_array.hh
index ab5afd2d80a..7672a76d5de 100644
--- a/source/blender/blenlib/BLI_virtual_vector_array.hh
+++ b/source/blender/blenlib/BLI_virtual_vector_array.hh
@@ -29,7 +29,7 @@
namespace blender {
-/* A readonly virtual array of vectors. */
+/** A read-only virtual array of vectors. */
template<typename T> class VVectorArray {
protected:
int64_t size_;
diff --git a/source/blender/blenlib/BLI_winstuff.h b/source/blender/blenlib/BLI_winstuff.h
index cbf1716602a..568734ee8a7 100644
--- a/source/blender/blenlib/BLI_winstuff.h
+++ b/source/blender/blenlib/BLI_winstuff.h
@@ -88,7 +88,7 @@ typedef SSIZE_T ssize_t;
# endif
#endif
-/* Directory reading compatibility with UNIX. */
+/** Directory reading compatibility with UNIX. */
struct dirent {
int d_ino;
int d_off;
@@ -96,7 +96,7 @@ struct dirent {
char *d_name;
};
-/* intentionally opaque to users */
+/** Intentionally opaque to users. */
typedef struct __dirstream DIR;
DIR *opendir(const char *path);
@@ -105,6 +105,7 @@ int closedir(DIR *dp);
const char *dirname(char *path);
/* Windows utility functions. */
+
bool BLI_windows_register_blend_extension(const bool background);
void BLI_windows_get_default_root_dir(char root_dir[4]);
int BLI_windows_get_executable_dir(char *str);
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 29493c799b3..516d9d2fe84 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -76,6 +76,7 @@ set(SRC
intern/endian_switch.c
intern/expr_pylike_eval.c
intern/fileops.c
+ intern/fileops.cc
intern/filereader_file.c
intern/filereader_gzip.c
intern/filereader_memory.c
@@ -204,6 +205,7 @@ set(SRC
BLI_enumerable_thread_specific.hh
BLI_expr_pylike_eval.h
BLI_fileops.h
+ BLI_fileops.hh
BLI_fileops_types.h
BLI_filereader.h
BLI_float2.hh
@@ -422,6 +424,7 @@ if(WITH_GTESTS)
tests/BLI_edgehash_test.cc
tests/BLI_expr_pylike_eval_test.cc
tests/BLI_function_ref_test.cc
+ tests/BLI_fileops_test.cc
tests/BLI_ghash_test.cc
tests/BLI_hash_mm2a_test.cc
tests/BLI_heap_simple_test.cc
diff --git a/source/blender/blenlib/intern/fileops.cc b/source/blender/blenlib/intern/fileops.cc
new file mode 100644
index 00000000000..5ceedbd8cb5
--- /dev/null
+++ b/source/blender/blenlib/intern/fileops.cc
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup bli
+ */
+
+#include "BLI_fileops.hh"
+
+#ifdef WIN32
+# include "utfconv.h"
+#endif
+
+namespace blender {
+fstream::fstream(const char *filepath, std::ios_base::openmode mode)
+{
+ this->open(filepath, mode);
+}
+
+fstream::fstream(const std::string &filepath, std::ios_base::openmode mode)
+{
+ this->open(filepath, mode);
+}
+
+void fstream::open(StringRefNull filepath, ios_base::openmode mode)
+{
+#ifdef WIN32
+ const char *filepath_cstr = filepath.c_str();
+ UTF16_ENCODE(filepath_cstr);
+ std::wstring filepath_wstr(filepath_cstr_16);
+ std::fstream::open(filepath_wstr.c_str(), mode);
+ UTF16_UN_ENCODE(filepath_cstr);
+#else
+ std::fstream::open(filepath, mode);
+#endif
+}
+
+} // namespace blender
diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c
index a166c846ea7..513b08a589d 100644
--- a/source/blender/blenlib/intern/listbase.c
+++ b/source/blender/blenlib/intern/listbase.c
@@ -749,6 +749,26 @@ int BLI_findstringindex(const ListBase *listbase, const char *id, const int offs
return -1;
}
+ListBase BLI_listbase_from_link(Link *some_link)
+{
+ ListBase list = {some_link, some_link};
+ if (some_link == NULL) {
+ return list;
+ }
+
+ /* Find the first element. */
+ while (((Link *)list.first)->prev != NULL) {
+ list.first = ((Link *)list.first)->prev;
+ }
+
+ /* Find the last element. */
+ while (((Link *)list.last)->next != NULL) {
+ list.last = ((Link *)list.last)->next;
+ }
+
+ return list;
+}
+
void BLI_duplicatelist(ListBase *dst, const ListBase *src)
{
struct Link *dst_link, *src_link;
diff --git a/source/blender/blenlib/intern/task_scheduler.cc b/source/blender/blenlib/intern/task_scheduler.cc
index 69117e9dc7e..5992e092f4d 100644
--- a/source/blender/blenlib/intern/task_scheduler.cc
+++ b/source/blender/blenlib/intern/task_scheduler.cc
@@ -50,8 +50,8 @@ void BLI_task_scheduler_init()
if (num_threads_override > 0) {
/* Override number of threads. This settings is used within the lifetime
* of tbb::global_control, so we allocate it on the heap. */
- task_scheduler_global_control = OBJECT_GUARDED_NEW(
- tbb::global_control, tbb::global_control::max_allowed_parallelism, num_threads_override);
+ task_scheduler_global_control = MEM_new<tbb::global_control>(
+ __func__, tbb::global_control::max_allowed_parallelism, num_threads_override);
task_scheduler_num_threads = num_threads_override;
}
else {
@@ -69,7 +69,7 @@ void BLI_task_scheduler_init()
void BLI_task_scheduler_exit()
{
#ifdef WITH_TBB_GLOBAL_CONTROL
- OBJECT_GUARDED_DELETE(task_scheduler_global_control, tbb::global_control);
+ MEM_delete(task_scheduler_global_control);
#endif
}
diff --git a/source/blender/blenlib/tests/BLI_fileops_test.cc b/source/blender/blenlib/tests/BLI_fileops_test.cc
new file mode 100644
index 00000000000..e2a792647dc
--- /dev/null
+++ b/source/blender/blenlib/tests/BLI_fileops_test.cc
@@ -0,0 +1,40 @@
+/* Apache License, Version 2.0 */
+
+#include "BLI_fileops.hh"
+
+#include "testing/testing.h"
+
+namespace blender::tests {
+
+TEST(fileops, fstream_open_string_filename)
+{
+ const std::string test_files_dir = blender::tests::flags_test_asset_dir();
+ if (test_files_dir.empty()) {
+ FAIL();
+ }
+
+ const std::string filepath = test_files_dir + "/asset_library/новый/blender_assets.cats.txt";
+ fstream in(filepath, std::ios_base::in);
+ ASSERT_TRUE(in.is_open()) << "could not open " << filepath;
+ in.close(); /* This should not crash. */
+
+ /* Reading the file not tested here. That's deferred to `std::fstream` anyway. */
+}
+
+TEST(fileops, fstream_open_charptr_filename)
+{
+ const std::string test_files_dir = blender::tests::flags_test_asset_dir();
+ if (test_files_dir.empty()) {
+ FAIL();
+ }
+
+ const std::string filepath_str = test_files_dir + "/asset_library/новый/blender_assets.cats.txt";
+ const char *filepath = filepath_str.c_str();
+ fstream in(filepath, std::ios_base::in);
+ ASSERT_TRUE(in.is_open()) << "could not open " << filepath;
+ in.close(); /* This should not crash. */
+
+ /* Reading the file not tested here. That's deferred to `std::fstream` anyway. */
+}
+
+} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/BLI_listbase_test.cc b/source/blender/blenlib/tests/BLI_listbase_test.cc
index d66eb214902..9e4d7c7dd36 100644
--- a/source/blender/blenlib/tests/BLI_listbase_test.cc
+++ b/source/blender/blenlib/tests/BLI_listbase_test.cc
@@ -154,6 +154,31 @@ TEST(listbase, FindLinkFromStringOrPointer)
BLI_freelistN(&lb);
}
+TEST(listbase, FromLink)
+{
+ ListBase lb = {nullptr, nullptr};
+ Link *link1 = static_cast<Link *>(MEM_callocN(sizeof(Link), "link1"));
+ Link *link2 = static_cast<Link *>(MEM_callocN(sizeof(Link), "link2"));
+ Link *link3 = static_cast<Link *>(MEM_callocN(sizeof(Link), "link3"));
+
+ /* NULL safety. */
+ EXPECT_EQ(lb, BLI_listbase_from_link(nullptr));
+
+ /* One link. */
+ BLI_addtail(&lb, link1);
+ EXPECT_EQ(lb, BLI_listbase_from_link(link1));
+
+ /* Two links. */
+ BLI_addtail(&lb, link2);
+ EXPECT_EQ(lb, BLI_listbase_from_link(link2));
+
+ /* Three links, search from middle. */
+ BLI_addtail(&lb, link3);
+ EXPECT_EQ(lb, BLI_listbase_from_link(link2));
+
+ BLI_freelistN(&lb);
+}
+
/* -------------------------------------------------------------------- */
/* Sort utilities & test */
diff --git a/source/blender/blenlib/tests/BLI_vector_test.cc b/source/blender/blenlib/tests/BLI_vector_test.cc
index e8636168308..e9393a2b1e5 100644
--- a/source/blender/blenlib/tests/BLI_vector_test.cc
+++ b/source/blender/blenlib/tests/BLI_vector_test.cc
@@ -708,6 +708,17 @@ TEST(vector, Prepend)
EXPECT_EQ_ARRAY(vec.data(), Span({7, 8, 1, 2, 3}).data(), 5);
}
+TEST(vector, PrependString)
+{
+ std::string s = "test";
+ Vector<std::string> vec;
+ vec.prepend(s);
+ vec.prepend(std::move(s));
+ EXPECT_EQ(vec.size(), 2);
+ EXPECT_EQ(vec[0], "test");
+ EXPECT_EQ(vec[1], "test");
+}
+
TEST(vector, ReverseIterator)
{
Vector<int> vec = {4, 5, 6, 7};
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index 54e673b51eb..8bcb99e41e4 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -70,6 +70,7 @@
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
+#include "BKE_node_tree_update.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_screen.h"
@@ -590,7 +591,7 @@ static bNodeSocket *do_versions_node_group_add_socket_2_56_2(bNodeTree *ngroup,
BLI_addtail(in_out == SOCK_IN ? &ngroup->inputs : &ngroup->outputs, gsock);
- ngroup->update |= (in_out == SOCK_IN ? NTREE_UPDATE_GROUP_IN : NTREE_UPDATE_GROUP_OUT);
+ BKE_ntree_update_tag_interface(ngroup);
return gsock;
}
@@ -2019,7 +2020,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
link->fromsock = gsock;
link->tonode = node;
link->tosock = sock;
- ntree->update |= NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_link_added(ntree, link);
sock->link = link;
}
@@ -2042,7 +2043,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
link->fromsock = sock;
link->tonode = NULL;
link->tosock = gsock;
- ntree->update |= NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_link_added(ntree, link);
gsock->link = link;
}
@@ -2282,7 +2283,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
do_versions_socket_default_value_259(sock);
}
- ntree->update |= NTREE_UPDATE;
+ BKE_ntree_update_tag_all(ntree);
}
FOREACH_NODETREE_END;
}
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index 4333bdb851c..d9052c6b1f7 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -88,6 +88,7 @@
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_paint.h"
#include "BKE_pointcache.h"
#include "BKE_report.h"
@@ -896,7 +897,7 @@ static void do_versions_material_convert_legacy_blend_mode(bNodeTree *ntree, cha
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index bc3cd7a09cb..5eb9b0a4c6a 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -30,6 +30,7 @@
#include "BLI_math_vector.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "DNA_anim_types.h"
@@ -592,7 +593,7 @@ static bNodeTree *add_realize_node_tree(Main *bmain)
nodeSetSelected(node, false);
}
- ntreeUpdateTree(bmain, node_tree);
+ version_socket_update_is_used(node_tree);
return node_tree;
}
@@ -790,6 +791,32 @@ void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports))
*/
{
/* Keep this block, even when empty. */
+
+ { /* Ensure driver variable names are unique within the driver. */
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ AnimData *adt = BKE_animdata_from_id(id);
+ if (adt == NULL) {
+ continue;
+ }
+ LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) {
+ ChannelDriver *driver = fcu->driver;
+ /* Ensure the uniqueness front to back. Given a list of identically
+ * named variables, the last one gets to keep its original name. This
+ * matches the evaluation order, and thus shouldn't change the evaluated
+ * value of the driver expression. */
+ LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
+ BLI_uniquename(&driver->variables,
+ dvar,
+ dvar->name,
+ '_',
+ offsetof(DriverVar, name),
+ sizeof(dvar->name));
+ }
+ }
+ }
+ FOREACH_MAIN_ID_END;
+ }
}
}
@@ -2414,7 +2441,6 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
data->data_type = SOCK_FLOAT;
data->operation = node->custom1;
strcpy(node->idname, "FunctionNodeCompare");
- node->update = NODE_UPDATE;
node->storage = data;
}
}
@@ -2432,22 +2458,6 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
-
- /* Add node storage for map range node. */
- FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->type == SH_NODE_MAP_RANGE) {
- if (node->storage == NULL) {
- NodeMapRange *data = MEM_callocN(sizeof(NodeMapRange), __func__);
- data->clamp = node->custom1;
- data->data_type = CD_PROP_FLOAT;
- data->interpolation_type = node->custom2;
- node->storage = data;
- }
- }
- }
- }
- FOREACH_NODETREE_END;
}
if (!MAIN_VERSION_ATLEAST(bmain, 301, 5)) {
@@ -2475,5 +2485,21 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
*/
{
/* Keep this block, even when empty. */
+
+ /* Add node storage for map range node. */
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == SH_NODE_MAP_RANGE) {
+ if (node->storage == NULL) {
+ NodeMapRange *data = MEM_callocN(sizeof(NodeMapRange), __func__);
+ data->clamp = node->custom1;
+ data->data_type = CD_PROP_FLOAT;
+ data->interpolation_type = node->custom2;
+ node->storage = data;
+ }
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
}
}
diff --git a/source/blender/blenloader/intern/versioning_common.cc b/source/blender/blenloader/intern/versioning_common.cc
index 3deaaa040d6..752157bffde 100644
--- a/source/blender/blenloader/intern/versioning_common.cc
+++ b/source/blender/blenloader/intern/versioning_common.cc
@@ -223,3 +223,23 @@ void version_node_socket_index_animdata(Main *bmain,
FOREACH_NODETREE_END;
}
}
+
+/**
+ * The versioning code generally expects `SOCK_IN_USE` to be set correctly. This function updates
+ * the flag on all sockets after changes to the node tree.
+ */
+void version_socket_update_is_used(bNodeTree *ntree)
+{
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ socket->flag &= ~SOCK_IN_USE;
+ }
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
+ socket->flag &= ~SOCK_IN_USE;
+ }
+ }
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ link->fromsock->flag |= SOCK_IN_USE;
+ link->tosock->flag |= SOCK_IN_USE;
+ }
+}
diff --git a/source/blender/blenloader/intern/versioning_common.h b/source/blender/blenloader/intern/versioning_common.h
index 0613484b754..dd1dd1f22f2 100644
--- a/source/blender/blenloader/intern/versioning_common.h
+++ b/source/blender/blenloader/intern/versioning_common.h
@@ -100,6 +100,8 @@ struct bNodeSocket *version_node_add_socket_if_not_exist(struct bNodeTree *ntree
const char *identifier,
const char *name);
+void version_socket_update_is_used(bNodeTree *ntree);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenloader/intern/versioning_cycles.c b/source/blender/blenloader/intern/versioning_cycles.c
index afe2e1067ae..f1a2e678b2e 100644
--- a/source/blender/blenloader/intern/versioning_cycles.c
+++ b/source/blender/blenloader/intern/versioning_cycles.c
@@ -48,6 +48,7 @@
#include "BLO_readfile.h"
#include "readfile.h"
+#include "versioning_common.h"
static bool socket_is_used(bNodeSocket *sock)
{
@@ -170,7 +171,7 @@ static void displacement_node_insert(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -243,7 +244,7 @@ static void square_roughness_node_insert(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -318,7 +319,7 @@ static void ambient_occlusion_node_relink(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -466,7 +467,7 @@ static void update_math_node_single_operand_operators(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -528,7 +529,7 @@ static void update_vector_math_node_add_and_subtract_operators(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -566,7 +567,7 @@ static void update_vector_math_node_dot_product_operator(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -631,7 +632,7 @@ static void update_vector_math_node_cross_product_operator(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -683,7 +684,7 @@ static void update_vector_math_node_normalize_operator(bNodeTree *ntree)
}
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -785,7 +786,7 @@ static void update_vector_math_node_average_operator(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -974,7 +975,7 @@ static void update_mapping_node_inputs_and_properties(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -1149,7 +1150,7 @@ static void update_voronoi_node_crackle(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -1191,7 +1192,7 @@ static void update_voronoi_node_coloring(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -1234,7 +1235,7 @@ static void update_voronoi_node_square_distance(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -1279,7 +1280,7 @@ static void update_noise_and_wave_distortion(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index a5c44ea711b..234951eac9a 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -61,6 +61,7 @@
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_paint.h"
#include "BKE_screen.h"
#include "BKE_workspace.h"
@@ -583,11 +584,11 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
bNodeSocketValueFloat *roughness_data = roughness_socket->default_value;
roughness_data->value = 0.4f;
node->custom2 = SHD_SUBSURFACE_RANDOM_WALK;
- nodeUpdate(ma->nodetree, node);
+ BKE_ntree_update_tag_node_property(ma->nodetree, node);
}
else if (node->type == SH_NODE_SUBSURFACE_SCATTERING) {
node->custom1 = SHD_SUBSURFACE_RANDOM_WALK;
- nodeUpdate(ma->nodetree, node);
+ BKE_ntree_update_tag_node_property(ma->nodetree, node);
}
}
}
diff --git a/source/blender/blenloader/tests/blendfile_loading_base_test.cc b/source/blender/blenloader/tests/blendfile_loading_base_test.cc
index a4a5ced070d..32d288f35e1 100644
--- a/source/blender/blenloader/tests/blendfile_loading_base_test.cc
+++ b/source/blender/blenloader/tests/blendfile_loading_base_test.cc
@@ -21,6 +21,7 @@
#include "BKE_appdir.h"
#include "BKE_blender.h"
+#include "BKE_callbacks.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
@@ -71,6 +72,7 @@ void BlendfileLoadingBaseTest::SetUpTestCase()
DEG_register_node_types();
RNA_init();
BKE_node_system_init();
+ BKE_callback_global_init();
G.background = true;
G.factory_startup = true;
diff --git a/source/blender/compositor/intern/COM_compositor.cc b/source/blender/compositor/intern/COM_compositor.cc
index be70ae792cb..5c9b34c4772 100644
--- a/source/blender/compositor/intern/COM_compositor.cc
+++ b/source/blender/compositor/intern/COM_compositor.cc
@@ -51,7 +51,7 @@ static void compositor_init_node_previews(const RenderData *render_data, bNodeTr
preview_width = (int)(blender::compositor::COM_PREVIEW_SIZE / aspect);
preview_height = blender::compositor::COM_PREVIEW_SIZE;
}
- BKE_node_preview_init_tree(node_tree, preview_width, preview_height, false);
+ BKE_node_preview_init_tree(node_tree, preview_width, preview_height);
}
static void compositor_reset_node_tree_status(bNodeTree *node_tree)
diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h
index 94cba833096..8a69dbf3312 100644
--- a/source/blender/depsgraph/DEG_depsgraph_build.h
+++ b/source/blender/depsgraph/DEG_depsgraph_build.h
@@ -153,9 +153,9 @@ void DEG_add_collection_geometry_customdata_mask(struct DepsNodeHandle *node_han
void DEG_add_simulation_relation(struct DepsNodeHandle *node_handle,
struct Simulation *simulation,
const char *description);
-void DEG_add_node_tree_relation(struct DepsNodeHandle *node_handle,
- struct bNodeTree *node_tree,
- const char *description);
+void DEG_add_node_tree_output_relation(struct DepsNodeHandle *node_handle,
+ struct bNodeTree *node_tree,
+ const char *description);
void DEG_add_bone_relation(struct DepsNodeHandle *handle,
struct Object *object,
const char *bone_name,
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index 51582508b6f..16eacc735d4 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -1710,8 +1710,8 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
build_idproperties(ntree->id.properties);
/* Animation, */
build_animdata(&ntree->id);
- /* Shading update. */
- add_operation_node(&ntree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE);
+ /* Output update. */
+ add_operation_node(&ntree->id, NodeType::NTREE_OUTPUT, OperationCode::NTREE_OUTPUT);
/* nodetree's nodes... */
LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) {
build_idproperties(bnode->prop);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index b195b2d9e11..09263718677 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -1770,7 +1770,7 @@ void DepsgraphRelationBuilder::build_world(World *world)
if (world->nodetree != nullptr) {
build_nodetree(world->nodetree);
OperationKey ntree_key(
- &world->nodetree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE);
+ &world->nodetree->id, NodeType::NTREE_OUTPUT, OperationCode::NTREE_OUTPUT);
add_relation(ntree_key, world_key, "World's NTree");
build_nested_nodetree(&world->id, world->nodetree);
}
@@ -2381,17 +2381,17 @@ void DepsgraphRelationBuilder::build_light(Light *lamp)
ComponentKey lamp_parameters_key(&lamp->id, NodeType::PARAMETERS);
+ /* For allowing drivers on lamp properties. */
+ ComponentKey shading_key(&lamp->id, NodeType::SHADING);
+ add_relation(lamp_parameters_key, shading_key, "Light Shading Parameters");
+
/* light's nodetree */
if (lamp->nodetree != nullptr) {
build_nodetree(lamp->nodetree);
- ComponentKey nodetree_key(&lamp->nodetree->id, NodeType::SHADING);
- add_relation(nodetree_key, lamp_parameters_key, "NTree->Light Parameters");
+ ComponentKey nodetree_key(&lamp->nodetree->id, NodeType::NTREE_OUTPUT);
+ add_relation(nodetree_key, shading_key, "NTree->Light Parameters");
build_nested_nodetree(&lamp->id, lamp->nodetree);
}
-
- /* For allowing drivers on lamp properties. */
- ComponentKey shading_key(&lamp->id, NodeType::SHADING);
- add_relation(lamp_parameters_key, shading_key, "Light Shading Parameters");
}
void DepsgraphRelationBuilder::build_nodetree_socket(bNodeSocket *socket)
@@ -2441,7 +2441,7 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
build_idproperties(ntree->id.properties);
build_animdata(&ntree->id);
build_parameters(&ntree->id);
- ComponentKey shading_key(&ntree->id, NodeType::SHADING);
+ OperationKey ntree_output_key(&ntree->id, NodeType::NTREE_OUTPUT, OperationCode::NTREE_OUTPUT);
/* nodetree's nodes... */
LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) {
build_idproperties(bnode->prop);
@@ -2460,25 +2460,25 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
if (id_type == ID_MA) {
build_material((Material *)bnode->id);
ComponentKey material_key(id, NodeType::SHADING);
- add_relation(material_key, shading_key, "Material -> Node");
+ add_relation(material_key, ntree_output_key, "Material -> Node");
}
else if (id_type == ID_TE) {
build_texture((Tex *)bnode->id);
ComponentKey texture_key(id, NodeType::GENERIC_DATABLOCK);
- add_relation(texture_key, shading_key, "Texture -> Node");
+ add_relation(texture_key, ntree_output_key, "Texture -> Node");
}
else if (id_type == ID_IM) {
build_image((Image *)bnode->id);
ComponentKey image_key(id, NodeType::GENERIC_DATABLOCK);
- add_relation(image_key, shading_key, "Image -> Node");
+ add_relation(image_key, ntree_output_key, "Image -> Node");
}
else if (id_type == ID_OB) {
build_object((Object *)id);
ComponentKey object_transform_key(id, NodeType::TRANSFORM);
- add_relation(object_transform_key, shading_key, "Object Transform -> Node");
+ add_relation(object_transform_key, ntree_output_key, "Object Transform -> Node");
if (object_have_geometry_component(reinterpret_cast<Object *>(id))) {
ComponentKey object_geometry_key(id, NodeType::GEOMETRY);
- add_relation(object_geometry_key, shading_key, "Object Geometry -> Node");
+ add_relation(object_geometry_key, ntree_output_key, "Object Geometry -> Node");
}
}
else if (id_type == ID_SCE) {
@@ -2498,23 +2498,28 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
else if (id_type == ID_MSK) {
build_mask((Mask *)id);
OperationKey mask_key(id, NodeType::PARAMETERS, OperationCode::MASK_EVAL);
- add_relation(mask_key, shading_key, "Mask -> Node");
+ add_relation(mask_key, ntree_output_key, "Mask -> Node");
}
else if (id_type == ID_MC) {
build_movieclip((MovieClip *)id);
OperationKey clip_key(id, NodeType::PARAMETERS, OperationCode::MOVIECLIP_EVAL);
- add_relation(clip_key, shading_key, "Clip -> Node");
+ add_relation(clip_key, ntree_output_key, "Clip -> Node");
}
else if (id_type == ID_VF) {
build_vfont((VFont *)id);
ComponentKey vfont_key(id, NodeType::GENERIC_DATABLOCK);
- add_relation(vfont_key, shading_key, "VFont -> Node");
+ add_relation(vfont_key, ntree_output_key, "VFont -> Node");
}
else if (ELEM(bnode->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
bNodeTree *group_ntree = (bNodeTree *)id;
build_nodetree(group_ntree);
- ComponentKey group_shading_key(&group_ntree->id, NodeType::SHADING);
- add_relation(group_shading_key, shading_key, "Group Node");
+ ComponentKey group_output_key(&group_ntree->id, NodeType::NTREE_OUTPUT);
+ /* The output of the current tree does not necessarily change when the output of the group
+ * changed. The parent node group is currently explicitly tagged for update in
+ * #ED_node_tree_propagate_change. In the future we could move this relation to the
+ * depsgraph, but then the depsgraph has to do some more static analysis of the node tree to
+ * see which groups the output actually depends on. */
+ add_relation(group_output_key, ntree_output_key, "Group Node", RELATION_FLAG_NO_FLUSH);
}
else {
BLI_assert_msg(0, "Unknown ID type used for node");
@@ -2528,14 +2533,10 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
build_idproperties(socket->prop);
}
- OperationKey shading_update_key(&ntree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE);
-
if (check_id_has_anim_component(&ntree->id)) {
ComponentKey animation_key(&ntree->id, NodeType::ANIMATION);
- add_relation(animation_key, shading_update_key, "NTree Shading Parameters");
+ add_relation(animation_key, ntree_output_key, "NTree Shading Parameters");
}
- ComponentKey parameters_key(&ntree->id, NodeType::PARAMETERS);
- add_relation(parameters_key, shading_update_key, "NTree Shading Parameters");
}
/* Recursively build graph for material */
@@ -2558,7 +2559,7 @@ void DepsgraphRelationBuilder::build_material(Material *material)
if (material->nodetree != nullptr) {
build_nodetree(material->nodetree);
OperationKey ntree_key(
- &material->nodetree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE);
+ &material->nodetree->id, NodeType::NTREE_OUTPUT, OperationCode::NTREE_OUTPUT);
add_relation(ntree_key, material_key, "Material's NTree");
build_nested_nodetree(&material->id, material->nodetree);
}
@@ -2587,8 +2588,13 @@ void DepsgraphRelationBuilder::build_texture(Tex *texture)
build_parameters(&texture->id);
/* texture's nodetree */
- build_nodetree(texture->nodetree);
- build_nested_nodetree(&texture->id, texture->nodetree);
+ if (texture->nodetree) {
+ build_nodetree(texture->nodetree);
+ OperationKey ntree_key(
+ &texture->nodetree->id, NodeType::NTREE_OUTPUT, OperationCode::NTREE_OUTPUT);
+ add_relation(ntree_key, texture_key, "Texture's NTree");
+ build_nested_nodetree(&texture->id, texture->nodetree);
+ }
/* Special cases for different IDs which texture uses. */
if (texture->type == TEX_IMAGE) {
@@ -2875,12 +2881,16 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations()
*
* This is similar to what happens in ntree_hack_remap_pointers().
*/
-void DepsgraphRelationBuilder::build_nested_datablock(ID *owner, ID *id)
+void DepsgraphRelationBuilder::build_nested_datablock(ID *owner, ID *id, bool flush_cow_changes)
{
+ int relation_flag = 0;
+ if (!flush_cow_changes) {
+ relation_flag |= RELATION_FLAG_NO_FLUSH;
+ }
OperationKey owner_copy_on_write_key(
owner, NodeType::COPY_ON_WRITE, OperationCode::COPY_ON_WRITE);
OperationKey id_copy_on_write_key(id, NodeType::COPY_ON_WRITE, OperationCode::COPY_ON_WRITE);
- add_relation(id_copy_on_write_key, owner_copy_on_write_key, "Eval Order");
+ add_relation(id_copy_on_write_key, owner_copy_on_write_key, "Eval Order", relation_flag);
}
void DepsgraphRelationBuilder::build_nested_nodetree(ID *owner, bNodeTree *ntree)
@@ -2888,7 +2898,10 @@ void DepsgraphRelationBuilder::build_nested_nodetree(ID *owner, bNodeTree *ntree
if (ntree == nullptr) {
return;
}
- build_nested_datablock(owner, &ntree->id);
+ /* Don't flush cow changes, because the node tree may change in ways that do not affect the
+ * owner data block (e.g. when a node is deleted that is not connected to any output).
+ * Data blocks owning node trees should add a relation to the `NTREE_OUTPUT` node instead. */
+ build_nested_datablock(owner, &ntree->id, false);
}
void DepsgraphRelationBuilder::build_nested_shapekey(ID *owner, Key *key)
@@ -2896,7 +2909,7 @@ void DepsgraphRelationBuilder::build_nested_shapekey(ID *owner, Key *key)
if (key == nullptr) {
return;
}
- build_nested_datablock(owner, &key->id);
+ build_nested_datablock(owner, &key->id, true);
}
void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node)
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index 09003de3ce4..787e3799029 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -299,7 +299,7 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
virtual void build_scene_speakers(Scene *scene, ViewLayer *view_layer);
virtual void build_vfont(VFont *vfont);
- virtual void build_nested_datablock(ID *owner, ID *id);
+ virtual void build_nested_datablock(ID *owner, ID *id, bool flush_cow_changes);
virtual void build_nested_nodetree(ID *owner, bNodeTree *ntree);
virtual void build_nested_shapekey(ID *owner, Key *key);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
index 40e59875832..43d24125dc2 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
@@ -351,7 +351,7 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
return node_identifier;
}
else if (RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) {
- node_identifier.type = NodeType::SHADING;
+ node_identifier.type = NodeType::NTREE_OUTPUT;
return node_identifier;
}
else if (RNA_struct_is_a(ptr->type, &RNA_ShaderNode)) {
diff --git a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
index 7be661d9668..36120ae76d1 100644
--- a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
+++ b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
@@ -425,6 +425,7 @@ static void deg_debug_graphviz_node(DotExportContext &ctx,
case NodeType::ARMATURE:
case NodeType::GENERIC_DATABLOCK:
case NodeType::VISIBILITY:
+ case NodeType::NTREE_OUTPUT:
case NodeType::SIMULATION: {
ComponentNode *comp_node = (ComponentNode *)node;
if (comp_node->operations.is_empty()) {
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index db00c595383..acb8fa8fe88 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -148,15 +148,15 @@ void DEG_add_simulation_relation(DepsNodeHandle *node_handle,
deg_node_handle->builder->add_node_handle_relation(operation_key, deg_node_handle, description);
}
-void DEG_add_node_tree_relation(DepsNodeHandle *node_handle,
- bNodeTree *node_tree,
- const char *description)
+void DEG_add_node_tree_output_relation(DepsNodeHandle *node_handle,
+ bNodeTree *node_tree,
+ const char *description)
{
- /* Using shading key, because that's the one that exists right now. Should use something else in
- * the future. */
- deg::ComponentKey shading_key(&node_tree->id, deg::NodeType::SHADING);
+ deg::OperationKey ntree_output_key(
+ &node_tree->id, deg::NodeType::NTREE_OUTPUT, deg::OperationCode::NTREE_OUTPUT);
deg::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle);
- deg_node_handle->builder->add_node_handle_relation(shading_key, deg_node_handle, description);
+ deg_node_handle->builder->add_node_handle_relation(
+ ntree_output_key, deg_node_handle, description);
}
void DEG_add_object_cache_relation(DepsNodeHandle *node_handle,
diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
index 7af3d03d478..c84adbcde00 100644
--- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
@@ -334,10 +334,13 @@ static void DEG_iterator_ids_step(BLI_Iterator *iter, deg::IDNode *id_node, bool
return;
}
if (only_updated && !(id_cow->recalc & ID_RECALC_ALL)) {
- bNodeTree *ntree = ntreeFromID(id_cow);
-
/* Node-tree is considered part of the data-block. */
- if (!(ntree && (ntree->id.recalc & ID_RECALC_ALL))) {
+ bNodeTree *ntree = ntreeFromID(id_cow);
+ if (ntree == nullptr) {
+ iter->skip = true;
+ return;
+ }
+ if ((ntree->id.recalc & ID_RECALC_NTREE_OUTPUT) == 0) {
iter->skip = true;
return;
}
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index 2b0d0e6e780..4bc9e0d2d14 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -232,6 +232,10 @@ void depsgraph_tag_to_component_opcode(const ID *id,
break;
case ID_RECALC_TAG_FOR_UNDO:
break; /* Must be ignored by depsgraph. */
+ case ID_RECALC_NTREE_OUTPUT:
+ *component_type = NodeType::NTREE_OUTPUT;
+ *operation_code = OperationCode::NTREE_OUTPUT;
+ break;
}
}
@@ -749,6 +753,8 @@ const char *DEG_update_tag_as_string(IDRecalcFlag flag)
return "ALL";
case ID_RECALC_TAG_FOR_UNDO:
return "TAG_FOR_UNDO";
+ case ID_RECALC_NTREE_OUTPUT:
+ return "ID_RECALC_NTREE_OUTPUT";
}
return nullptr;
}
diff --git a/source/blender/depsgraph/intern/node/deg_node.cc b/source/blender/depsgraph/intern/node/deg_node.cc
index 8bc03d8b736..075bfd35ec1 100644
--- a/source/blender/depsgraph/intern/node/deg_node.cc
+++ b/source/blender/depsgraph/intern/node/deg_node.cc
@@ -116,6 +116,8 @@ const char *nodeTypeAsString(NodeType type)
return "VISIBILITY";
case NodeType::SIMULATION:
return "SIMULATION";
+ case NodeType::NTREE_OUTPUT:
+ return "NTREE_OUTPUT";
/* Total number of meaningful node types. */
case NodeType::NUM_TYPES:
@@ -174,6 +176,7 @@ eDepsSceneComponentType nodeTypeToSceneComponent(NodeType type)
case NodeType::CACHE:
case NodeType::PROXY:
case NodeType::SIMULATION:
+ case NodeType::NTREE_OUTPUT:
return DEG_SCENE_COMP_PARAMETERS;
case NodeType::VISIBILITY:
@@ -251,6 +254,7 @@ eDepsObjectComponentType nodeTypeToObjectComponent(NodeType type)
case NodeType::DUPLI:
case NodeType::SYNCHRONIZATION:
case NodeType::SIMULATION:
+ case NodeType::NTREE_OUTPUT:
case NodeType::UNDEFINED:
case NodeType::NUM_TYPES:
return DEG_OB_COMP_PARAMETERS;
diff --git a/source/blender/depsgraph/intern/node/deg_node.h b/source/blender/depsgraph/intern/node/deg_node.h
index 7e093ab8765..ef58a35afb2 100644
--- a/source/blender/depsgraph/intern/node/deg_node.h
+++ b/source/blender/depsgraph/intern/node/deg_node.h
@@ -147,6 +147,8 @@ enum class NodeType {
SYNCHRONIZATION,
/* Simulation component. */
SIMULATION,
+ /* Node tree output component. */
+ NTREE_OUTPUT,
/* Total number of meaningful node types. */
NUM_TYPES,
diff --git a/source/blender/depsgraph/intern/node/deg_node_component.cc b/source/blender/depsgraph/intern/node/deg_node_component.cc
index b716877902c..4c430904e44 100644
--- a/source/blender/depsgraph/intern/node/deg_node_component.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_component.cc
@@ -351,6 +351,7 @@ DEG_COMPONENT_NODE_DEFINE(Armature, ARMATURE, 0);
DEG_COMPONENT_NODE_DEFINE(GenericDatablock, GENERIC_DATABLOCK, 0);
DEG_COMPONENT_NODE_DEFINE(Visibility, VISIBILITY, 0);
DEG_COMPONENT_NODE_DEFINE(Simulation, SIMULATION, 0);
+DEG_COMPONENT_NODE_DEFINE(NTreeOutput, NTREE_OUTPUT, ID_RECALC_NTREE_OUTPUT);
/** \} */
@@ -385,6 +386,7 @@ void deg_register_component_depsnodes()
register_node_typeinfo(&DNTI_GENERIC_DATABLOCK);
register_node_typeinfo(&DNTI_VISIBILITY);
register_node_typeinfo(&DNTI_SIMULATION);
+ register_node_typeinfo(&DNTI_NTREE_OUTPUT);
}
/** \} */
diff --git a/source/blender/depsgraph/intern/node/deg_node_component.h b/source/blender/depsgraph/intern/node/deg_node_component.h
index 9f108af8012..8fd28dfc497 100644
--- a/source/blender/depsgraph/intern/node/deg_node_component.h
+++ b/source/blender/depsgraph/intern/node/deg_node_component.h
@@ -222,6 +222,7 @@ DEG_COMPONENT_NODE_DECLARE_GENERIC(Armature);
DEG_COMPONENT_NODE_DECLARE_GENERIC(GenericDatablock);
DEG_COMPONENT_NODE_DECLARE_NO_COW(Visibility);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Simulation);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(NTreeOutput);
/* Bone Component */
struct BoneComponentNode : public ComponentNode {
diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.cc b/source/blender/depsgraph/intern/node/deg_node_operation.cc
index eaae5d2d5dc..2d0d6854851 100644
--- a/source/blender/depsgraph/intern/node/deg_node_operation.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_operation.cc
@@ -182,6 +182,9 @@ const char *operationCodeAsString(OperationCode opcode)
return "LIGHT_UPDATE";
case OperationCode::WORLD_UPDATE:
return "WORLD_UPDATE";
+ /* Node Tree. */
+ case OperationCode::NTREE_OUTPUT:
+ return "NTREE_OUTPUT";
/* Movie clip. */
case OperationCode::MOVIECLIP_EVAL:
return "MOVIECLIP_EVAL";
diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.h b/source/blender/depsgraph/intern/node/deg_node_operation.h
index 31cbb9702ba..4abdc014946 100644
--- a/source/blender/depsgraph/intern/node/deg_node_operation.h
+++ b/source/blender/depsgraph/intern/node/deg_node_operation.h
@@ -177,6 +177,9 @@ enum class OperationCode {
LIGHT_UPDATE,
WORLD_UPDATE,
+ /* Node Tree. ----------------------------------------------------------- */
+ NTREE_OUTPUT,
+
/* Batch caches. -------------------------------------------------------- */
GEOMETRY_SELECT_UPDATE,
diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
index 315133186da..dfff45cbca5 100644
--- a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
+++ b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
@@ -99,6 +99,11 @@ static void gpencil_vfx_blur(BlurShaderFxData *fx, Object *ob, gpIterVfxData *it
return;
}
+ if ((fx->flag & FX_BLUR_DOF_MODE) && iter->pd->camera == NULL) {
+ /* No blur outside camera view (or when DOF is disabled on the camera). */
+ return;
+ }
+
DRWShadingGroup *grp;
const float s = sin(fx->rotation);
const float c = cos(fx->rotation);
@@ -108,7 +113,7 @@ static void gpencil_vfx_blur(BlurShaderFxData *fx, Object *ob, gpIterVfxData *it
DRW_view_persmat_get(NULL, persmat, false);
const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3]));
- if ((fx->flag & FX_BLUR_DOF_MODE) && iter->pd->camera != NULL) {
+ if ((fx->flag & FX_BLUR_DOF_MODE)) {
/* Compute circle of confusion size. */
float coc = (iter->pd->dof_params[0] / -w) - iter->pd->dof_params[1];
copy_v2_fl(blur_size, fabsf(coc));
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index f509898f2ee..e99e4a63786 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -879,10 +879,10 @@ EnumPropertyItem prop_driver_create_mapping_types[] = {
};
/* Filtering callback for driver mapping types enum */
-static const EnumPropertyItem *driver_mapping_type_itemsf(bContext *C,
- PointerRNA *UNUSED(owner_ptr),
- PropertyRNA *UNUSED(owner_prop),
- bool *r_free)
+static const EnumPropertyItem *driver_mapping_type_itemf(bContext *C,
+ PointerRNA *UNUSED(owner_ptr),
+ PropertyRNA *UNUSED(owner_prop),
+ bool *r_free)
{
EnumPropertyItem *input = prop_driver_create_mapping_types;
EnumPropertyItem *item = NULL;
@@ -1039,7 +1039,7 @@ static void UNUSED_FUNCTION(ANIM_OT_driver_button_add_menu)(wmOperatorType *ot)
0,
"Mapping Type",
"Method used to match target and driven properties");
- RNA_def_enum_funcs(ot->prop, driver_mapping_type_itemsf);
+ RNA_def_enum_funcs(ot->prop, driver_mapping_type_itemf);
}
/* Add Driver Button Operator ------------------------ */
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index dc5d71b5a1e..4fa5dee99a6 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -345,6 +345,28 @@ static bool find_fcurve_segment(FCurve *fcu,
return in_segment;
}
+/* Return a list of FCurveSegment with a start index and a length.
+ * A segment is a continuous selection of keyframes.
+ * Keys that have BEZT_FLAG_IGNORE_TAG set are treated as unselected.
+ * The caller is responsible for freeing the memory. */
+ListBase find_fcurve_segments(FCurve *fcu)
+{
+ ListBase segments = {NULL, NULL};
+ int segment_start_idx = 0;
+ int segment_len = 0;
+ int current_index = 0;
+
+ while (find_fcurve_segment(fcu, current_index, &segment_start_idx, &segment_len)) {
+ FCurveSegment *segment;
+ segment = MEM_callocN(sizeof(*segment), "FCurveSegment");
+ segment->start_index = segment_start_idx;
+ segment->length = segment_len;
+ BLI_addtail(&segments, segment);
+ current_index = segment_start_idx + segment_len;
+ }
+ return segments;
+}
+
/* ---------------- */
/* Check if the keyframe interpolation type is supported */
@@ -440,15 +462,12 @@ bool decimate_fcurve(bAnimListElem *ale, float remove_ratio, float error_sq_max)
fcu->bezt[i].f2 &= ~BEZT_FLAG_TEMP_TAG;
}
- /* Only decimate the individual selected curve segments. */
- int segment_start_idx = 0;
- int segment_len = 0;
- int current_index = 0;
-
- while (find_fcurve_segment(fcu, current_index, &segment_start_idx, &segment_len)) {
- decimate_fcurve_segment(fcu, segment_start_idx, segment_len, remove_ratio, error_sq_max);
- current_index = segment_start_idx + segment_len;
+ ListBase segments = find_fcurve_segments(fcu);
+ LISTBASE_FOREACH (FCurveSegment *, segment, &segments) {
+ decimate_fcurve_segment(
+ fcu, segment->start_index, segment->length, remove_ratio, error_sq_max);
}
+ BLI_freelistN(&segments);
uint old_totvert = fcu->totvert;
fcu->bezt = NULL;
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 772fe8f3196..8bd6c9f54fd 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -160,7 +160,7 @@ static bool pose_has_protected_selected(Object *ob, short warn)
bArmature *arm = ob->data;
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone && (pchan->bone->layer & arm->layer)) {
+ if (pchan->bone && BKE_pose_is_layer_visible(arm, pchan)) {
if (pchan->bone->layer & arm->layer_protected) {
if (pchan->bone->flag & BONE_SELECTED) {
break;
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index 646356e7a45..dc96c777be0 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -1070,7 +1070,7 @@ static void poselib_apply_pose(tPoseLib_PreviewData *pld,
else if (pchan->bone) {
/* only ok if bone is visible and selected */
if ((pchan->bone->flag & BONE_SELECTED) && (pchan->bone->flag & BONE_HIDDEN_P) == 0 &&
- (pchan->bone->layer & arm->layer)) {
+ BKE_pose_is_layer_visible(arm, pchan)) {
ok = 1;
}
}
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index 17347aa57fe..0b889149f9d 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -746,7 +746,7 @@ static int pose_select_hierarchy_exec(bContext *C, wmOperator *op)
const bool add_to_sel = RNA_boolean_get(op->ptr, "extend");
bool changed = false;
- pchan_act = BKE_pose_channel_active(ob);
+ pchan_act = BKE_pose_channel_active_if_layer_visible(ob);
if (pchan_act == NULL) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/asset/intern/asset_indexer.cc b/source/blender/editors/asset/intern/asset_indexer.cc
index 4107d28b5e3..fa55560d3c8 100644
--- a/source/blender/editors/asset/intern/asset_indexer.cc
+++ b/source/blender/editors/asset/intern/asset_indexer.cc
@@ -742,16 +742,15 @@ static void update_index(const char *filename, FileIndexerEntries *entries, void
static void *init_user_data(const char *root_directory, size_t root_directory_maxlen)
{
- AssetLibraryIndex *library_index = OBJECT_GUARDED_NEW(
- AssetLibraryIndex,
- StringRef(root_directory, BLI_strnlen(root_directory, root_directory_maxlen)));
+ AssetLibraryIndex *library_index = MEM_new<AssetLibraryIndex>(
+ __func__, StringRef(root_directory, BLI_strnlen(root_directory, root_directory_maxlen)));
library_index->init_unused_index_files();
return library_index;
}
static void free_user_data(void *user_data)
{
- OBJECT_GUARDED_DELETE(user_data, AssetLibraryIndex);
+ MEM_delete((AssetLibraryIndex *)user_data);
}
static void filelist_finished(void *user_data)
diff --git a/source/blender/editors/asset/intern/asset_ops.cc b/source/blender/editors/asset/intern/asset_ops.cc
index e4edff19a21..f7755aa9fea 100644
--- a/source/blender/editors/asset/intern/asset_ops.cc
+++ b/source/blender/editors/asset/intern/asset_ops.cc
@@ -934,10 +934,10 @@ static bool has_external_files(Main *bmain, struct ReportList *reports)
BKE_reportf(
callback_info.reports,
RPT_ERROR,
- "Unable to copy bundle due to %ld external dependencies; more details on the console",
- callback_info.external_files.size());
- printf("Unable to copy bundle due to %ld external dependencies:\n",
- callback_info.external_files.size());
+ "Unable to copy bundle due to %zu external dependencies; more details on the console",
+ (size_t)callback_info.external_files.size());
+ printf("Unable to copy bundle due to %zu external dependencies:\n",
+ (size_t)callback_info.external_files.size());
for (const std::string &path : callback_info.external_files) {
printf(" \"%s\"\n", path.c_str());
}
diff --git a/source/blender/editors/asset/intern/asset_temp_id_consumer.cc b/source/blender/editors/asset/intern/asset_temp_id_consumer.cc
index f136c08f129..8790c907f05 100644
--- a/source/blender/editors/asset/intern/asset_temp_id_consumer.cc
+++ b/source/blender/editors/asset/intern/asset_temp_id_consumer.cc
@@ -88,12 +88,13 @@ AssetTempIDConsumer *ED_asset_temp_id_consumer_create(const AssetHandle *handle)
}
BLI_assert(handle->file_data->asset_data != nullptr);
return reinterpret_cast<AssetTempIDConsumer *>(
- OBJECT_GUARDED_NEW(AssetTemporaryIDConsumer, *handle));
+ MEM_new<AssetTemporaryIDConsumer>(__func__, *handle));
}
void ED_asset_temp_id_consumer_free(AssetTempIDConsumer **consumer)
{
- OBJECT_GUARDED_SAFE_DELETE(*consumer, AssetTemporaryIDConsumer);
+ MEM_delete(reinterpret_cast<AssetTemporaryIDConsumer *>(*consumer));
+ *consumer = nullptr;
}
ID *ED_asset_temp_id_consumer_ensure_local_id(AssetTempIDConsumer *consumer_,
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index dabe2050b28..d1fbd3bc507 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -1567,6 +1567,12 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p,
}
bGPDspoint npt;
+ gpencil_point_to_parent_space(pt1, p->diff_mat, &npt);
+ gpencil_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]);
+
+ gpencil_point_to_parent_space(pt2, p->diff_mat, &npt);
+ gpencil_point_to_xy(&p->gsc, gps, &npt, &pc2[0], &pc2[1]);
+
if (pt0) {
gpencil_point_to_parent_space(pt0, p->diff_mat, &npt);
gpencil_point_to_xy(&p->gsc, gps, &npt, &pc0[0], &pc0[1]);
@@ -1576,12 +1582,6 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p,
copy_v2_v2_int(pc0, pc1);
}
- gpencil_point_to_parent_space(pt1, p->diff_mat, &npt);
- gpencil_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]);
-
- gpencil_point_to_parent_space(pt2, p->diff_mat, &npt);
- gpencil_point_to_xy(&p->gsc, gps, &npt, &pc2[0], &pc2[1]);
-
/* Check that point segment of the boundbox of the eraser stroke */
if (((!ELEM(V2D_IS_CLIPPED, pc0[0], pc0[1])) && BLI_rcti_isect_pt(rect, pc0[0], pc0[1])) ||
((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h
index bafe68bd28d..8a7831db0ea 100644
--- a/source/blender/editors/include/ED_keyframes_edit.h
+++ b/source/blender/editors/include/ED_keyframes_edit.h
@@ -380,6 +380,11 @@ bool delete_fcurve_keys(struct FCurve *fcu);
void clear_fcurve_keys(struct FCurve *fcu);
void duplicate_fcurve_keys(struct FCurve *fcu);
+typedef struct FCurveSegment {
+ struct FCurveSegment *next, *prev;
+ int start_index, length;
+} FCurveSegment;
+ListBase find_fcurve_segments(struct FCurve *fcu);
void clean_fcurve(struct bAnimContext *ac,
struct bAnimListElem *ale,
float thresh,
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index 5bac452c7c9..db1ba80dd3c 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -100,7 +100,7 @@ void ED_node_socket_draw(struct bNodeSocket *sock,
float scale);
void ED_node_tree_update(const struct bContext *C);
void ED_node_tag_update_id(struct ID *id);
-void ED_node_tag_update_nodetree(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node);
+
/**
* Sort nodes by selection: unselected nodes first, then selected,
* then the active node at the very end. Relative order is kept intact.
@@ -152,6 +152,26 @@ void ED_node_set_active(struct Main *bmain,
bool *r_active_texture_changed);
/**
+ * Call after one or more node trees have been changed and tagged accordingly.
+ *
+ * This function will make sure that other parts of Blender update accordingly. For example, if the
+ * node group interface changed, parent node groups have to be updated as well.
+ *
+ * Additionally, this will send notifiers and tag the depsgraph based on the changes. Depsgraph
+ * relation updates have to be triggered by the caller.
+ *
+ * \param C: Context if available. This can be null.
+ * \param bmain: Main whose data-blocks should be updated based on the changes.
+ * \param ntree: Under some circumstances the caller knows that only one node tree has
+ * changed since the last update. In this case the function may be able to skip scanning #bmain
+ * for other things that have to be changed. It may still scan #bmain if the interface of the
+ * node tree has changed.
+ */
+void ED_node_tree_propagate_change(const struct bContext *C,
+ struct Main *bmain,
+ struct bNodeTree *ntree);
+
+/**
* \param scene_owner: is the owner of the job,
* we don't use it for anything else currently so could also be a void pointer,
* but for now keep it an 'Scene' for consistency.
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 61869f3da41..35b621b0272 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -1023,8 +1023,8 @@ bool UI_context_copy_to_selected_check(PointerRNA *ptr,
return false;
}
- /* Skip non-existing properties on link. This was previously covered with the lprop != prop check
- * but we are now more permissive when it comes to ID properties, see below. */
+ /* Skip non-existing properties on link. This was previously covered with the `lprop != prop`
+ * check but we are now more permissive when it comes to ID properties, see below. */
if (lprop == NULL) {
return false;
}
@@ -1033,19 +1033,19 @@ bool UI_context_copy_to_selected_check(PointerRNA *ptr,
return false;
}
- /* Check property pointers matching
- * For ID properties, these pointers match
- * - if the property is API defined on an existing class (and they are equally named)
- * - never for ID properties on specific ID (even if they are equally named)
- * - never for NodesModifierSettings properties (even if they are equally named)
+ /* Check property pointers matching.
+ * For ID properties, these pointers match:
+ * - If the property is API defined on an existing class (and they are equally named).
+ * - Never for ID properties on specific ID (even if they are equally named).
+ * - Never for NodesModifierSettings properties (even if they are equally named).
*
* Be permissive on ID properties in the following cases:
- * - NodesModifierSettings properties
- * - (special check: only if the nodegroup matches, since the 'Input_n' properties are name
- * based and similar on potentionally very different nodegroups)
+ * - #NodesModifierSettings properties
+ * - (special check: only if the node-group matches, since the 'Input_n' properties are name
+ * based and similar on potentially very different node-groups).
* - ID properties on specific ID
- * - (no special check, copying seems OK [even if type does not match -- does not do anything
- * then])
+ * - (no special check, copying seems OK [even if type does not match -- does not do anything
+ * then])
*/
bool ignore_prop_eq = RNA_property_is_idprop(lprop) && RNA_property_is_idprop(prop);
if (RNA_struct_is_a(lptr.type, &RNA_NodesModifier) &&
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 166a8911ca1..0b57b6adcc6 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -2672,7 +2672,7 @@ static void constraint_ops_extra_draw(bContext *C, uiLayout *layout, void *con_v
static void draw_constraint_header(uiLayout *layout, Object *ob, bConstraint *con)
{
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
short proxy_protected, xco = 0, yco = 0;
// int rb_col; // UNUSED
diff --git a/source/blender/editors/interface/interface_view.cc b/source/blender/editors/interface/interface_view.cc
index 500834f4434..81b24c75020 100644
--- a/source/blender/editors/interface/interface_view.cc
+++ b/source/blender/editors/interface/interface_view.cc
@@ -60,7 +60,7 @@ AbstractTreeView *UI_block_add_view(uiBlock &block,
StringRef idname,
std::unique_ptr<AbstractTreeView> tree_view)
{
- ViewLink *view_link = OBJECT_GUARDED_NEW(ViewLink);
+ ViewLink *view_link = MEM_new<ViewLink>(__func__);
BLI_addtail(&block.views, view_link);
view_link->view = std::move(tree_view);
@@ -72,7 +72,7 @@ AbstractTreeView *UI_block_add_view(uiBlock &block,
void ui_block_free_views(uiBlock *block)
{
LISTBASE_FOREACH_MUTABLE (ViewLink *, link, &block->views) {
- OBJECT_GUARDED_DELETE(link, ViewLink);
+ MEM_delete(link);
}
}
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 5c3a8fc2277..91a512ae8e9 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -89,7 +89,7 @@ ListBase *ED_object_constraint_active_list(Object *ob)
if (ob->mode & OB_MODE_POSE) {
bPoseChannel *pchan;
- pchan = BKE_pose_channel_active(ob);
+ pchan = BKE_pose_channel_active_if_layer_visible(ob);
if (pchan) {
return &pchan->constraints;
}
@@ -2215,7 +2215,7 @@ static bool get_new_constraint_target(
bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, bool add)
{
Object *obact = ED_object_active_context(C);
- bPoseChannel *pchanact = BKE_pose_channel_active(obact);
+ bPoseChannel *pchanact = BKE_pose_channel_active_if_layer_visible(obact);
bool only_curve = false, only_mesh = false, only_ob = false;
bool found = false;
@@ -2370,7 +2370,7 @@ static int constraint_add_exec(
pchan = NULL;
}
else {
- pchan = BKE_pose_channel_active(ob);
+ pchan = BKE_pose_channel_active_if_layer_visible(ob);
/* ensure not to confuse object/pose adding */
if (pchan == NULL) {
@@ -2650,7 +2650,7 @@ void POSE_OT_constraint_add_with_targets(wmOperatorType *ot)
static int pose_ik_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
bConstraint *con = NULL;
uiPopupMenu *pup;
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index f06744068d5..38d0a044cb4 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -1638,10 +1638,10 @@ void OBJECT_OT_shade_smooth(wmOperatorType *ot)
/** \name Object Mode Set Operator
* \{ */
-static const EnumPropertyItem *object_mode_set_itemsf(bContext *C,
- PointerRNA *UNUSED(ptr),
- PropertyRNA *UNUSED(prop),
- bool *r_free)
+static const EnumPropertyItem *object_mode_set_itemf(bContext *C,
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
{
const EnumPropertyItem *input = rna_enum_object_mode_items;
EnumPropertyItem *item = NULL;
@@ -1790,7 +1790,7 @@ void OBJECT_OT_mode_set(wmOperatorType *ot)
ot->prop = RNA_def_enum(
ot->srna, "mode", rna_enum_object_mode_items, OB_MODE_OBJECT, "Mode", "");
- RNA_def_enum_funcs(ot->prop, object_mode_set_itemsf);
+ RNA_def_enum_funcs(ot->prop, object_mode_set_itemf);
RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "");
diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c
index 5065a2c00f0..51967ff35c7 100644
--- a/source/blender/editors/object/object_hook.c
+++ b/source/blender/editors/object/object_hook.c
@@ -582,7 +582,7 @@ static int add_hook_object(const bContext *C,
BLI_strncpy(hmd->subtarget, arm->act_bone->name, sizeof(hmd->subtarget));
- pchan_act = BKE_pose_channel_active(ob);
+ pchan_act = BKE_pose_channel_active_if_layer_visible(ob);
if (LIKELY(pchan_act)) {
invert_m4_m4(pose_mat, pchan_act->pose_mat);
mul_v3_m4v3(cent, ob->obmat, pchan_act->pose_mat[3]);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 811f20e82be..71d9482597d 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -583,8 +583,8 @@ bool ED_object_parent_set(ReportList *reports,
}
case PAR_BONE:
case PAR_BONE_RELATIVE:
- pchan = BKE_pose_channel_active(par);
- pchan_eval = BKE_pose_channel_active(parent_eval);
+ pchan = BKE_pose_channel_active_if_layer_visible(par);
+ pchan_eval = BKE_pose_channel_active_if_layer_visible(parent_eval);
if (pchan == NULL) {
BKE_report(reports, RPT_ERROR, "No active bone");
diff --git a/source/blender/editors/object/object_utils.c b/source/blender/editors/object/object_utils.c
index 5f85f6ea0eb..df44d840ad3 100644
--- a/source/blender/editors/object/object_utils.c
+++ b/source/blender/editors/object/object_utils.c
@@ -115,7 +115,7 @@ bool ED_object_calc_active_center_for_posemode(Object *ob,
const bool select_only,
float r_center[3])
{
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
if (pchan && (!select_only || (pchan->bone->flag & BONE_SELECTED))) {
copy_v3_v3(r_center, pchan->pose_head);
return true;
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 29d829dc131..1a9b72c1fab 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -50,6 +50,7 @@
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -725,7 +726,8 @@ static void render_endjob(void *rjv)
rj->scene->r.scemode &= ~R_NO_FRAME_UPDATE;
if (rj->single_layer) {
- nodeUpdateID(rj->scene->nodetree, &rj->scene->id);
+ BKE_ntree_update_tag_id_changed(rj->main, &rj->scene->id);
+ BKE_ntree_update_main(rj->main, NULL);
WM_main_add_notifier(NC_NODE | NA_EDITED, rj->scene);
}
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index 304205d0cc4..04df90bf912 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -501,7 +501,7 @@ static eContextResult screen_ctx_active_pose_bone(const bContext *C, bContextDat
Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
Object *obpose = BKE_object_pose_armature_get(obact);
- bPoseChannel *pchan = BKE_pose_channel_active(obpose);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(obpose);
if (pchan) {
CTX_data_pointer_set(result, &obpose->id, &RNA_PoseBone, pchan);
return CTX_RESULT_OK;
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index b826ff8701d..517125f016e 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -59,6 +59,7 @@ set(SRC
sculpt.c
sculpt_automasking.c
sculpt_boundary.c
+ sculpt_brushes.c
sculpt_cloth.c
sculpt_detail.c
sculpt_dyntopo.c
@@ -71,6 +72,7 @@ set(SRC
sculpt_mask_expand.c
sculpt_mask_init.c
sculpt_multiplane_scrape.c
+ sculpt_ops.c
sculpt_paint_color.c
sculpt_pose.c
sculpt_smooth.c
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 7df5848e068..8a5d75d5f77 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -6623,7 +6623,7 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
}
}
- ntreeUpdateTree(CTX_data_main(C), ntree);
+ ED_node_tree_propagate_change(C, bmain, ntree);
/* In case we added more than one node, position them too. */
nodePositionPropagate(out_node);
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 90887b9fc39..09013ea00f4 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -25,6 +25,8 @@
#include "BKE_paint.h"
+#include "BLI_compiler_compat.h"
+#include "BLI_math.h"
#include "BLI_rect.h"
#include "DNA_scene_types.h"
@@ -404,8 +406,61 @@ bool facemask_paint_poll(struct bContext *C);
/**
* Uses symm to selectively flip any axis of a coordinate.
*/
-void flip_v3_v3(float out[3], const float in[3], const enum ePaintSymmetryFlags symm);
-void flip_qt_qt(float out[4], const float in[4], const enum ePaintSymmetryFlags symm);
+
+BLI_INLINE void flip_v3_v3(float out[3], const float in[3], const ePaintSymmetryFlags symm)
+{
+ if (symm & PAINT_SYMM_X) {
+ out[0] = -in[0];
+ }
+ else {
+ out[0] = in[0];
+ }
+ if (symm & PAINT_SYMM_Y) {
+ out[1] = -in[1];
+ }
+ else {
+ out[1] = in[1];
+ }
+ if (symm & PAINT_SYMM_Z) {
+ out[2] = -in[2];
+ }
+ else {
+ out[2] = in[2];
+ }
+}
+
+BLI_INLINE void flip_qt_qt(float out[4], const float in[4], const ePaintSymmetryFlags symm)
+{
+ float axis[3], angle;
+
+ quat_to_axis_angle(axis, &angle, in);
+ normalize_v3(axis);
+
+ if (symm & PAINT_SYMM_X) {
+ axis[0] *= -1.0f;
+ angle *= -1.0f;
+ }
+ if (symm & PAINT_SYMM_Y) {
+ axis[1] *= -1.0f;
+ angle *= -1.0f;
+ }
+ if (symm & PAINT_SYMM_Z) {
+ axis[2] *= -1.0f;
+ angle *= -1.0f;
+ }
+
+ axis_angle_normalized_to_quat(out, axis, angle);
+}
+
+BLI_INLINE void flip_v3(float v[3], const ePaintSymmetryFlags symm)
+{
+ flip_v3_v3(v, v, symm);
+}
+
+BLI_INLINE void flip_qt(float quat[4], const ePaintSymmetryFlags symm)
+{
+ flip_qt_qt(quat, quat, symm);
+}
/* stroke operator */
typedef enum BrushStrokeMode {
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 541893f7957..95a0aba1ffb 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -397,51 +397,6 @@ static Image *imapaint_face_image(Object *ob, Mesh *me, int face_index)
return ima;
}
-void flip_v3_v3(float out[3], const float in[3], const ePaintSymmetryFlags symm)
-{
- if (symm & PAINT_SYMM_X) {
- out[0] = -in[0];
- }
- else {
- out[0] = in[0];
- }
- if (symm & PAINT_SYMM_Y) {
- out[1] = -in[1];
- }
- else {
- out[1] = in[1];
- }
- if (symm & PAINT_SYMM_Z) {
- out[2] = -in[2];
- }
- else {
- out[2] = in[2];
- }
-}
-
-void flip_qt_qt(float out[4], const float in[4], const ePaintSymmetryFlags symm)
-{
- float axis[3], angle;
-
- quat_to_axis_angle(axis, &angle, in);
- normalize_v3(axis);
-
- if (symm & PAINT_SYMM_X) {
- axis[0] *= -1.0f;
- angle *= -1.0f;
- }
- if (symm & PAINT_SYMM_Y) {
- axis[1] *= -1.0f;
- angle *= -1.0f;
- }
- if (symm & PAINT_SYMM_Z) {
- axis[2] *= -1.0f;
- angle *= -1.0f;
- }
-
- axis_angle_normalized_to_quat(out, axis, angle);
-}
-
void paint_sample_color(
bContext *C, ARegion *region, int x, int y, bool texpaint_proj, bool use_palette)
{
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index b764d0e1b5b..ea13bb7adca 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -1329,103 +1329,6 @@ static void sculpt_rake_data_update(struct SculptRakeData *srd, const float co[3
}
}
-static void sculpt_rake_rotate(const SculptSession *ss,
- const float sculpt_co[3],
- const float v_co[3],
- float factor,
- float r_delta[3])
-{
- float vec_rot[3];
-
-#if 0
- /* lerp */
- sub_v3_v3v3(vec_rot, v_co, sculpt_co);
- mul_qt_v3(ss->cache->rake_rotation_symmetry, vec_rot);
- add_v3_v3(vec_rot, sculpt_co);
- sub_v3_v3v3(r_delta, vec_rot, v_co);
- mul_v3_fl(r_delta, factor);
-#else
- /* slerp */
- float q_interp[4];
- sub_v3_v3v3(vec_rot, v_co, sculpt_co);
-
- copy_qt_qt(q_interp, ss->cache->rake_rotation_symmetry);
- pow_qt_fl_normalized(q_interp, factor);
- mul_qt_v3(q_interp, vec_rot);
-
- add_v3_v3(vec_rot, sculpt_co);
- sub_v3_v3v3(r_delta, vec_rot, v_co);
-#endif
-}
-
-/**
- * Align the grab delta to the brush normal.
- *
- * \param grab_delta: Typically from `ss->cache->grab_delta_symmetry`.
- */
-static void sculpt_project_v3_normal_align(SculptSession *ss,
- const float normal_weight,
- float grab_delta[3])
-{
- /* Signed to support grabbing in (to make a hole) as well as out. */
- const float len_signed = dot_v3v3(ss->cache->sculpt_normal_symm, grab_delta);
-
- /* This scale effectively projects the offset so dragging follows the cursor,
- * as the normal points towards the view, the scale increases. */
- float len_view_scale;
- {
- float view_aligned_normal[3];
- project_plane_v3_v3v3(
- view_aligned_normal, ss->cache->sculpt_normal_symm, ss->cache->view_normal);
- len_view_scale = fabsf(dot_v3v3(view_aligned_normal, ss->cache->sculpt_normal_symm));
- len_view_scale = (len_view_scale > FLT_EPSILON) ? 1.0f / len_view_scale : 1.0f;
- }
-
- mul_v3_fl(grab_delta, 1.0f - normal_weight);
- madd_v3_v3fl(
- grab_delta, ss->cache->sculpt_normal_symm, (len_signed * normal_weight) * len_view_scale);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name SculptProjectVector
- *
- * Fast-path for #project_plane_v3_v3v3
- * \{ */
-
-typedef struct SculptProjectVector {
- float plane[3];
- float len_sq;
- float len_sq_inv_neg;
- bool is_valid;
-
-} SculptProjectVector;
-
-/**
- * \param plane: Direction, can be any length.
- */
-static void sculpt_project_v3_cache_init(SculptProjectVector *spvc, const float plane[3])
-{
- copy_v3_v3(spvc->plane, plane);
- spvc->len_sq = len_squared_v3(spvc->plane);
- spvc->is_valid = (spvc->len_sq > FLT_EPSILON);
- spvc->len_sq_inv_neg = (spvc->is_valid) ? -1.0f / spvc->len_sq : 0.0f;
-}
-
-/**
- * Calculate the projection.
- */
-static void sculpt_project_v3(const SculptProjectVector *spvc, const float vec[3], float r_vec[3])
-{
-#if 0
- project_plane_v3_v3v3(r_vec, vec, spvc->plane);
-#else
- /* inline the projection, cache `-1.0 / dot_v3_v3(v_proj, v_proj)` */
- madd_v3_v3fl(r_vec, spvc->plane, dot_v3v3(vec, spvc->plane) * spvc->len_sq_inv_neg);
-#endif
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -1835,15 +1738,6 @@ static bool sculpt_brush_test_cyl(SculptBrushTest *test,
/* ===== Sculpting =====
*/
-static void flip_v3(float v[3], const ePaintSymmetryFlags symm)
-{
- flip_v3_v3(v, v, symm);
-}
-
-static void flip_qt(float quat[4], const ePaintSymmetryFlags symm)
-{
- flip_qt_qt(quat, quat, symm);
-}
static float calc_overlap(StrokeCache *cache, const char symm, const char axis, const float angle)
{
@@ -1913,9 +1807,9 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache)
* (optionally using original coordinates).
*
* Functions are:
- * - #calc_area_center
- * - #calc_area_normal
- * - #calc_area_normal_and_center
+ * - #SCULPT_calc_area_center
+ * - #SCULPT_calc_area_normal
+ * - #SCULPT_calc_area_normal_and_center
*
* \note These are all _very_ similar, when changing one, check others.
* \{ */
@@ -2137,7 +2031,7 @@ static void calc_area_normal_and_center_reduce(const void *__restrict UNUSED(use
add_v2_v2_int(join->count_co, anctd->count_co);
}
-static void calc_area_center(
+void SCULPT_calc_area_center(
Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_co[3])
{
const Brush *brush = BKE_paint_brush(&sd->paint);
@@ -2238,7 +2132,7 @@ bool SCULPT_pbvh_calc_area_normal(const Brush *brush,
* This calculates flatten center and area normal together,
* amortizing the memory bandwidth and loop overhead to calculate both at the same time.
*/
-static void calc_area_normal_and_center(
+void SCULPT_calc_area_normal_and_center(
Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3])
{
const Brush *brush = BKE_paint_brush(&sd->paint);
@@ -2856,10 +2750,6 @@ static void update_brush_local_mat(Sculpt *sd, Object *ob)
/** \} */
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Topology Rake (Shared Utility)
- * \{ */
-
typedef struct {
SculptSession *ss;
const float *ray_start;
@@ -2885,1295 +2775,6 @@ typedef struct {
bool original;
} SculptFindNearestToRayData;
-static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- Sculpt *sd = data->sd;
- const Brush *brush = data->brush;
-
- float direction[3];
- copy_v3_v3(direction, ss->cache->grab_delta_symmetry);
-
- float tmp[3];
- mul_v3_v3fl(
- tmp, ss->cache->sculpt_normal_symm, dot_v3v3(ss->cache->sculpt_normal_symm, direction));
- sub_v3_v3(direction, tmp);
- normalize_v3(direction);
-
- /* Cancel if there's no grab data. */
- if (is_zero_v3(direction)) {
- return;
- }
-
- const float bstrength = clamp_f(data->strength, 0.0f, 1.0f);
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- const float fade =
- bstrength *
- SCULPT_brush_strength_factor(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, vd.index, thread_id) *
- ss->cache->pressure;
-
- float avg[3], val[3];
-
- SCULPT_bmesh_four_neighbor_average(avg, direction, vd.bm_vert);
-
- sub_v3_v3v3(val, avg, vd.co);
-
- madd_v3_v3v3fl(val, vd.co, val, fade);
-
- SCULPT_clip(sd, ss, vd.co, val);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void bmesh_topology_rake(
- Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, float bstrength)
-{
- Brush *brush = BKE_paint_brush(&sd->paint);
- const float strength = clamp_f(bstrength, 0.0f, 1.0f);
-
- /* Interactions increase both strength and quality. */
- const int iterations = 3;
-
- int iteration;
- const int count = iterations * strength + 1;
- const float factor = iterations * strength / count;
-
- for (iteration = 0; iteration <= count; iteration++) {
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .strength = factor,
- };
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
-
- BLI_task_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings);
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Mask Brush
- * \{ */
-
-static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float bstrength = ss->cache->bstrength;
-
- PBVHVertexIter vd;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
-
- const float fade = SCULPT_brush_strength_factor(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id);
-
- if (bstrength > 0.0f) {
- (*vd.mask) += fade * bstrength * (1.0f - *vd.mask);
- }
- else {
- (*vd.mask) += fade * bstrength * (*vd.mask);
- }
- *vd.mask = clamp_f(*vd.mask, 0.0f, 1.0f);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- BKE_pbvh_vertex_iter_end;
- }
-}
-
-static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings);
-}
-
-static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- switch ((BrushMaskTool)brush->mask_tool) {
- case BRUSH_MASK_DRAW:
- do_mask_brush_draw(sd, ob, nodes, totnode);
- break;
- case BRUSH_MASK_SMOOTH:
- SCULPT_smooth(sd, ob, nodes, totnode, ss->cache->bstrength, true);
- break;
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Multires Displacement Eraser Brush
- * \{ */
-
-static void do_displacement_eraser_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f);
-
- float(*proxy)[3] = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- float limit_co[3];
- float disp[3];
- SCULPT_vertex_limit_surface_get(ss, vd.index, limit_co);
- sub_v3_v3v3(disp, limit_co, vd.co);
- mul_v3_v3fl(proxy[vd.i], disp, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_displacement_eraser_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- Brush *brush = BKE_paint_brush(&sd->paint);
- BKE_curvemapping_init(brush->curve);
-
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_displacement_eraser_brush_task_cb_ex, &settings);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Multires Displacement Smear Brush
- * \{ */
-
-static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f);
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- float current_disp[3];
- float current_disp_norm[3];
- float interp_limit_surface_disp[3];
-
- copy_v3_v3(interp_limit_surface_disp, ss->cache->prev_displacement[vd.index]);
-
- switch (brush->smear_deform_type) {
- case BRUSH_SMEAR_DEFORM_DRAG:
- sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location);
- break;
- case BRUSH_SMEAR_DEFORM_PINCH:
- sub_v3_v3v3(current_disp, ss->cache->location, vd.co);
- break;
- case BRUSH_SMEAR_DEFORM_EXPAND:
- sub_v3_v3v3(current_disp, vd.co, ss->cache->location);
- break;
- }
-
- normalize_v3_v3(current_disp_norm, current_disp);
- mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
-
- float weights_accum = 1.0f;
-
- SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
- float vertex_disp[3];
- float vertex_disp_norm[3];
- float neighbor_limit_co[3];
- SCULPT_vertex_limit_surface_get(ss, ni.index, neighbor_limit_co);
- sub_v3_v3v3(vertex_disp,
- ss->cache->limit_surface_co[ni.index],
- ss->cache->limit_surface_co[vd.index]);
- const float *neighbor_limit_surface_disp = ss->cache->prev_displacement[ni.index];
- normalize_v3_v3(vertex_disp_norm, vertex_disp);
-
- if (dot_v3v3(current_disp_norm, vertex_disp_norm) >= 0.0f) {
- continue;
- }
-
- const float disp_interp = clamp_f(
- -dot_v3v3(current_disp_norm, vertex_disp_norm), 0.0f, 1.0f);
- madd_v3_v3fl(interp_limit_surface_disp, neighbor_limit_surface_disp, disp_interp);
- weights_accum += disp_interp;
- }
- SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
-
- mul_v3_fl(interp_limit_surface_disp, 1.0f / weights_accum);
-
- float new_co[3];
- add_v3_v3v3(new_co, ss->cache->limit_surface_co[vd.index], interp_limit_surface_disp);
- interp_v3_v3v3(vd.co, vd.co, new_co, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_displacement_smear_store_prev_disp_task_cb_ex(
- void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
-
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- sub_v3_v3v3(ss->cache->prev_displacement[vd.index],
- SCULPT_vertex_co_get(ss, vd.index),
- ss->cache->limit_surface_co[vd.index]);
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_displacement_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- Brush *brush = BKE_paint_brush(&sd->paint);
- SculptSession *ss = ob->sculpt;
-
- BKE_curvemapping_init(brush->curve);
-
- const int totvert = SCULPT_vertex_count_get(ss);
- if (!ss->cache->prev_displacement) {
- ss->cache->prev_displacement = MEM_malloc_arrayN(
- totvert, sizeof(float[3]), "prev displacement");
- ss->cache->limit_surface_co = MEM_malloc_arrayN(totvert, sizeof(float[3]), "limit surface co");
- for (int i = 0; i < totvert; i++) {
- SCULPT_vertex_limit_surface_get(ss, i, ss->cache->limit_surface_co[i]);
- sub_v3_v3v3(ss->cache->prev_displacement[i],
- SCULPT_vertex_co_get(ss, i),
- ss->cache->limit_surface_co[i]);
- }
- }
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(
- 0, totnode, &data, do_displacement_smear_store_prev_disp_task_cb_ex, &settings);
- BLI_task_parallel_range(0, totnode, &data, do_displacement_smear_brush_task_cb_ex, &settings);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Draw Brush
- * \{ */
-
-static void do_draw_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *offset = data->offset;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- /* Offset vertex. */
- const float fade = SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], offset, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float offset[3];
- const float bstrength = ss->cache->bstrength;
-
- /* Offset with as much as possible factored in already. */
- float effective_normal[3];
- SCULPT_tilt_effective_normal_get(ss, brush, effective_normal);
- mul_v3_v3fl(offset, effective_normal, ss->cache->radius);
- mul_v3_v3(offset, ss->cache->scale);
- mul_v3_fl(offset, bstrength);
-
- /* XXX: this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise
- * initialize before threads so they can do curve mapping. */
- BKE_curvemapping_init(brush->curve);
-
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .offset = offset,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings);
-}
-
-static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *offset = data->offset;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float(*proxy)[3];
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- /* Offset vertex. */
- const float fade = SCULPT_brush_strength_factor(ss,
- brush,
- orig_data.co,
- sqrtf(test.dist),
- orig_data.no,
- NULL,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], offset, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float offset[3];
- const float bstrength = ss->cache->bstrength;
-
- /* Offset with as much as possible factored in already. */
- float effective_normal[3];
- SCULPT_tilt_effective_normal_get(ss, brush, effective_normal);
- mul_v3_v3fl(offset, effective_normal, ss->cache->radius);
- mul_v3_v3(offset, ss->cache->scale);
- mul_v3_fl(offset, bstrength);
-
- /* XXX: this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise
- * initialize before threads so they can do curve mapping. */
- BKE_curvemapping_init(brush->curve);
-
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .offset = offset,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Topology Brush
- * \{ */
-
-static void do_topology_slide_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float(*proxy)[3];
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- const float fade = SCULPT_brush_strength_factor(ss,
- brush,
- orig_data.co,
- sqrtf(test.dist),
- orig_data.no,
- NULL,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
- float current_disp[3];
- float current_disp_norm[3];
- float final_disp[3] = {0.0f, 0.0f, 0.0f};
-
- switch (brush->slide_deform_type) {
- case BRUSH_SLIDE_DEFORM_DRAG:
- sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location);
- break;
- case BRUSH_SLIDE_DEFORM_PINCH:
- sub_v3_v3v3(current_disp, ss->cache->location, vd.co);
- break;
- case BRUSH_SLIDE_DEFORM_EXPAND:
- sub_v3_v3v3(current_disp, vd.co, ss->cache->location);
- break;
- }
-
- normalize_v3_v3(current_disp_norm, current_disp);
- mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
-
- SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
- float vertex_disp[3];
- float vertex_disp_norm[3];
- sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.index), vd.co);
- normalize_v3_v3(vertex_disp_norm, vertex_disp);
- if (dot_v3v3(current_disp_norm, vertex_disp_norm) > 0.0f) {
- madd_v3_v3fl(final_disp, vertex_disp_norm, dot_v3v3(current_disp, vertex_disp));
- }
- }
- SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
-
- mul_v3_v3fl(proxy[vd.i], final_disp, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-void SCULPT_relax_vertex(SculptSession *ss,
- PBVHVertexIter *vd,
- float factor,
- bool filter_boundary_face_sets,
- float *r_final_pos)
-{
- float smooth_pos[3];
- float final_disp[3];
- float boundary_normal[3];
- int avg_count = 0;
- int neighbor_count = 0;
- zero_v3(smooth_pos);
- zero_v3(boundary_normal);
- const bool is_boundary = SCULPT_vertex_is_boundary(ss, vd->index);
-
- SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->index, ni) {
- neighbor_count++;
- if (!filter_boundary_face_sets ||
- (filter_boundary_face_sets && !SCULPT_vertex_has_unique_face_set(ss, ni.index))) {
-
- /* When the vertex to relax is boundary, use only connected boundary vertices for the average
- * position. */
- if (is_boundary) {
- if (!SCULPT_vertex_is_boundary(ss, ni.index)) {
- continue;
- }
- add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index));
- avg_count++;
-
- /* Calculate a normal for the constraint plane using the edges of the boundary. */
- float to_neighbor[3];
- sub_v3_v3v3(to_neighbor, SCULPT_vertex_co_get(ss, ni.index), vd->co);
- normalize_v3(to_neighbor);
- add_v3_v3(boundary_normal, to_neighbor);
- }
- else {
- add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index));
- avg_count++;
- }
- }
- }
- SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
-
- /* Don't modify corner vertices. */
- if (neighbor_count <= 2) {
- copy_v3_v3(r_final_pos, vd->co);
- return;
- }
-
- if (avg_count > 0) {
- mul_v3_fl(smooth_pos, 1.0f / avg_count);
- }
- else {
- copy_v3_v3(r_final_pos, vd->co);
- return;
- }
-
- float plane[4];
- float smooth_closest_plane[3];
- float vno[3];
-
- if (is_boundary && avg_count == 2) {
- normalize_v3_v3(vno, boundary_normal);
- }
- else {
- SCULPT_vertex_normal_get(ss, vd->index, vno);
- }
-
- if (is_zero_v3(vno)) {
- copy_v3_v3(r_final_pos, vd->co);
- return;
- }
-
- plane_from_point_normal_v3(plane, vd->co, vno);
- closest_to_plane_v3(smooth_closest_plane, plane, smooth_pos);
- sub_v3_v3v3(final_disp, smooth_closest_plane, vd->co);
-
- mul_v3_fl(final_disp, factor);
- add_v3_v3v3(r_final_pos, vd->co, final_disp);
-}
-
-static void do_topology_relax_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float bstrength = ss->cache->bstrength;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n]);
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- const float fade = SCULPT_brush_strength_factor(ss,
- brush,
- orig_data.co,
- sqrtf(test.dist),
- orig_data.no,
- NULL,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- SCULPT_relax_vertex(ss, &vd, fade * bstrength, false, vd.co);
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_slide_relax_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
- return;
- }
-
- BKE_curvemapping_init(brush->curve);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- if (ss->cache->alt_smooth) {
- SCULPT_boundary_info_ensure(ob);
- for (int i = 0; i < 4; i++) {
- BLI_task_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings);
- }
- }
- else {
- BLI_task_parallel_range(0, totnode, &data, do_topology_slide_task_cb_ex, &settings);
- }
-}
-
-static void calc_sculpt_plane(
- Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3])
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- if (SCULPT_stroke_is_main_symmetry_pass(ss->cache) &&
- (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache) ||
- !(brush->flag & BRUSH_ORIGINAL_PLANE) || !(brush->flag & BRUSH_ORIGINAL_NORMAL))) {
- switch (brush->sculpt_plane) {
- case SCULPT_DISP_DIR_VIEW:
- copy_v3_v3(r_area_no, ss->cache->true_view_normal);
- break;
-
- case SCULPT_DISP_DIR_X:
- ARRAY_SET_ITEMS(r_area_no, 1.0f, 0.0f, 0.0f);
- break;
-
- case SCULPT_DISP_DIR_Y:
- ARRAY_SET_ITEMS(r_area_no, 0.0f, 1.0f, 0.0f);
- break;
-
- case SCULPT_DISP_DIR_Z:
- ARRAY_SET_ITEMS(r_area_no, 0.0f, 0.0f, 1.0f);
- break;
-
- case SCULPT_DISP_DIR_AREA:
- calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co);
- if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- project_plane_v3_v3v3(r_area_no, r_area_no, ss->cache->view_normal);
- normalize_v3(r_area_no);
- }
- break;
-
- default:
- break;
- }
-
- /* For flatten center. */
- /* Flatten center has not been calculated yet if we are not using the area normal. */
- if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA) {
- calc_area_center(sd, ob, nodes, totnode, r_area_co);
- }
-
- /* For area normal. */
- if ((!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) &&
- (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
- copy_v3_v3(r_area_no, ss->cache->sculpt_normal);
- }
- else {
- copy_v3_v3(ss->cache->sculpt_normal, r_area_no);
- }
-
- /* For flatten center. */
- if ((!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) &&
- (brush->flag & BRUSH_ORIGINAL_PLANE)) {
- copy_v3_v3(r_area_co, ss->cache->last_center);
- }
- else {
- copy_v3_v3(ss->cache->last_center, r_area_co);
- }
- }
- else {
- /* For area normal. */
- copy_v3_v3(r_area_no, ss->cache->sculpt_normal);
-
- /* For flatten center. */
- copy_v3_v3(r_area_co, ss->cache->last_center);
-
- /* For area normal. */
- flip_v3(r_area_no, ss->cache->mirror_symmetry_pass);
-
- /* For flatten center. */
- flip_v3(r_area_co, ss->cache->mirror_symmetry_pass);
-
- /* For area normal. */
- mul_m4_v3(ss->cache->symm_rot_mat, r_area_no);
-
- /* For flatten center. */
- mul_m4_v3(ss->cache->symm_rot_mat, r_area_co);
-
- /* Shift the plane for the current tile. */
- add_v3_v3(r_area_co, ss->cache->plane_offset);
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Crease & Blob Brush
- * \{ */
-
-/**
- * Used for 'SCULPT_TOOL_CREASE' and 'SCULPT_TOOL_BLOB'
- */
-static void do_crease_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- SculptProjectVector *spvc = data->spvc;
- const float flippedbstrength = data->flippedbstrength;
- const float *offset = data->offset;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- /* Offset vertex. */
- const float fade = SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
- float val1[3];
- float val2[3];
-
- /* First we pinch. */
- sub_v3_v3v3(val1, test.location, vd.co);
- if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- project_plane_v3_v3v3(val1, val1, ss->cache->view_normal);
- }
-
- mul_v3_fl(val1, fade * flippedbstrength);
-
- sculpt_project_v3(spvc, val1, val1);
-
- /* Then we draw. */
- mul_v3_v3fl(val2, offset, fade);
-
- add_v3_v3v3(proxy[vd.i], val1, val2);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- const Scene *scene = ss->cache->vc->scene;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float offset[3];
- float bstrength = ss->cache->bstrength;
- float flippedbstrength, crease_correction;
- float brush_alpha;
-
- SculptProjectVector spvc;
-
- /* Offset with as much as possible factored in already. */
- mul_v3_v3fl(offset, ss->cache->sculpt_normal_symm, ss->cache->radius);
- mul_v3_v3(offset, ss->cache->scale);
- mul_v3_fl(offset, bstrength);
-
- /* We divide out the squared alpha and multiply by the squared crease
- * to give us the pinch strength. */
- crease_correction = brush->crease_pinch_factor * brush->crease_pinch_factor;
- brush_alpha = BKE_brush_alpha_get(scene, brush);
- if (brush_alpha > 0.0f) {
- crease_correction /= brush_alpha * brush_alpha;
- }
-
- /* We always want crease to pinch or blob to relax even when draw is negative. */
- flippedbstrength = (bstrength < 0.0f) ? -crease_correction * bstrength :
- crease_correction * bstrength;
-
- if (brush->sculpt_tool == SCULPT_TOOL_BLOB) {
- flippedbstrength *= -1.0f;
- }
-
- /* Use surface normal for 'spvc', so the vertices are pinched towards a line instead of a single
- * point. Without this we get a 'flat' surface surrounding the pinch. */
- sculpt_project_v3_cache_init(&spvc, ss->cache->sculpt_normal_symm);
-
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .spvc = &spvc,
- .offset = offset,
- .flippedbstrength = flippedbstrength,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings);
-}
-
-static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- float(*stroke_xz)[3] = data->stroke_xz;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- float x_object_space[3];
- float z_object_space[3];
- copy_v3_v3(x_object_space, stroke_xz[0]);
- copy_v3_v3(z_object_space, stroke_xz[1]);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
- float disp_center[3];
- float x_disp[3];
- float z_disp[3];
- /* Calculate displacement from the vertex to the brush center. */
- sub_v3_v3v3(disp_center, test.location, vd.co);
-
- /* Project the displacement into the X vector (aligned to the stroke). */
- mul_v3_v3fl(x_disp, x_object_space, dot_v3v3(disp_center, x_object_space));
-
- /* Project the displacement into the Z vector (aligned to the surface normal). */
- mul_v3_v3fl(z_disp, z_object_space, dot_v3v3(disp_center, z_object_space));
-
- /* Add the two projected vectors to calculate the final displacement.
- * The Y component is removed. */
- add_v3_v3v3(disp_center, x_disp, z_disp);
-
- if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- project_plane_v3_v3v3(disp_center, disp_center, ss->cache->view_normal);
- }
- mul_v3_v3fl(proxy[vd.i], disp_center, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- float area_no[3];
- float area_co[3];
-
- float mat[4][4];
- calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
-
- /* delay the first daub because grab delta is not setup */
- if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
- return;
- }
-
- if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
- return;
- }
-
- /* Initialize `mat`. */
- cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
- mat[0][3] = 0.0f;
- cross_v3_v3v3(mat[1], area_no, mat[0]);
- mat[1][3] = 0.0f;
- copy_v3_v3(mat[2], area_no);
- mat[2][3] = 0.0f;
- copy_v3_v3(mat[3], ss->cache->location);
- mat[3][3] = 1.0f;
- normalize_m4(mat);
-
- float stroke_xz[2][3];
- normalize_v3_v3(stroke_xz[0], mat[0]);
- normalize_v3_v3(stroke_xz[1], mat[2]);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .stroke_xz = stroke_xz,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings);
-}
-
-static void do_grab_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *grab_delta = data->grab_delta;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- const bool grab_silhouette = brush->flag2 & BRUSH_GRAB_SILHOUETTE;
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
-
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- orig_data.co,
- sqrtf(test.dist),
- orig_data.no,
- NULL,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- if (grab_silhouette) {
- float silhouette_test_dir[3];
- normalize_v3_v3(silhouette_test_dir, grab_delta);
- if (dot_v3v3(ss->cache->initial_normal, ss->cache->grab_delta_symmetry) < 0.0f) {
- mul_v3_fl(silhouette_test_dir, -1.0f);
- }
- float vno[3];
- normal_short_to_float_v3(vno, orig_data.no);
- fade *= max_ff(dot_v3v3(vno, silhouette_test_dir), 0.0f);
- }
-
- mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float grab_delta[3];
-
- copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
-
- if (ss->cache->normal_weight > 0.0f) {
- sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
- }
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .grab_delta = grab_delta,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings);
-}
-
-static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *grab_delta = data->grab_delta;
- const float *location = ss->cache->location;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float(*proxy)[3];
-
- const float bstrength = ss->cache->bstrength;
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- float dir;
- if (ss->cache->mouse[0] > ss->cache->initial_mouse[0]) {
- dir = 1.0f;
- }
- else {
- dir = -1.0f;
- }
-
- if (brush->elastic_deform_type == BRUSH_ELASTIC_DEFORM_TWIST) {
- int symm = ss->cache->mirror_symmetry_pass;
- if (ELEM(symm, 1, 2, 4, 7)) {
- dir = -dir;
- }
- }
-
- KelvinletParams params;
- float force = len_v3(grab_delta) * dir * bstrength;
- BKE_kelvinlet_init_params(
- &params, ss->cache->radius, force, 1.0f, brush->elastic_deform_volume_preservation);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
- float final_disp[3];
- switch (brush->elastic_deform_type) {
- case BRUSH_ELASTIC_DEFORM_GRAB:
- BKE_kelvinlet_grab(final_disp, &params, orig_data.co, location, grab_delta);
- mul_v3_fl(final_disp, bstrength * 20.0f);
- break;
- case BRUSH_ELASTIC_DEFORM_GRAB_BISCALE: {
- BKE_kelvinlet_grab_biscale(final_disp, &params, orig_data.co, location, grab_delta);
- mul_v3_fl(final_disp, bstrength * 20.0f);
- break;
- }
- case BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE: {
- BKE_kelvinlet_grab_triscale(final_disp, &params, orig_data.co, location, grab_delta);
- mul_v3_fl(final_disp, bstrength * 20.0f);
- break;
- }
- case BRUSH_ELASTIC_DEFORM_SCALE:
- BKE_kelvinlet_scale(
- final_disp, &params, orig_data.co, location, ss->cache->sculpt_normal_symm);
- break;
- case BRUSH_ELASTIC_DEFORM_TWIST:
- BKE_kelvinlet_twist(
- final_disp, &params, orig_data.co, location, ss->cache->sculpt_normal_symm);
- break;
- }
-
- if (vd.mask) {
- mul_v3_fl(final_disp, 1.0f - *vd.mask);
- }
-
- mul_v3_fl(final_disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index));
-
- copy_v3_v3(proxy[vd.i], final_disp);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float grab_delta[3];
-
- copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
-
- if (ss->cache->normal_weight > 0.0f) {
- sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
- }
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .grab_delta = grab_delta,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings);
-}
-
ePaintSymmetryAreas SCULPT_get_vertex_symm_area(const float co[3])
{
ePaintSymmetryAreas symm_area = PAINT_SYMM_AREA_DEFAULT;
@@ -4257,7 +2858,7 @@ void SCULPT_calc_brush_plane(
break;
case SCULPT_DISP_DIR_AREA:
- calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co);
+ SCULPT_calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co);
if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
project_plane_v3_v3v3(r_area_no, r_area_no, ss->cache->view_normal);
normalize_v3(r_area_no);
@@ -4271,7 +2872,7 @@ void SCULPT_calc_brush_plane(
/* For flatten center. */
/* Flatten center has not been calculated yet if we are not using the area normal. */
if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA) {
- calc_area_center(sd, ob, nodes, totnode, r_area_co);
+ SCULPT_calc_area_center(sd, ob, nodes, totnode, r_area_co);
}
/* For area normal. */
@@ -4316,564 +2917,12 @@ void SCULPT_calc_brush_plane(
}
}
-static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *cono = data->cono;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], cono, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float grab_delta[3];
- float tmp[3], cono[3];
-
- copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
-
- cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
- cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .cono = cono,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings);
-}
-
-static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- SculptProjectVector *spvc = data->spvc;
- const float *grab_delta = data->grab_delta;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
- const bool do_rake_rotation = ss->cache->is_rake_rotation_valid;
- const bool do_pinch = (brush->crease_pinch_factor != 0.5f);
- const float pinch = do_pinch ? (2.0f * (0.5f - brush->crease_pinch_factor) *
- (len_v3(grab_delta) / ss->cache->radius)) :
- 0.0f;
-
- const bool do_elastic = brush->snake_hook_deform_type == BRUSH_SNAKE_HOOK_DEFORM_ELASTIC;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- KelvinletParams params;
- BKE_kelvinlet_init_params(&params, ss->cache->radius, bstrength, 1.0f, 0.4f);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!do_elastic && !sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
-
- float fade;
- if (do_elastic) {
- fade = 1.0f;
- }
- else {
- fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
- }
-
- mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
-
- /* Negative pinch will inflate, helps maintain volume. */
- if (do_pinch) {
- float delta_pinch_init[3], delta_pinch[3];
-
- sub_v3_v3v3(delta_pinch, vd.co, test.location);
- if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- project_plane_v3_v3v3(delta_pinch, delta_pinch, ss->cache->true_view_normal);
- }
-
- /* Important to calculate based on the grabbed location
- * (intentionally ignore fade here). */
- add_v3_v3(delta_pinch, grab_delta);
-
- sculpt_project_v3(spvc, delta_pinch, delta_pinch);
-
- copy_v3_v3(delta_pinch_init, delta_pinch);
-
- float pinch_fade = pinch * fade;
- /* When reducing, scale reduction back by how close to the center we are,
- * so we don't pinch into nothingness. */
- if (pinch > 0.0f) {
- /* Square to have even less impact for close vertices. */
- pinch_fade *= pow2f(min_ff(1.0f, len_v3(delta_pinch) / ss->cache->radius));
- }
- mul_v3_fl(delta_pinch, 1.0f + pinch_fade);
- sub_v3_v3v3(delta_pinch, delta_pinch_init, delta_pinch);
- add_v3_v3(proxy[vd.i], delta_pinch);
- }
-
- if (do_rake_rotation) {
- float delta_rotate[3];
- sculpt_rake_rotate(ss, test.location, vd.co, fade, delta_rotate);
- add_v3_v3(proxy[vd.i], delta_rotate);
- }
-
- if (do_elastic) {
- float disp[3];
- BKE_kelvinlet_grab_triscale(disp, &params, vd.co, ss->cache->location, proxy[vd.i]);
- mul_v3_fl(disp, bstrength * 20.0f);
- if (vd.mask) {
- mul_v3_fl(disp, 1.0f - *vd.mask);
- }
- mul_v3_fl(disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index));
- copy_v3_v3(proxy[vd.i], disp);
- }
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- const float bstrength = ss->cache->bstrength;
- float grab_delta[3];
-
- SculptProjectVector spvc;
-
- copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
-
- if (bstrength < 0.0f) {
- negate_v3(grab_delta);
- }
-
- if (ss->cache->normal_weight > 0.0f) {
- sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
- }
-
- /* Optionally pinch while painting. */
- if (brush->crease_pinch_factor != 0.5f) {
- sculpt_project_v3_cache_init(&spvc, grab_delta);
- }
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .spvc = &spvc,
- .grab_delta = grab_delta,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings);
-}
-
-static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *cono = data->cono;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
-
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- orig_data.co,
- sqrtf(test.dist),
- orig_data.no,
- NULL,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], cono, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float grab_delta[3];
- float tmp[3], cono[3];
-
- copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
-
- cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
- cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .cono = cono,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings);
-}
-
-static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float angle = data->angle;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
-
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- float vec[3], rot[3][3];
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- orig_data.co,
- sqrtf(test.dist),
- orig_data.no,
- NULL,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- sub_v3_v3v3(vec, orig_data.co, ss->cache->location);
- axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade);
- mul_v3_m3v3(proxy[vd.i], rot, vec);
- add_v3_v3(proxy[vd.i], ss->cache->location);
- sub_v3_v3(proxy[vd.i], orig_data.co);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- static const int flip[8] = {1, -1, -1, 1, -1, 1, 1, -1};
- const float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass];
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .angle = angle,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings);
-}
-
-static void do_layer_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- Sculpt *sd = data->sd;
- const Brush *brush = data->brush;
-
- const bool use_persistent_base = ss->persistent_base && brush->flag & BRUSH_PERSISTENT;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- const float bstrength = ss->cache->bstrength;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
-
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- const float fade = SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- const int vi = vd.index;
- float *disp_factor;
- if (use_persistent_base) {
- disp_factor = &ss->persistent_base[vi].disp;
- }
- else {
- disp_factor = &ss->cache->layer_displacement_factor[vi];
- }
-
- /* When using persistent base, the layer brush (holding Control) invert mode resets the
- * height of the layer to 0. This makes possible to clean edges of previously added layers
- * on top of the base. */
- /* The main direction of the layers is inverted using the regular brush strength with the
- * brush direction property. */
- if (use_persistent_base && ss->cache->invert) {
- (*disp_factor) += fabsf(fade * bstrength * (*disp_factor)) *
- ((*disp_factor) > 0.0f ? -1.0f : 1.0f);
- }
- else {
- (*disp_factor) += fade * bstrength * (1.05f - fabsf(*disp_factor));
- }
- if (vd.mask) {
- const float clamp_mask = 1.0f - *vd.mask;
- *disp_factor = clamp_f(*disp_factor, -clamp_mask, clamp_mask);
- }
- else {
- *disp_factor = clamp_f(*disp_factor, -1.0f, 1.0f);
- }
-
- float final_co[3];
- float normal[3];
-
- if (use_persistent_base) {
- SCULPT_vertex_persistent_normal_get(ss, vi, normal);
- mul_v3_fl(normal, brush->height);
- madd_v3_v3v3fl(final_co, SCULPT_vertex_persistent_co_get(ss, vi), normal, *disp_factor);
- }
- else {
- normal_short_to_float_v3(normal, orig_data.no);
- mul_v3_fl(normal, brush->height);
- madd_v3_v3v3fl(final_co, orig_data.co, normal, *disp_factor);
- }
-
- float vdisp[3];
- sub_v3_v3v3(vdisp, final_co, vd.co);
- mul_v3_fl(vdisp, fabsf(fade));
- add_v3_v3v3(final_co, vd.co, vdisp);
-
- SCULPT_clip(sd, ss, vd.co, final_co);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- if (ss->cache->layer_displacement_factor == NULL) {
- ss->cache->layer_displacement_factor = MEM_callocN(sizeof(float) * SCULPT_vertex_count_get(ss),
- "layer displacement factor");
- }
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings);
-}
-
-static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
- float val[3];
-
- if (vd.fno) {
- copy_v3_v3(val, vd.fno);
- }
- else {
- normal_short_to_float_v3(val, vd.no);
- }
-
- mul_v3_fl(val, fade * ss->cache->radius);
- mul_v3_v3v3(proxy[vd.i], val, ss->cache->scale);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings);
-}
-
int SCULPT_plane_trim(const StrokeCache *cache, const Brush *brush, const float val[3])
{
return (!(brush->flag & BRUSH_PLANE_TRIM) ||
((dot_v3v3(val, val) <= cache->radius_squared * cache->plane_trim_squared)));
}
-static bool plane_point_side_flip(const float co[3], const float plane[4], const bool flip)
-{
- float d = plane_point_side_v3(plane, co);
- if (flip) {
- d = -d;
- }
- return d <= 0.0f;
-}
-
int SCULPT_plane_point_side(const float co[3], const float plane[4])
{
float d = plane_point_side_v3(plane, co);
@@ -4893,807 +2942,6 @@ float SCULPT_brush_plane_offset_get(Sculpt *sd, SculptSession *ss)
return rv;
}
-static void do_flatten_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *area_no = data->area_no;
- const float *area_co = data->area_co;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- float intr[3];
- float val[3];
-
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
-
- sub_v3_v3v3(val, intr, vd.co);
-
- if (SCULPT_plane_trim(ss->cache, brush, val)) {
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], val, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const float radius = ss->cache->radius;
-
- float area_no[3];
- float area_co[3];
-
- float offset = SCULPT_brush_plane_offset_get(sd, ss);
- float displace;
- float temp[3];
-
- SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
-
- SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor);
-
- displace = radius * offset;
-
- mul_v3_v3v3(temp, area_no, ss->cache->scale);
- mul_v3_fl(temp, displace);
- add_v3_v3(area_co, temp);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .area_no = area_no,
- .area_co = area_co,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Clay Brush
- * \{ */
-
-typedef struct ClaySampleData {
- float plane_dist[2];
-} ClaySampleData;
-
-static void calc_clay_surface_task_cb(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- ClaySampleData *csd = tls->userdata_chunk;
- const float *area_no = data->area_no;
- const float *area_co = data->area_co;
- float plane[4];
-
- PBVHVertexIter vd;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, brush->falloff_shape);
-
- /* Apply the brush normal radius to the test before sampling. */
- float test_radius = sqrtf(test.radius_squared);
- test_radius *= brush->normal_radius_factor;
- test.radius_squared = test_radius * test_radius;
- plane_from_point_normal_v3(plane, area_co, area_no);
-
- if (is_zero_v4(plane)) {
- return;
- }
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
-
- float plane_dist = dist_signed_to_plane_v3(vd.co, plane);
- float plane_dist_abs = fabsf(plane_dist);
- if (plane_dist > 0.0f) {
- csd->plane_dist[0] = MIN2(csd->plane_dist[0], plane_dist_abs);
- }
- else {
- csd->plane_dist[1] = MIN2(csd->plane_dist[1], plane_dist_abs);
- }
- BKE_pbvh_vertex_iter_end;
- }
-}
-
-static void calc_clay_surface_reduce(const void *__restrict UNUSED(userdata),
- void *__restrict chunk_join,
- void *__restrict chunk)
-{
- ClaySampleData *join = chunk_join;
- ClaySampleData *csd = chunk;
- join->plane_dist[0] = MIN2(csd->plane_dist[0], join->plane_dist[0]);
- join->plane_dist[1] = MIN2(csd->plane_dist[1], join->plane_dist[1]);
-}
-
-static void do_clay_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *area_no = data->area_no;
- const float *area_co = data->area_co;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = fabsf(ss->cache->bstrength);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
-
- float intr[3];
- float val[3];
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
-
- sub_v3_v3v3(val, intr, vd.co);
-
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], val, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const float radius = fabsf(ss->cache->radius);
- const float initial_radius = fabsf(ss->cache->initial_radius);
- bool flip = ss->cache->bstrength < 0.0f;
-
- float offset = SCULPT_brush_plane_offset_get(sd, ss);
- float displace;
-
- float area_no[3];
- float area_co[3];
- float temp[3];
-
- SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
-
- SculptThreadedTaskData sample_data = {
- .sd = NULL,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .totnode = totnode,
- .area_no = area_no,
- .area_co = ss->cache->location,
- };
-
- ClaySampleData csd = {{0}};
-
- TaskParallelSettings sample_settings;
- BKE_pbvh_parallel_range_settings(&sample_settings, true, totnode);
- sample_settings.func_reduce = calc_clay_surface_reduce;
- sample_settings.userdata_chunk = &csd;
- sample_settings.userdata_chunk_size = sizeof(ClaySampleData);
-
- BLI_task_parallel_range(0, totnode, &sample_data, calc_clay_surface_task_cb, &sample_settings);
-
- float d_offset = (csd.plane_dist[0] + csd.plane_dist[1]);
- d_offset = min_ff(radius, d_offset);
- d_offset = d_offset / radius;
- d_offset = 1.0f - d_offset;
- displace = fabsf(initial_radius * (0.25f + offset + (d_offset * 0.15f)));
- if (flip) {
- displace = -displace;
- }
-
- mul_v3_v3v3(temp, area_no, ss->cache->scale);
- mul_v3_fl(temp, displace);
- copy_v3_v3(area_co, ss->cache->location);
- add_v3_v3(area_co, temp);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .area_no = area_no,
- .area_co = area_co,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings);
-}
-
-static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- float(*mat)[4] = data->mat;
- const float *area_no_sp = data->area_no_sp;
- const float *area_co = data->area_co;
-
- PBVHVertexIter vd;
- SculptBrushTest test;
- float(*proxy)[3];
- const bool flip = (ss->cache->bstrength < 0.0f);
- const float bstrength = flip ? -ss->cache->bstrength : ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SCULPT_brush_test_init(ss, &test);
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!SCULPT_brush_test_cube(&test, vd.co, mat, brush->tip_roundness)) {
- continue;
- }
-
- if (!plane_point_side_flip(vd.co, test.plane_tool, flip)) {
- continue;
- }
-
- float intr[3];
- float val[3];
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
- sub_v3_v3v3(val, intr, vd.co);
-
- if (!SCULPT_plane_trim(ss->cache, brush, val)) {
- continue;
- }
- /* The normal from the vertices is ignored, it causes glitch with planes, see: T44390. */
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- ss->cache->radius * test.dist,
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], val, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const bool flip = (ss->cache->bstrength < 0.0f);
- const float radius = flip ? -ss->cache->radius : ss->cache->radius;
- const float offset = SCULPT_brush_plane_offset_get(sd, ss);
- const float displace = radius * (0.18f + offset);
-
- /* The sculpt-plane normal (whatever its set to). */
- float area_no_sp[3];
-
- /* Geometry normal */
- float area_no[3];
- float area_co[3];
-
- float temp[3];
- float mat[4][4];
- float scale[4][4];
- float tmat[4][4];
-
- SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no_sp, area_co);
- SCULPT_tilt_apply_to_normal(area_no_sp, ss->cache, brush->tilt_strength_factor);
-
- if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
- SCULPT_calc_area_normal(sd, ob, nodes, totnode, area_no);
- }
- else {
- copy_v3_v3(area_no, area_no_sp);
- }
-
- /* Delay the first daub because grab delta is not setup. */
- if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
- return;
- }
-
- if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
- return;
- }
-
- mul_v3_v3v3(temp, area_no_sp, ss->cache->scale);
- mul_v3_fl(temp, displace);
- add_v3_v3(area_co, temp);
-
- /* Clay Strips uses a cube test with falloff in the XY axis (not in Z) and a plane to deform the
- * vertices. When in Add mode, vertices that are below the plane and inside the cube are move
- * towards the plane. In this situation, there may be cases where a vertex is outside the cube
- * but below the plane, so won't be deformed, causing artifacts. In order to prevent these
- * artifacts, this displaces the test cube space in relation to the plane in order to
- * deform more vertices that may be below it. */
- /* The 0.7 and 1.25 factors are arbitrary and don't have any relation between them, they were set
- * by doing multiple tests using the default "Clay Strips" brush preset. */
- float area_co_displaced[3];
- madd_v3_v3v3fl(area_co_displaced, area_co, area_no, -radius * 0.7f);
-
- /* Initialize brush local-space matrix. */
- cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
- mat[0][3] = 0.0f;
- cross_v3_v3v3(mat[1], area_no, mat[0]);
- mat[1][3] = 0.0f;
- copy_v3_v3(mat[2], area_no);
- mat[2][3] = 0.0f;
- copy_v3_v3(mat[3], area_co_displaced);
- mat[3][3] = 1.0f;
- normalize_m4(mat);
-
- /* Scale brush local space matrix. */
- scale_m4_fl(scale, ss->cache->radius);
- mul_m4_m4m4(tmat, mat, scale);
-
- /* Deform the local space in Z to scale the test cube. As the test cube does not have falloff in
- * Z this does not produce artifacts in the falloff cube and allows to deform extra vertices
- * during big deformation while keeping the surface as uniform as possible. */
- mul_v3_fl(tmat[2], 1.25f);
-
- invert_m4_m4(mat, tmat);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .area_no_sp = area_no_sp,
- .area_co = area_co,
- .mat = mat,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings);
-}
-
-static void do_fill_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *area_no = data->area_no;
- const float *area_co = data->area_co;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
-
- if (!SCULPT_plane_point_side(vd.co, test.plane_tool)) {
- continue;
- }
-
- float intr[3];
- float val[3];
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
- sub_v3_v3v3(val, intr, vd.co);
-
- if (!SCULPT_plane_trim(ss->cache, brush, val)) {
- continue;
- }
-
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], val, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const float radius = ss->cache->radius;
-
- float area_no[3];
- float area_co[3];
- float offset = SCULPT_brush_plane_offset_get(sd, ss);
-
- float displace;
-
- float temp[3];
-
- SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
-
- SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor);
-
- displace = radius * offset;
-
- mul_v3_v3v3(temp, area_no, ss->cache->scale);
- mul_v3_fl(temp, displace);
- add_v3_v3(area_co, temp);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .area_no = area_no,
- .area_co = area_co,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings);
-}
-
-static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *area_no = data->area_no;
- const float *area_co = data->area_co;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
-
- if (SCULPT_plane_point_side(vd.co, test.plane_tool)) {
- continue;
- }
-
- float intr[3];
- float val[3];
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
- sub_v3_v3v3(val, intr, vd.co);
-
- if (!SCULPT_plane_trim(ss->cache, brush, val)) {
- continue;
- }
-
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], val, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const float radius = ss->cache->radius;
-
- float area_no[3];
- float area_co[3];
- float offset = SCULPT_brush_plane_offset_get(sd, ss);
-
- float displace;
-
- float temp[3];
-
- SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
-
- SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor);
-
- displace = -radius * offset;
-
- mul_v3_v3v3(temp, area_no, ss->cache->scale);
- mul_v3_fl(temp, displace);
- add_v3_v3(area_co, temp);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .area_no = area_no,
- .area_co = area_co,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Clay Thumb Brush
- * \{ */
-
-static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- float(*mat)[4] = data->mat;
- const float *area_no_sp = data->area_no_sp;
- const float *area_co = data->area_co;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = data->clay_strength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- float plane_tilt[4];
- float normal_tilt[3];
- float imat[4][4];
-
- invert_m4_m4(imat, mat);
- rotate_v3_v3v3fl(normal_tilt, area_no_sp, imat[0], DEG2RADF(-ss->cache->clay_thumb_front_angle));
-
- /* Plane aligned to the geometry normal (back part of the brush). */
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp);
- /* Tilted plane (front part of the brush). */
- plane_from_point_normal_v3(plane_tilt, area_co, normal_tilt);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- float local_co[3];
- mul_v3_m4v3(local_co, mat, vd.co);
- float intr[3], intr_tilt[3];
- float val[3];
-
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
- closest_to_plane_normalized_v3(intr_tilt, plane_tilt, vd.co);
-
- /* Mix the deformation of the aligned and the tilted plane based on the brush space vertex
- * coordinates. */
- /* We can also control the mix with a curve if it produces noticeable artifacts in the center
- * of the brush. */
- const float tilt_mix = local_co[1] > 0.0f ? 0.0f : 1.0f;
- interp_v3_v3v3(intr, intr, intr_tilt, tilt_mix);
- sub_v3_v3v3(val, intr_tilt, vd.co);
-
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], val, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static float sculpt_clay_thumb_get_stabilized_pressure(StrokeCache *cache)
-{
- float final_pressure = 0.0f;
- for (int i = 0; i < SCULPT_CLAY_STABILIZER_LEN; i++) {
- final_pressure += cache->clay_pressure_stabilizer[i];
- }
- return final_pressure / SCULPT_CLAY_STABILIZER_LEN;
-}
-
-static void do_clay_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const float radius = ss->cache->radius;
- const float offset = SCULPT_brush_plane_offset_get(sd, ss);
- const float displace = radius * (0.25f + offset);
-
- /* Sampled geometry normal and area center. */
- float area_no_sp[3];
- float area_no[3];
- float area_co[3];
-
- float temp[3];
- float mat[4][4];
- float scale[4][4];
- float tmat[4][4];
-
- SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no_sp, area_co);
-
- if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
- SCULPT_calc_area_normal(sd, ob, nodes, totnode, area_no);
- }
- else {
- copy_v3_v3(area_no, area_no_sp);
- }
-
- /* Delay the first daub because grab delta is not setup. */
- if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
- ss->cache->clay_thumb_front_angle = 0.0f;
- return;
- }
-
- /* Simulate the clay accumulation by increasing the plane angle as more samples are added to the
- * stroke. */
- if (SCULPT_stroke_is_main_symmetry_pass(ss->cache)) {
- ss->cache->clay_thumb_front_angle += 0.8f;
- ss->cache->clay_thumb_front_angle = clamp_f(ss->cache->clay_thumb_front_angle, 0.0f, 60.0f);
- }
-
- if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
- return;
- }
-
- /* Displace the brush planes. */
- copy_v3_v3(area_co, ss->cache->location);
- mul_v3_v3v3(temp, area_no_sp, ss->cache->scale);
- mul_v3_fl(temp, displace);
- add_v3_v3(area_co, temp);
-
- /* Initialize brush local-space matrix. */
- cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
- mat[0][3] = 0.0f;
- cross_v3_v3v3(mat[1], area_no, mat[0]);
- mat[1][3] = 0.0f;
- copy_v3_v3(mat[2], area_no);
- mat[2][3] = 0.0f;
- copy_v3_v3(mat[3], ss->cache->location);
- mat[3][3] = 1.0f;
- normalize_m4(mat);
-
- /* Scale brush local space matrix. */
- scale_m4_fl(scale, ss->cache->radius);
- mul_m4_m4m4(tmat, mat, scale);
- invert_m4_m4(mat, tmat);
-
- float clay_strength = ss->cache->bstrength *
- sculpt_clay_thumb_get_stabilized_pressure(ss->cache);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .area_no_sp = area_no_sp,
- .area_co = ss->cache->location,
- .mat = mat,
- .clay_strength = clay_strength,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_clay_thumb_brush_task_cb_ex, &settings);
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -6036,7 +3284,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
/* Apply one type of brush action. */
switch (brush->sculpt_tool) {
case SCULPT_TOOL_DRAW:
- do_draw_brush(sd, ob, nodes, totnode);
+ SCULPT_do_draw_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_SMOOTH:
if (brush->smooth_deform_type == BRUSH_SMOOTH_DEFORM_LAPLACIAN) {
@@ -6047,80 +3295,80 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
}
break;
case SCULPT_TOOL_CREASE:
- do_crease_brush(sd, ob, nodes, totnode);
+ SCULPT_do_crease_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_BLOB:
- do_crease_brush(sd, ob, nodes, totnode);
+ SCULPT_do_crease_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_PINCH:
- do_pinch_brush(sd, ob, nodes, totnode);
+ SCULPT_do_pinch_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_INFLATE:
- do_inflate_brush(sd, ob, nodes, totnode);
+ SCULPT_do_inflate_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_GRAB:
- do_grab_brush(sd, ob, nodes, totnode);
+ SCULPT_do_grab_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_ROTATE:
- do_rotate_brush(sd, ob, nodes, totnode);
+ SCULPT_do_rotate_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_SNAKE_HOOK:
- do_snake_hook_brush(sd, ob, nodes, totnode);
+ SCULPT_do_snake_hook_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_NUDGE:
- do_nudge_brush(sd, ob, nodes, totnode);
+ SCULPT_do_nudge_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_THUMB:
- do_thumb_brush(sd, ob, nodes, totnode);
+ SCULPT_do_thumb_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_LAYER:
- do_layer_brush(sd, ob, nodes, totnode);
+ SCULPT_do_layer_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_FLATTEN:
- do_flatten_brush(sd, ob, nodes, totnode);
+ SCULPT_do_flatten_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_CLAY:
- do_clay_brush(sd, ob, nodes, totnode);
+ SCULPT_do_clay_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_CLAY_STRIPS:
- do_clay_strips_brush(sd, ob, nodes, totnode);
+ SCULPT_do_clay_strips_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_MULTIPLANE_SCRAPE:
SCULPT_do_multiplane_scrape_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_CLAY_THUMB:
- do_clay_thumb_brush(sd, ob, nodes, totnode);
+ SCULPT_do_clay_thumb_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_FILL:
if (invert && brush->flag & BRUSH_INVERT_TO_SCRAPE_FILL) {
- do_scrape_brush(sd, ob, nodes, totnode);
+ SCULPT_do_scrape_brush(sd, ob, nodes, totnode);
}
else {
- do_fill_brush(sd, ob, nodes, totnode);
+ SCULPT_do_fill_brush(sd, ob, nodes, totnode);
}
break;
case SCULPT_TOOL_SCRAPE:
if (invert && brush->flag & BRUSH_INVERT_TO_SCRAPE_FILL) {
- do_fill_brush(sd, ob, nodes, totnode);
+ SCULPT_do_fill_brush(sd, ob, nodes, totnode);
}
else {
- do_scrape_brush(sd, ob, nodes, totnode);
+ SCULPT_do_scrape_brush(sd, ob, nodes, totnode);
}
break;
case SCULPT_TOOL_MASK:
- do_mask_brush(sd, ob, nodes, totnode);
+ SCULPT_do_mask_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_POSE:
SCULPT_do_pose_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_DRAW_SHARP:
- do_draw_sharp_brush(sd, ob, nodes, totnode);
+ SCULPT_do_draw_sharp_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_ELASTIC_DEFORM:
- do_elastic_deform_brush(sd, ob, nodes, totnode);
+ SCULPT_do_elastic_deform_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_SLIDE_RELAX:
- do_slide_relax_brush(sd, ob, nodes, totnode);
+ SCULPT_do_slide_relax_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_BOUNDARY:
SCULPT_do_boundary_brush(sd, ob, nodes, totnode);
@@ -6132,10 +3380,10 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
SCULPT_do_draw_face_sets_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_DISPLACEMENT_ERASER:
- do_displacement_eraser_brush(sd, ob, nodes, totnode);
+ SCULPT_do_displacement_eraser_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_DISPLACEMENT_SMEAR:
- do_displacement_smear_brush(sd, ob, nodes, totnode);
+ SCULPT_do_displacement_smear_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_PAINT:
SCULPT_do_paint_brush(sd, ob, nodes, totnode);
@@ -6157,7 +3405,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
}
if (sculpt_brush_use_topology_rake(ss, brush)) {
- bmesh_topology_rake(sd, ob, nodes, totnode, brush->topology_rake_factor);
+ SCULPT_bmesh_topology_rake(sd, ob, nodes, totnode, brush->topology_rake_factor);
}
/* The cloth brush adds the gravity as a regular force and it is processed in the solver. */
@@ -6946,7 +4194,7 @@ static float sculpt_brush_dynamic_size_get(Brush *brush, StrokeCache *cache, flo
case SCULPT_TOOL_CLAY_STRIPS:
return max_ff(initial_size * 0.30f, initial_size * powf(cache->pressure, 1.5f));
case SCULPT_TOOL_CLAY_THUMB: {
- float clay_stabilized_pressure = sculpt_clay_thumb_get_stabilized_pressure(cache);
+ float clay_stabilized_pressure = SCULPT_clay_thumb_get_stabilized_pressure(cache);
return initial_size * clay_stabilized_pressure;
}
default:
@@ -8131,7 +5379,7 @@ static void sculpt_brush_stroke_cancel(bContext *C, wmOperator *op)
sculpt_brush_exit_tex(sd);
}
-static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
+void SCULPT_OT_brush_stroke(wmOperatorType *ot)
{
/* Identifiers. */
ot->name = "Sculpt";
@@ -8159,677 +5407,6 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
"Clicks on the background do not start the stroke");
}
-/* Reset the copy of the mesh that is being sculpted on (currently just for the layer brush). */
-
-static int sculpt_set_persistent_base_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
-
- if (!ss) {
- return OPERATOR_FINISHED;
- }
- SCULPT_vertex_random_access_ensure(ss);
- BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
-
- MEM_SAFE_FREE(ss->persistent_base);
-
- const int totvert = SCULPT_vertex_count_get(ss);
- ss->persistent_base = MEM_mallocN(sizeof(SculptPersistentBase) * totvert,
- "layer persistent base");
-
- for (int i = 0; i < totvert; i++) {
- copy_v3_v3(ss->persistent_base[i].co, SCULPT_vertex_co_get(ss, i));
- SCULPT_vertex_normal_get(ss, i, ss->persistent_base[i].no);
- ss->persistent_base[i].disp = 0.0f;
- }
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Set Persistent Base";
- ot->idname = "SCULPT_OT_set_persistent_base";
- ot->description = "Reset the copy of the mesh that is being sculpted on";
-
- /* API callbacks. */
- ot->exec = sculpt_set_persistent_base_exec;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/************************* SCULPT_OT_optimize *************************/
-
-static int sculpt_optimize_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = CTX_data_active_object(C);
-
- SCULPT_pbvh_clear(ob);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- return OPERATOR_FINISHED;
-}
-
-/* The BVH gets less optimal more quickly with dynamic topology than
- * regular sculpting. There is no doubt more clever stuff we can do to
- * optimize it on the fly, but for now this gives the user a nicer way
- * to recalculate it than toggling modes. */
-static void SCULPT_OT_optimize(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Rebuild BVH";
- ot->idname = "SCULPT_OT_optimize";
- ot->description = "Recalculate the sculpt BVH to improve performance";
-
- /* API callbacks. */
- ot->exec = sculpt_optimize_exec;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/********************* Dynamic topology symmetrize ********************/
-
-static bool sculpt_no_multires_poll(bContext *C)
-{
- Object *ob = CTX_data_active_object(C);
- if (SCULPT_mode_poll(C) && ob->sculpt && ob->sculpt->pbvh) {
- return BKE_pbvh_type(ob->sculpt->pbvh) != PBVH_GRIDS;
- }
- return false;
-}
-
-static int sculpt_symmetrize_exec(bContext *C, wmOperator *op)
-{
- Main *bmain = CTX_data_main(C);
- Object *ob = CTX_data_active_object(C);
- const Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- SculptSession *ss = ob->sculpt;
- PBVH *pbvh = ss->pbvh;
- const float dist = RNA_float_get(op->ptr, "merge_tolerance");
-
- if (!pbvh) {
- return OPERATOR_CANCELLED;
- }
-
- switch (BKE_pbvh_type(pbvh)) {
- case PBVH_BMESH:
- /* Dyntopo Symmetrize. */
-
- /* To simplify undo for symmetrize, all BMesh elements are logged
- * as deleted, then after symmetrize operation all BMesh elements
- * are logged as added (as opposed to attempting to store just the
- * parts that symmetrize modifies). */
- SCULPT_undo_push_begin(ob, "Dynamic topology symmetrize");
- SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE);
- BM_log_before_all_removed(ss->bm, ss->bm_log);
-
- BM_mesh_toolflags_set(ss->bm, true);
-
- /* Symmetrize and re-triangulate. */
- BMO_op_callf(ss->bm,
- (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
- "symmetrize input=%avef direction=%i dist=%f use_shapekey=%b",
- sd->symmetrize_direction,
- dist,
- true);
- SCULPT_dynamic_topology_triangulate(ss->bm);
-
- /* Bisect operator flags edges (keep tags clean for edge queue). */
- BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false);
-
- BM_mesh_toolflags_set(ss->bm, false);
-
- /* Finish undo. */
- BM_log_all_added(ss->bm, ss->bm_log);
- SCULPT_undo_push_end();
-
- break;
- case PBVH_FACES:
- /* Mesh Symmetrize. */
- ED_sculpt_undo_geometry_begin(ob, "mesh symmetrize");
- Mesh *mesh = ob->data;
-
- BKE_mesh_mirror_apply_mirror_on_axis(bmain, mesh, sd->symmetrize_direction, dist);
-
- ED_sculpt_undo_geometry_end(ob);
- BKE_mesh_calc_normals(ob->data);
- BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
-
- break;
- case PBVH_GRIDS:
- return OPERATOR_CANCELLED;
- }
-
- /* Redraw. */
- SCULPT_pbvh_clear(ob);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_symmetrize(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Symmetrize";
- ot->idname = "SCULPT_OT_symmetrize";
- ot->description = "Symmetrize the topology modifications";
-
- /* API callbacks. */
- ot->exec = sculpt_symmetrize_exec;
- ot->poll = sculpt_no_multires_poll;
-
- RNA_def_float(ot->srna,
- "merge_tolerance",
- 0.001f,
- 0.0f,
- FLT_MAX,
- "Merge Distance",
- "Distance within which symmetrical vertices are merged",
- 0.0f,
- 1.0f);
-}
-
-/**** Toggle operator for turning sculpt mode on or off ****/
-
-static void sculpt_init_session(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
-{
- /* Create persistent sculpt mode data. */
- BKE_sculpt_toolsettings_data_ensure(scene);
-
- /* Create sculpt mode session data. */
- if (ob->sculpt != NULL) {
- BKE_sculptsession_free(ob);
- }
- ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
- ob->sculpt->mode_type = OB_MODE_SCULPT;
-
- BKE_sculpt_ensure_orig_mesh_data(scene, ob);
-
- BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
-
- /* This function expects a fully evaluated depsgraph. */
- BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
-
- /* Here we can detect geometry that was just added to Sculpt Mode as it has the
- * SCULPT_FACE_SET_NONE assigned, so we can create a new Face Set for it. */
- /* In sculpt mode all geometry that is assigned to SCULPT_FACE_SET_NONE is considered as not
- * initialized, which is used is some operators that modify the mesh topology to perform certain
- * actions in the new polys. After these operations are finished, all polys should have a valid
- * face set ID assigned (different from SCULPT_FACE_SET_NONE) to manage their visibility
- * correctly. */
- /* TODO(pablodp606): Based on this we can improve the UX in future tools for creating new
- * objects, like moving the transform pivot position to the new area or masking existing
- * geometry. */
- SculptSession *ss = ob->sculpt;
- const int new_face_set = SCULPT_face_set_next_available_get(ss);
- for (int i = 0; i < ss->totfaces; i++) {
- if (ss->face_sets[i] == SCULPT_FACE_SET_NONE) {
- ss->face_sets[i] = new_face_set;
- }
- }
-}
-
-void ED_object_sculptmode_enter_ex(Main *bmain,
- Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
- const bool force_dyntopo,
- ReportList *reports)
-{
- const int mode_flag = OB_MODE_SCULPT;
- Mesh *me = BKE_mesh_from_object(ob);
-
- /* Enter sculpt mode. */
- ob->mode |= mode_flag;
-
- sculpt_init_session(bmain, depsgraph, scene, ob);
-
- if (!(fabsf(ob->scale[0] - ob->scale[1]) < 1e-4f &&
- fabsf(ob->scale[1] - ob->scale[2]) < 1e-4f)) {
- BKE_report(
- reports, RPT_WARNING, "Object has non-uniform scale, sculpting may be unpredictable");
- }
- else if (is_negative_m4(ob->obmat)) {
- BKE_report(reports, RPT_WARNING, "Object has negative scale, sculpting may be unpredictable");
- }
-
- Paint *paint = BKE_paint_get_active_from_paintmode(scene, PAINT_MODE_SCULPT);
- BKE_paint_init(bmain, scene, PAINT_MODE_SCULPT, PAINT_CURSOR_SCULPT);
-
- paint_cursor_start(paint, SCULPT_mode_poll_view3d);
-
- /* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes,
- * As long as no data was added that is not supported. */
- if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
- MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
-
- const char *message_unsupported = NULL;
- if (me->totloop != me->totpoly * 3) {
- message_unsupported = TIP_("non-triangle face");
- }
- else if (mmd != NULL) {
- message_unsupported = TIP_("multi-res modifier");
- }
- else {
- enum eDynTopoWarnFlag flag = SCULPT_dynamic_topology_check(scene, ob);
- if (flag == 0) {
- /* pass */
- }
- else if (flag & DYNTOPO_WARN_VDATA) {
- message_unsupported = TIP_("vertex data");
- }
- else if (flag & DYNTOPO_WARN_EDATA) {
- message_unsupported = TIP_("edge data");
- }
- else if (flag & DYNTOPO_WARN_LDATA) {
- message_unsupported = TIP_("face data");
- }
- else if (flag & DYNTOPO_WARN_MODIFIER) {
- message_unsupported = TIP_("constructive modifier");
- }
- else {
- BLI_assert(0);
- }
- }
-
- if ((message_unsupported == NULL) || force_dyntopo) {
- /* Needed because we may be entering this mode before the undo system loads. */
- wmWindowManager *wm = bmain->wm.first;
- bool has_undo = wm->undo_stack != NULL;
- /* Undo push is needed to prevent memory leak. */
- if (has_undo) {
- SCULPT_undo_push_begin(ob, "Dynamic topology enable");
- }
- SCULPT_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob);
- if (has_undo) {
- SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
- SCULPT_undo_push_end();
- }
- }
- else {
- BKE_reportf(
- reports, RPT_WARNING, "Dynamic Topology found: %s, disabled", message_unsupported);
- me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
- }
- }
-
- /* Flush object mode. */
- DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
-}
-
-void ED_object_sculptmode_enter(struct bContext *C, Depsgraph *depsgraph, ReportList *reports)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
- ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, reports);
-}
-
-void ED_object_sculptmode_exit_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
-{
- const int mode_flag = OB_MODE_SCULPT;
- Mesh *me = BKE_mesh_from_object(ob);
-
- multires_flush_sculpt_updates(ob);
-
- /* Not needed for now. */
-#if 0
- MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
- const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd);
-#endif
-
- /* Always for now, so leaving sculpt mode always ensures scene is in
- * a consistent state. */
- if (true || /* flush_recalc || */ (ob->sculpt && ob->sculpt->bm)) {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
-
- if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
- /* Dynamic topology must be disabled before exiting sculpt
- * mode to ensure the undo stack stays in a consistent
- * state. */
- sculpt_dynamic_topology_disable_with_undo(bmain, depsgraph, scene, ob);
-
- /* Store so we know to re-enable when entering sculpt mode. */
- me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
- }
-
- /* Leave sculpt mode. */
- ob->mode &= ~mode_flag;
-
- BKE_sculptsession_free(ob);
-
- paint_cursor_delete_textures();
-
- /* Never leave derived meshes behind. */
- BKE_object_free_derived_caches(ob);
-
- /* Flush object mode. */
- DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
-}
-
-void ED_object_sculptmode_exit(bContext *C, Depsgraph *depsgraph)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
- ED_object_sculptmode_exit_ex(bmain, depsgraph, scene, ob);
-}
-
-static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
-{
- struct wmMsgBus *mbus = CTX_wm_message_bus(C);
- Main *bmain = CTX_data_main(C);
- Depsgraph *depsgraph = CTX_data_depsgraph_on_load(C);
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
- const int mode_flag = OB_MODE_SCULPT;
- const bool is_mode_set = (ob->mode & mode_flag) != 0;
-
- if (!is_mode_set) {
- if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
- return OPERATOR_CANCELLED;
- }
- }
-
- if (is_mode_set) {
- ED_object_sculptmode_exit_ex(bmain, depsgraph, scene, ob);
- }
- else {
- if (depsgraph) {
- depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- }
- ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, op->reports);
- BKE_paint_toolslots_brush_validate(bmain, &ts->sculpt->paint);
-
- if (ob->mode & mode_flag) {
- Mesh *me = ob->data;
- /* Dyntopo adds its own undo step. */
- if ((me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) == 0) {
- /* Without this the memfile undo step is used,
- * while it works it causes lag when undoing the first undo step, see T71564. */
- wmWindowManager *wm = CTX_wm_manager(C);
- if (wm->op_undo_depth <= 1) {
- SCULPT_undo_push_begin(ob, op->type->name);
- }
- }
- }
- }
-
- WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
-
- WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
-
- WM_toolsystem_update_from_context_view3d(C);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_sculptmode_toggle(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Sculpt Mode";
- ot->idname = "SCULPT_OT_sculptmode_toggle";
- ot->description = "Toggle sculpt mode in 3D view";
-
- /* API callbacks. */
- ot->exec = sculpt_mode_toggle_exec;
- ot->poll = ED_operator_object_active_editable_mesh;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float radius)
-{
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- Object *ob = CTX_data_active_object(C);
-
- ss->preview_vert_index_count = 0;
- int totpoints = 0;
-
- /* This function is called from the cursor drawing code, so the PBVH may not be build yet. */
- if (!ss->pbvh) {
- return;
- }
-
- if (!ss->deform_modifiers_active) {
- return;
- }
-
- if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
- return;
- }
-
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
-
- if (!ss->pmap) {
- return;
- }
-
- float brush_co[3];
- copy_v3_v3(brush_co, SCULPT_active_vertex_co_get(ss));
-
- BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(SCULPT_vertex_count_get(ss), "visited_vertices");
-
- /* Assuming an average of 6 edges per vertex in a triangulated mesh. */
- const int max_preview_vertices = SCULPT_vertex_count_get(ss) * 3 * 2;
-
- if (ss->preview_vert_index_list == NULL) {
- ss->preview_vert_index_list = MEM_callocN(max_preview_vertices * sizeof(int), "preview lines");
- }
-
- GSQueue *not_visited_vertices = BLI_gsqueue_new(sizeof(int));
- int active_v = SCULPT_active_vertex_get(ss);
- BLI_gsqueue_push(not_visited_vertices, &active_v);
-
- while (!BLI_gsqueue_is_empty(not_visited_vertices)) {
- int from_v;
- BLI_gsqueue_pop(not_visited_vertices, &from_v);
- SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) {
- if (totpoints + (ni.size * 2) < max_preview_vertices) {
- int to_v = ni.index;
- ss->preview_vert_index_list[totpoints] = from_v;
- totpoints++;
- ss->preview_vert_index_list[totpoints] = to_v;
- totpoints++;
- if (BLI_BITMAP_TEST(visited_vertices, to_v)) {
- continue;
- }
- BLI_BITMAP_ENABLE(visited_vertices, to_v);
- const float *co = SCULPT_vertex_co_for_grab_active_get(ss, to_v);
- if (len_squared_v3v3(brush_co, co) < radius * radius) {
- BLI_gsqueue_push(not_visited_vertices, &to_v);
- }
- }
- }
- SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
- }
-
- BLI_gsqueue_free(not_visited_vertices);
-
- MEM_freeN(visited_vertices);
-
- ss->preview_vert_index_count = totpoints;
-}
-
-static int vertex_to_loop_colors_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = CTX_data_active_object(C);
-
- ID *data;
- data = ob->data;
- if (data && ID_IS_LINKED(data)) {
- return OPERATOR_CANCELLED;
- }
-
- if (ob->type != OB_MESH) {
- return OPERATOR_CANCELLED;
- }
-
- Mesh *mesh = ob->data;
-
- const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL);
- if (mloopcol_layer_n == -1) {
- return OPERATOR_CANCELLED;
- }
- MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n);
-
- const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR);
- if (MPropCol_layer_n == -1) {
- return OPERATOR_CANCELLED;
- }
- MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n);
-
- MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP);
- MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY);
-
- for (int i = 0; i < mesh->totpoly; i++) {
- MPoly *c_poly = &polys[i];
- for (int j = 0; j < c_poly->totloop; j++) {
- int loop_index = c_poly->loopstart + j;
- MLoop *c_loop = &loops[c_poly->loopstart + j];
- float srgb_color[4];
- linearrgb_to_srgb_v4(srgb_color, vertcols[c_loop->v].color);
- loopcols[loop_index].r = (char)(srgb_color[0] * 255);
- loopcols[loop_index].g = (char)(srgb_color[1] * 255);
- loopcols[loop_index].b = (char)(srgb_color[2] * 255);
- loopcols[loop_index].a = (char)(srgb_color[3] * 255);
- }
- }
-
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_vertex_to_loop_colors(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Sculpt Vertex Color to Vertex Color";
- ot->description = "Copy the Sculpt Vertex Color to a regular color layer";
- ot->idname = "SCULPT_OT_vertex_to_loop_colors";
-
- /* api callbacks */
- ot->poll = SCULPT_vertex_colors_poll;
- ot->exec = vertex_to_loop_colors_exec;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static int loop_to_vertex_colors_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = CTX_data_active_object(C);
-
- ID *data;
- data = ob->data;
- if (data && ID_IS_LINKED(data)) {
- return OPERATOR_CANCELLED;
- }
-
- if (ob->type != OB_MESH) {
- return OPERATOR_CANCELLED;
- }
-
- Mesh *mesh = ob->data;
-
- const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL);
- if (mloopcol_layer_n == -1) {
- return OPERATOR_CANCELLED;
- }
- MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n);
-
- const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR);
- if (MPropCol_layer_n == -1) {
- return OPERATOR_CANCELLED;
- }
- MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n);
-
- MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP);
- MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY);
-
- for (int i = 0; i < mesh->totpoly; i++) {
- MPoly *c_poly = &polys[i];
- for (int j = 0; j < c_poly->totloop; j++) {
- int loop_index = c_poly->loopstart + j;
- MLoop *c_loop = &loops[c_poly->loopstart + j];
- vertcols[c_loop->v].color[0] = (loopcols[loop_index].r / 255.0f);
- vertcols[c_loop->v].color[1] = (loopcols[loop_index].g / 255.0f);
- vertcols[c_loop->v].color[2] = (loopcols[loop_index].b / 255.0f);
- vertcols[c_loop->v].color[3] = (loopcols[loop_index].a / 255.0f);
- srgb_to_linearrgb_v4(vertcols[c_loop->v].color, vertcols[c_loop->v].color);
- }
- }
-
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_loop_to_vertex_colors(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Vertex Color to Sculpt Vertex Color";
- ot->description = "Copy the active loop color layer to the vertex color";
- ot->idname = "SCULPT_OT_loop_to_vertex_colors";
-
- /* api callbacks */
- ot->poll = SCULPT_vertex_colors_poll;
- ot->exec = loop_to_vertex_colors_exec;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static int sculpt_sample_color_invoke(bContext *C,
- wmOperator *UNUSED(op),
- const wmEvent *UNUSED(e))
-{
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- Brush *brush = BKE_paint_brush(&sd->paint);
- SculptSession *ss = ob->sculpt;
- int active_vertex = SCULPT_active_vertex_get(ss);
- const float *active_vertex_color = SCULPT_vertex_color_get(ss, active_vertex);
- if (!active_vertex_color) {
- return OPERATOR_CANCELLED;
- }
-
- float color_srgb[3];
- copy_v3_v3(color_srgb, active_vertex_color);
- IMB_colormanagement_scene_linear_to_srgb_v3(color_srgb);
- BKE_brush_color_set(scene, brush, color_srgb);
-
- WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_sample_color(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Sample Color";
- ot->idname = "SCULPT_OT_sample_color";
- ot->description = "Sample the vertex color of the active vertex";
-
- /* api callbacks */
- ot->invoke = sculpt_sample_color_invoke;
- ot->poll = SCULPT_vertex_colors_poll;
-
- ot->flag = OPTYPE_REGISTER;
-}
-
/* Fake Neighbors. */
/* This allows the sculpt tools to work on meshes with multiple connected components as they had
* only one connected component. When initialized and enabled, the sculpt API will return extra
@@ -9105,356 +5682,10 @@ void SCULPT_fake_neighbors_free(Object *ob)
sculpt_pose_fake_neighbors_free(ss);
}
-/**
- * #sculpt_mask_by_color_delta_get returns values in the (0,1) range that are used to generate the
- * mask based on the difference between two colors (the active color and the color of any other
- * vertex). Ideally, a threshold of 0 should mask only the colors that are equal to the active
- * color and threshold of 1 should mask all colors. In order to avoid artifacts and produce softer
- * falloffs in the mask, the MASK_BY_COLOR_SLOPE defines the size of the transition values between
- * masked and unmasked vertices. The smaller this value is, the sharper the generated mask is going
- * to be.
- */
-#define MASK_BY_COLOR_SLOPE 0.25f
-
-static float sculpt_mask_by_color_delta_get(const float *color_a,
- const float *color_b,
- const float threshold,
- const bool invert)
-{
- float len = len_v3v3(color_a, color_b);
- /* Normalize len to the (0, 1) range. */
- len = len / M_SQRT3;
-
- if (len < threshold - MASK_BY_COLOR_SLOPE) {
- len = 1.0f;
- }
- else if (len >= threshold) {
- len = 0.0f;
- }
- else {
- len = (-len + threshold) / MASK_BY_COLOR_SLOPE;
- }
-
- if (invert) {
- return 1.0f - len;
- }
- return len;
-}
-
-static float sculpt_mask_by_color_final_mask_get(const float current_mask,
- const float new_mask,
- const bool invert,
- const bool preserve_mask)
-{
- if (preserve_mask) {
- if (invert) {
- return min_ff(current_mask, new_mask);
- }
- return max_ff(current_mask, new_mask);
- }
- return new_mask;
-}
-
-typedef struct MaskByColorContiguousFloodFillData {
- float threshold;
- bool invert;
- float *new_mask;
- float initial_color[3];
-} MaskByColorContiguousFloodFillData;
-
-static void do_mask_by_color_contiguous_update_nodes_cb(
- void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
-
- SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK);
- bool update_node = false;
-
- const bool invert = data->mask_by_color_invert;
- const bool preserve_mask = data->mask_by_color_preserve_mask;
-
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- const float current_mask = *vd.mask;
- const float new_mask = data->mask_by_color_floodfill[vd.index];
- *vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask);
- if (current_mask == *vd.mask) {
- continue;
- }
- update_node = true;
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
- if (update_node) {
- BKE_pbvh_node_mark_redraw(data->nodes[n]);
- }
-}
-
-static bool sculpt_mask_by_color_contiguous_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
-{
- MaskByColorContiguousFloodFillData *data = userdata;
- const float *current_color = SCULPT_vertex_color_get(ss, to_v);
- float new_vertex_mask = sculpt_mask_by_color_delta_get(
- current_color, data->initial_color, data->threshold, data->invert);
- data->new_mask[to_v] = new_vertex_mask;
-
- if (is_duplicate) {
- data->new_mask[to_v] = data->new_mask[from_v];
- }
-
- float len = len_v3v3(current_color, data->initial_color);
- len = len / M_SQRT3;
- return len <= data->threshold;
-}
-
-static void sculpt_mask_by_color_contiguous(Object *object,
- const int vertex,
- const float threshold,
- const bool invert,
- const bool preserve_mask)
-{
- SculptSession *ss = object->sculpt;
- const int totvert = SCULPT_vertex_count_get(ss);
-
- float *new_mask = MEM_calloc_arrayN(totvert, sizeof(float), "new mask");
-
- if (invert) {
- for (int i = 0; i < totvert; i++) {
- new_mask[i] = 1.0f;
- }
- }
-
- SculptFloodFill flood;
- SCULPT_floodfill_init(ss, &flood);
- SCULPT_floodfill_add_initial(&flood, vertex);
-
- MaskByColorContiguousFloodFillData ffd;
- ffd.threshold = threshold;
- ffd.invert = invert;
- ffd.new_mask = new_mask;
- copy_v3_v3(ffd.initial_color, SCULPT_vertex_color_get(ss, vertex));
-
- SCULPT_floodfill_execute(ss, &flood, sculpt_mask_by_color_contiguous_floodfill_cb, &ffd);
- SCULPT_floodfill_free(&flood);
-
- int totnode;
- PBVHNode **nodes;
- BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
-
- SculptThreadedTaskData data = {
- .ob = object,
- .nodes = nodes,
- .mask_by_color_floodfill = new_mask,
- .mask_by_color_vertex = vertex,
- .mask_by_color_threshold = threshold,
- .mask_by_color_invert = invert,
- .mask_by_color_preserve_mask = preserve_mask,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(
- 0, totnode, &data, do_mask_by_color_contiguous_update_nodes_cb, &settings);
-
- MEM_SAFE_FREE(nodes);
-
- MEM_freeN(new_mask);
-}
-
-static void do_mask_by_color_task_cb(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
-
- SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK);
- bool update_node = false;
-
- const float threshold = data->mask_by_color_threshold;
- const bool invert = data->mask_by_color_invert;
- const bool preserve_mask = data->mask_by_color_preserve_mask;
- const float *active_color = SCULPT_vertex_color_get(ss, data->mask_by_color_vertex);
-
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- const float current_mask = *vd.mask;
- const float new_mask = sculpt_mask_by_color_delta_get(active_color, vd.col, threshold, invert);
- *vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask);
-
- if (current_mask == *vd.mask) {
- continue;
- }
- update_node = true;
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
- if (update_node) {
- BKE_pbvh_node_mark_redraw(data->nodes[n]);
- }
-}
-
-static void sculpt_mask_by_color_full_mesh(Object *object,
- const int vertex,
- const float threshold,
- const bool invert,
- const bool preserve_mask)
-{
- SculptSession *ss = object->sculpt;
-
- int totnode;
- PBVHNode **nodes;
- BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
-
- SculptThreadedTaskData data = {
- .ob = object,
- .nodes = nodes,
- .mask_by_color_vertex = vertex,
- .mask_by_color_threshold = threshold,
- .mask_by_color_invert = invert,
- .mask_by_color_preserve_mask = preserve_mask,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_mask_by_color_task_cb, &settings);
-
- MEM_SAFE_FREE(nodes);
-}
-
-static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
-
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
-
- /* Color data is not available in Multires. */
- if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
- return OPERATOR_CANCELLED;
- }
-
- if (!ss->vcol) {
- return OPERATOR_CANCELLED;
- }
-
- SCULPT_vertex_random_access_ensure(ss);
-
- /* Tools that are not brushes do not have the brush gizmo to update the vertex as the mouse move,
- * so it needs to be updated here. */
- SculptCursorGeometryInfo sgi;
- float mouse[2];
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
-
- SCULPT_undo_push_begin(ob, "Mask by color");
-
- const int active_vertex = SCULPT_active_vertex_get(ss);
- const float threshold = RNA_float_get(op->ptr, "threshold");
- const bool invert = RNA_boolean_get(op->ptr, "invert");
- const bool preserve_mask = RNA_boolean_get(op->ptr, "preserve_previous_mask");
-
- if (RNA_boolean_get(op->ptr, "contiguous")) {
- sculpt_mask_by_color_contiguous(ob, active_vertex, threshold, invert, preserve_mask);
- }
- else {
- sculpt_mask_by_color_full_mesh(ob, active_vertex, threshold, invert, preserve_mask);
- }
-
- BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask);
- SCULPT_undo_push_end();
-
- SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_mask_by_color(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Mask by Color";
- ot->idname = "SCULPT_OT_mask_by_color";
- ot->description = "Creates a mask based on the sculpt vertex colors";
-
- /* api callbacks */
- ot->invoke = sculpt_mask_by_color_invoke;
- ot->poll = SCULPT_vertex_colors_poll;
-
- ot->flag = OPTYPE_REGISTER;
-
- ot->prop = RNA_def_boolean(
- ot->srna, "contiguous", false, "Contiguous", "Mask only contiguous color areas");
-
- ot->prop = RNA_def_boolean(ot->srna, "invert", false, "Invert", "Invert the generated mask");
- ot->prop = RNA_def_boolean(
- ot->srna,
- "preserve_previous_mask",
- false,
- "Preserve Previous Mask",
- "Preserve the previous mask and add or subtract the new one generated by the colors");
-
- RNA_def_float(ot->srna,
- "threshold",
- 0.35f,
- 0.0f,
- 1.0f,
- "Threshold",
- "How much changes in color affect the mask generation",
- 0.0f,
- 1.0f);
-}
-
/** \} */
/* -------------------------------------------------------------------- */
/** \name Operator Registration
* \{ */
-void ED_operatortypes_sculpt(void)
-{
- WM_operatortype_append(SCULPT_OT_brush_stroke);
- WM_operatortype_append(SCULPT_OT_sculptmode_toggle);
- WM_operatortype_append(SCULPT_OT_set_persistent_base);
- WM_operatortype_append(SCULPT_OT_dynamic_topology_toggle);
- WM_operatortype_append(SCULPT_OT_optimize);
- WM_operatortype_append(SCULPT_OT_symmetrize);
- WM_operatortype_append(SCULPT_OT_detail_flood_fill);
- WM_operatortype_append(SCULPT_OT_sample_detail_size);
- WM_operatortype_append(SCULPT_OT_set_detail_size);
- WM_operatortype_append(SCULPT_OT_mesh_filter);
- WM_operatortype_append(SCULPT_OT_mask_filter);
- WM_operatortype_append(SCULPT_OT_dirty_mask);
- WM_operatortype_append(SCULPT_OT_mask_expand);
- WM_operatortype_append(SCULPT_OT_set_pivot_position);
- WM_operatortype_append(SCULPT_OT_face_sets_create);
- WM_operatortype_append(SCULPT_OT_face_sets_change_visibility);
- WM_operatortype_append(SCULPT_OT_face_sets_randomize_colors);
- WM_operatortype_append(SCULPT_OT_face_sets_init);
- WM_operatortype_append(SCULPT_OT_cloth_filter);
- WM_operatortype_append(SCULPT_OT_face_sets_edit);
- WM_operatortype_append(SCULPT_OT_face_set_lasso_gesture);
- WM_operatortype_append(SCULPT_OT_face_set_box_gesture);
- WM_operatortype_append(SCULPT_OT_trim_box_gesture);
- WM_operatortype_append(SCULPT_OT_trim_lasso_gesture);
- WM_operatortype_append(SCULPT_OT_project_line_gesture);
-
- WM_operatortype_append(SCULPT_OT_sample_color);
- WM_operatortype_append(SCULPT_OT_loop_to_vertex_colors);
- WM_operatortype_append(SCULPT_OT_vertex_to_loop_colors);
- WM_operatortype_append(SCULPT_OT_color_filter);
- WM_operatortype_append(SCULPT_OT_mask_by_color);
- WM_operatortype_append(SCULPT_OT_dyntopo_detail_size_edit);
- WM_operatortype_append(SCULPT_OT_mask_init);
-
- WM_operatortype_append(SCULPT_OT_expand);
-}
-
/** \} */
diff --git a/source/blender/editors/sculpt_paint/sculpt_brushes.c b/source/blender/editors/sculpt_paint/sculpt_brushes.c
new file mode 100644
index 00000000000..8842d93410c
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_brushes.c
@@ -0,0 +1,2847 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 by Nicholas Bishop
+ * All rights reserved.
+ * Implements the Sculpt Mode tools
+ */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_dial_2d.h"
+#include "BLI_ghash.h"
+#include "BLI_gsqueue.h"
+#include "BLI_hash.h"
+#include "BLI_math.h"
+#include "BLI_math_color.h"
+#include "BLI_math_color_blend.h"
+#include "BLI_task.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "PIL_time.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_ccg.h"
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_image.h"
+#include "BKE_kelvinlet.h"
+#include "BKE_key.h"
+#include "BKE_lib_id.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_mirror.h"
+#include "BKE_modifier.h"
+#include "BKE_multires.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_particle.h"
+#include "BKE_pbvh.h"
+#include "BKE_pointcache.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_subdiv_ccg.h"
+#include "BKE_subsurf.h"
+
+#include "DEG_depsgraph.h"
+
+#include "IMB_colormanagement.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "ED_view3d.h"
+
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* -------------------------------------------------------------------- */
+/** \name SculptProjectVector
+ *
+ * Fast-path for #project_plane_v3_v3v3
+ * \{ */
+
+typedef struct SculptProjectVector {
+ float plane[3];
+ float len_sq;
+ float len_sq_inv_neg;
+ bool is_valid;
+
+} SculptProjectVector;
+
+static bool plane_point_side_flip(const float co[3], const float plane[4], const bool flip)
+{
+ float d = plane_point_side_v3(plane, co);
+ if (flip) {
+ d = -d;
+ }
+ return d <= 0.0f;
+}
+
+/**
+ * \param plane: Direction, can be any length.
+ */
+static void sculpt_project_v3_cache_init(SculptProjectVector *spvc, const float plane[3])
+{
+ copy_v3_v3(spvc->plane, plane);
+ spvc->len_sq = len_squared_v3(spvc->plane);
+ spvc->is_valid = (spvc->len_sq > FLT_EPSILON);
+ spvc->len_sq_inv_neg = (spvc->is_valid) ? -1.0f / spvc->len_sq : 0.0f;
+}
+
+/**
+ * Calculate the projection.
+ */
+static void sculpt_project_v3(const SculptProjectVector *spvc, const float vec[3], float r_vec[3])
+{
+#if 0
+ project_plane_v3_v3v3(r_vec, vec, spvc->plane);
+#else
+ /* inline the projection, cache `-1.0 / dot_v3_v3(v_proj, v_proj)` */
+ madd_v3_v3fl(r_vec, spvc->plane, dot_v3v3(vec, spvc->plane) * spvc->len_sq_inv_neg);
+#endif
+}
+
+static void calc_sculpt_plane(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3])
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ if (SCULPT_stroke_is_main_symmetry_pass(ss->cache) &&
+ (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache) ||
+ !(brush->flag & BRUSH_ORIGINAL_PLANE) || !(brush->flag & BRUSH_ORIGINAL_NORMAL))) {
+ switch (brush->sculpt_plane) {
+ case SCULPT_DISP_DIR_VIEW:
+ copy_v3_v3(r_area_no, ss->cache->true_view_normal);
+ break;
+
+ case SCULPT_DISP_DIR_X:
+ ARRAY_SET_ITEMS(r_area_no, 1.0f, 0.0f, 0.0f);
+ break;
+
+ case SCULPT_DISP_DIR_Y:
+ ARRAY_SET_ITEMS(r_area_no, 0.0f, 1.0f, 0.0f);
+ break;
+
+ case SCULPT_DISP_DIR_Z:
+ ARRAY_SET_ITEMS(r_area_no, 0.0f, 0.0f, 1.0f);
+ break;
+
+ case SCULPT_DISP_DIR_AREA:
+ SCULPT_calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co);
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(r_area_no, r_area_no, ss->cache->view_normal);
+ normalize_v3(r_area_no);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /* For flatten center. */
+ /* Flatten center has not been calculated yet if we are not using the area normal. */
+ if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA) {
+ SCULPT_calc_area_center(sd, ob, nodes, totnode, r_area_co);
+ }
+
+ /* For area normal. */
+ if ((!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) &&
+ (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
+ copy_v3_v3(r_area_no, ss->cache->sculpt_normal);
+ }
+ else {
+ copy_v3_v3(ss->cache->sculpt_normal, r_area_no);
+ }
+
+ /* For flatten center. */
+ if ((!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) &&
+ (brush->flag & BRUSH_ORIGINAL_PLANE)) {
+ copy_v3_v3(r_area_co, ss->cache->last_center);
+ }
+ else {
+ copy_v3_v3(ss->cache->last_center, r_area_co);
+ }
+ }
+ else {
+ /* For area normal. */
+ copy_v3_v3(r_area_no, ss->cache->sculpt_normal);
+
+ /* For flatten center. */
+ copy_v3_v3(r_area_co, ss->cache->last_center);
+
+ /* For area normal. */
+ flip_v3(r_area_no, ss->cache->mirror_symmetry_pass);
+
+ /* For flatten center. */
+ flip_v3(r_area_co, ss->cache->mirror_symmetry_pass);
+
+ /* For area normal. */
+ mul_m4_v3(ss->cache->symm_rot_mat, r_area_no);
+
+ /* For flatten center. */
+ mul_m4_v3(ss->cache->symm_rot_mat, r_area_co);
+
+ /* Shift the plane for the current tile. */
+ add_v3_v3(r_area_co, ss->cache->plane_offset);
+ }
+}
+
+static void sculpt_rake_rotate(const SculptSession *ss,
+ const float sculpt_co[3],
+ const float v_co[3],
+ float factor,
+ float r_delta[3])
+{
+ float vec_rot[3];
+
+#if 0
+ /* lerp */
+ sub_v3_v3v3(vec_rot, v_co, sculpt_co);
+ mul_qt_v3(ss->cache->rake_rotation_symmetry, vec_rot);
+ add_v3_v3(vec_rot, sculpt_co);
+ sub_v3_v3v3(r_delta, vec_rot, v_co);
+ mul_v3_fl(r_delta, factor);
+#else
+ /* slerp */
+ float q_interp[4];
+ sub_v3_v3v3(vec_rot, v_co, sculpt_co);
+
+ copy_qt_qt(q_interp, ss->cache->rake_rotation_symmetry);
+ pow_qt_fl_normalized(q_interp, factor);
+ mul_qt_v3(q_interp, vec_rot);
+
+ add_v3_v3(vec_rot, sculpt_co);
+ sub_v3_v3v3(r_delta, vec_rot, v_co);
+#endif
+}
+
+/**
+ * Align the grab delta to the brush normal.
+ *
+ * \param grab_delta: Typically from `ss->cache->grab_delta_symmetry`.
+ */
+static void sculpt_project_v3_normal_align(SculptSession *ss,
+ const float normal_weight,
+ float grab_delta[3])
+{
+ /* Signed to support grabbing in (to make a hole) as well as out. */
+ const float len_signed = dot_v3v3(ss->cache->sculpt_normal_symm, grab_delta);
+
+ /* This scale effectively projects the offset so dragging follows the cursor,
+ * as the normal points towards the view, the scale increases. */
+ float len_view_scale;
+ {
+ float view_aligned_normal[3];
+ project_plane_v3_v3v3(
+ view_aligned_normal, ss->cache->sculpt_normal_symm, ss->cache->view_normal);
+ len_view_scale = fabsf(dot_v3v3(view_aligned_normal, ss->cache->sculpt_normal_symm));
+ len_view_scale = (len_view_scale > FLT_EPSILON) ? 1.0f / len_view_scale : 1.0f;
+ }
+
+ mul_v3_fl(grab_delta, 1.0f - normal_weight);
+ madd_v3_v3fl(
+ grab_delta, ss->cache->sculpt_normal_symm, (len_signed * normal_weight) * len_view_scale);
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Draw Brush
+ * \{ */
+
+static void do_draw_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *offset = data->offset;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ /* Offset vertex. */
+ const float fade = SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], offset, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float offset[3];
+ const float bstrength = ss->cache->bstrength;
+
+ /* Offset with as much as possible factored in already. */
+ float effective_normal[3];
+ SCULPT_tilt_effective_normal_get(ss, brush, effective_normal);
+ mul_v3_v3fl(offset, effective_normal, ss->cache->radius);
+ mul_v3_v3(offset, ss->cache->scale);
+ mul_v3_fl(offset, bstrength);
+
+ /* XXX: this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise
+ * initialize before threads so they can do curve mapping. */
+ BKE_curvemapping_init(brush->curve);
+
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .offset = offset,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings);
+}
+
+/** \} */
+
+static void do_fill_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+
+ if (!SCULPT_plane_point_side(vd.co, test.plane_tool)) {
+ continue;
+ }
+
+ float intr[3];
+ float val[3];
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (!SCULPT_plane_trim(ss->cache, brush, val)) {
+ continue;
+ }
+
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const float radius = ss->cache->radius;
+
+ float area_no[3];
+ float area_co[3];
+ float offset = SCULPT_brush_plane_offset_get(sd, ss);
+
+ float displace;
+
+ float temp[3];
+
+ SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
+
+ SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor);
+
+ displace = radius * offset;
+
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(area_co, temp);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no = area_no,
+ .area_co = area_co,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings);
+}
+
+static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+
+ if (SCULPT_plane_point_side(vd.co, test.plane_tool)) {
+ continue;
+ }
+
+ float intr[3];
+ float val[3];
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (!SCULPT_plane_trim(ss->cache, brush, val)) {
+ continue;
+ }
+
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const float radius = ss->cache->radius;
+
+ float area_no[3];
+ float area_co[3];
+ float offset = SCULPT_brush_plane_offset_get(sd, ss);
+
+ float displace;
+
+ float temp[3];
+
+ SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
+
+ SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor);
+
+ displace = -radius * offset;
+
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(area_co, temp);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no = area_no,
+ .area_co = area_co,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Clay Thumb Brush
+ * \{ */
+
+static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ float(*mat)[4] = data->mat;
+ const float *area_no_sp = data->area_no_sp;
+ const float *area_co = data->area_co;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = data->clay_strength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ float plane_tilt[4];
+ float normal_tilt[3];
+ float imat[4][4];
+
+ invert_m4_m4(imat, mat);
+ rotate_v3_v3v3fl(normal_tilt, area_no_sp, imat[0], DEG2RADF(-ss->cache->clay_thumb_front_angle));
+
+ /* Plane aligned to the geometry normal (back part of the brush). */
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp);
+ /* Tilted plane (front part of the brush). */
+ plane_from_point_normal_v3(plane_tilt, area_co, normal_tilt);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ float local_co[3];
+ mul_v3_m4v3(local_co, mat, vd.co);
+ float intr[3], intr_tilt[3];
+ float val[3];
+
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+ closest_to_plane_normalized_v3(intr_tilt, plane_tilt, vd.co);
+
+ /* Mix the deformation of the aligned and the tilted plane based on the brush space vertex
+ * coordinates. */
+ /* We can also control the mix with a curve if it produces noticeable artifacts in the center
+ * of the brush. */
+ const float tilt_mix = local_co[1] > 0.0f ? 0.0f : 1.0f;
+ interp_v3_v3v3(intr, intr, intr_tilt, tilt_mix);
+ sub_v3_v3v3(val, intr_tilt, vd.co);
+
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+float SCULPT_clay_thumb_get_stabilized_pressure(StrokeCache *cache)
+{
+ float final_pressure = 0.0f;
+ for (int i = 0; i < SCULPT_CLAY_STABILIZER_LEN; i++) {
+ final_pressure += cache->clay_pressure_stabilizer[i];
+ }
+ return final_pressure / SCULPT_CLAY_STABILIZER_LEN;
+}
+
+void SCULPT_do_clay_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const float radius = ss->cache->radius;
+ const float offset = SCULPT_brush_plane_offset_get(sd, ss);
+ const float displace = radius * (0.25f + offset);
+
+ /* Sampled geometry normal and area center. */
+ float area_no_sp[3];
+ float area_no[3];
+ float area_co[3];
+
+ float temp[3];
+ float mat[4][4];
+ float scale[4][4];
+ float tmat[4][4];
+
+ SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no_sp, area_co);
+
+ if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
+ SCULPT_calc_area_normal(sd, ob, nodes, totnode, area_no);
+ }
+ else {
+ copy_v3_v3(area_no, area_no_sp);
+ }
+
+ /* Delay the first daub because grab delta is not setup. */
+ if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
+ ss->cache->clay_thumb_front_angle = 0.0f;
+ return;
+ }
+
+ /* Simulate the clay accumulation by increasing the plane angle as more samples are added to the
+ * stroke. */
+ if (SCULPT_stroke_is_main_symmetry_pass(ss->cache)) {
+ ss->cache->clay_thumb_front_angle += 0.8f;
+ ss->cache->clay_thumb_front_angle = clamp_f(ss->cache->clay_thumb_front_angle, 0.0f, 60.0f);
+ }
+
+ if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
+ return;
+ }
+
+ /* Displace the brush planes. */
+ copy_v3_v3(area_co, ss->cache->location);
+ mul_v3_v3v3(temp, area_no_sp, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(area_co, temp);
+
+ /* Initialize brush local-space matrix. */
+ cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
+ mat[0][3] = 0.0f;
+ cross_v3_v3v3(mat[1], area_no, mat[0]);
+ mat[1][3] = 0.0f;
+ copy_v3_v3(mat[2], area_no);
+ mat[2][3] = 0.0f;
+ copy_v3_v3(mat[3], ss->cache->location);
+ mat[3][3] = 1.0f;
+ normalize_m4(mat);
+
+ /* Scale brush local space matrix. */
+ scale_m4_fl(scale, ss->cache->radius);
+ mul_m4_m4m4(tmat, mat, scale);
+ invert_m4_m4(mat, tmat);
+
+ float clay_strength = ss->cache->bstrength *
+ SCULPT_clay_thumb_get_stabilized_pressure(ss->cache);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no_sp = area_no_sp,
+ .area_co = ss->cache->location,
+ .mat = mat,
+ .clay_strength = clay_strength,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_clay_thumb_brush_task_cb_ex, &settings);
+}
+
+/** \} */
+
+static void do_flatten_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ float intr[3];
+ float val[3];
+
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (SCULPT_plane_trim(ss->cache, brush, val)) {
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const float radius = ss->cache->radius;
+
+ float area_no[3];
+ float area_co[3];
+
+ float offset = SCULPT_brush_plane_offset_get(sd, ss);
+ float displace;
+ float temp[3];
+
+ SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
+
+ SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor);
+
+ displace = radius * offset;
+
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(area_co, temp);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no = area_no,
+ .area_co = area_co,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Clay Brush
+ * \{ */
+
+typedef struct ClaySampleData {
+ float plane_dist[2];
+} ClaySampleData;
+
+static void calc_clay_surface_task_cb(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ ClaySampleData *csd = tls->userdata_chunk;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
+ float plane[4];
+
+ PBVHVertexIter vd;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, brush->falloff_shape);
+
+ /* Apply the brush normal radius to the test before sampling. */
+ float test_radius = sqrtf(test.radius_squared);
+ test_radius *= brush->normal_radius_factor;
+ test.radius_squared = test_radius * test_radius;
+ plane_from_point_normal_v3(plane, area_co, area_no);
+
+ if (is_zero_v4(plane)) {
+ return;
+ }
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+
+ float plane_dist = dist_signed_to_plane_v3(vd.co, plane);
+ float plane_dist_abs = fabsf(plane_dist);
+ if (plane_dist > 0.0f) {
+ csd->plane_dist[0] = MIN2(csd->plane_dist[0], plane_dist_abs);
+ }
+ else {
+ csd->plane_dist[1] = MIN2(csd->plane_dist[1], plane_dist_abs);
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+}
+
+static void calc_clay_surface_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
+{
+ ClaySampleData *join = chunk_join;
+ ClaySampleData *csd = chunk;
+ join->plane_dist[0] = MIN2(csd->plane_dist[0], join->plane_dist[0]);
+ join->plane_dist[1] = MIN2(csd->plane_dist[1], join->plane_dist[1]);
+}
+
+static void do_clay_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = fabsf(ss->cache->bstrength);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+
+ float intr[3];
+ float val[3];
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+
+ sub_v3_v3v3(val, intr, vd.co);
+
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const float radius = fabsf(ss->cache->radius);
+ const float initial_radius = fabsf(ss->cache->initial_radius);
+ bool flip = ss->cache->bstrength < 0.0f;
+
+ float offset = SCULPT_brush_plane_offset_get(sd, ss);
+ float displace;
+
+ float area_no[3];
+ float area_co[3];
+ float temp[3];
+
+ SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
+
+ SculptThreadedTaskData sample_data = {
+ .sd = NULL,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .totnode = totnode,
+ .area_no = area_no,
+ .area_co = ss->cache->location,
+ };
+
+ ClaySampleData csd = {{0}};
+
+ TaskParallelSettings sample_settings;
+ BKE_pbvh_parallel_range_settings(&sample_settings, true, totnode);
+ sample_settings.func_reduce = calc_clay_surface_reduce;
+ sample_settings.userdata_chunk = &csd;
+ sample_settings.userdata_chunk_size = sizeof(ClaySampleData);
+
+ BLI_task_parallel_range(0, totnode, &sample_data, calc_clay_surface_task_cb, &sample_settings);
+
+ float d_offset = (csd.plane_dist[0] + csd.plane_dist[1]);
+ d_offset = min_ff(radius, d_offset);
+ d_offset = d_offset / radius;
+ d_offset = 1.0f - d_offset;
+ displace = fabsf(initial_radius * (0.25f + offset + (d_offset * 0.15f)));
+ if (flip) {
+ displace = -displace;
+ }
+
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ copy_v3_v3(area_co, ss->cache->location);
+ add_v3_v3(area_co, temp);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no = area_no,
+ .area_co = area_co,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings);
+}
+
+static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ float(*mat)[4] = data->mat;
+ const float *area_no_sp = data->area_no_sp;
+ const float *area_co = data->area_co;
+
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float(*proxy)[3];
+ const bool flip = (ss->cache->bstrength < 0.0f);
+ const float bstrength = flip ? -ss->cache->bstrength : ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SCULPT_brush_test_init(ss, &test);
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!SCULPT_brush_test_cube(&test, vd.co, mat, brush->tip_roundness)) {
+ continue;
+ }
+
+ if (!plane_point_side_flip(vd.co, test.plane_tool, flip)) {
+ continue;
+ }
+
+ float intr[3];
+ float val[3];
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (!SCULPT_plane_trim(ss->cache, brush, val)) {
+ continue;
+ }
+ /* The normal from the vertices is ignored, it causes glitch with planes, see: T44390. */
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ ss->cache->radius * test.dist,
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const bool flip = (ss->cache->bstrength < 0.0f);
+ const float radius = flip ? -ss->cache->radius : ss->cache->radius;
+ const float offset = SCULPT_brush_plane_offset_get(sd, ss);
+ const float displace = radius * (0.18f + offset);
+
+ /* The sculpt-plane normal (whatever its set to). */
+ float area_no_sp[3];
+
+ /* Geometry normal */
+ float area_no[3];
+ float area_co[3];
+
+ float temp[3];
+ float mat[4][4];
+ float scale[4][4];
+ float tmat[4][4];
+
+ SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no_sp, area_co);
+ SCULPT_tilt_apply_to_normal(area_no_sp, ss->cache, brush->tilt_strength_factor);
+
+ if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
+ SCULPT_calc_area_normal(sd, ob, nodes, totnode, area_no);
+ }
+ else {
+ copy_v3_v3(area_no, area_no_sp);
+ }
+
+ /* Delay the first daub because grab delta is not setup. */
+ if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
+ return;
+ }
+
+ if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
+ return;
+ }
+
+ mul_v3_v3v3(temp, area_no_sp, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(area_co, temp);
+
+ /* Clay Strips uses a cube test with falloff in the XY axis (not in Z) and a plane to deform the
+ * vertices. When in Add mode, vertices that are below the plane and inside the cube are move
+ * towards the plane. In this situation, there may be cases where a vertex is outside the cube
+ * but below the plane, so won't be deformed, causing artifacts. In order to prevent these
+ * artifacts, this displaces the test cube space in relation to the plane in order to
+ * deform more vertices that may be below it. */
+ /* The 0.7 and 1.25 factors are arbitrary and don't have any relation between them, they were set
+ * by doing multiple tests using the default "Clay Strips" brush preset. */
+ float area_co_displaced[3];
+ madd_v3_v3v3fl(area_co_displaced, area_co, area_no, -radius * 0.7f);
+
+ /* Initialize brush local-space matrix. */
+ cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
+ mat[0][3] = 0.0f;
+ cross_v3_v3v3(mat[1], area_no, mat[0]);
+ mat[1][3] = 0.0f;
+ copy_v3_v3(mat[2], area_no);
+ mat[2][3] = 0.0f;
+ copy_v3_v3(mat[3], area_co_displaced);
+ mat[3][3] = 1.0f;
+ normalize_m4(mat);
+
+ /* Scale brush local space matrix. */
+ scale_m4_fl(scale, ss->cache->radius);
+ mul_m4_m4m4(tmat, mat, scale);
+
+ /* Deform the local space in Z to scale the test cube. As the test cube does not have falloff in
+ * Z this does not produce artifacts in the falloff cube and allows to deform extra vertices
+ * during big deformation while keeping the surface as uniform as possible. */
+ mul_v3_fl(tmat[2], 1.25f);
+
+ invert_m4_m4(mat, tmat);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no_sp = area_no_sp,
+ .area_co = area_co,
+ .mat = mat,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings);
+}
+
+static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ SculptProjectVector *spvc = data->spvc;
+ const float *grab_delta = data->grab_delta;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+ const bool do_rake_rotation = ss->cache->is_rake_rotation_valid;
+ const bool do_pinch = (brush->crease_pinch_factor != 0.5f);
+ const float pinch = do_pinch ? (2.0f * (0.5f - brush->crease_pinch_factor) *
+ (len_v3(grab_delta) / ss->cache->radius)) :
+ 0.0f;
+
+ const bool do_elastic = brush->snake_hook_deform_type == BRUSH_SNAKE_HOOK_DEFORM_ELASTIC;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ KelvinletParams params;
+ BKE_kelvinlet_init_params(&params, ss->cache->radius, bstrength, 1.0f, 0.4f);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!do_elastic && !sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+
+ float fade;
+ if (do_elastic) {
+ fade = 1.0f;
+ }
+ else {
+ fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+ }
+
+ mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
+
+ /* Negative pinch will inflate, helps maintain volume. */
+ if (do_pinch) {
+ float delta_pinch_init[3], delta_pinch[3];
+
+ sub_v3_v3v3(delta_pinch, vd.co, test.location);
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(delta_pinch, delta_pinch, ss->cache->true_view_normal);
+ }
+
+ /* Important to calculate based on the grabbed location
+ * (intentionally ignore fade here). */
+ add_v3_v3(delta_pinch, grab_delta);
+
+ sculpt_project_v3(spvc, delta_pinch, delta_pinch);
+
+ copy_v3_v3(delta_pinch_init, delta_pinch);
+
+ float pinch_fade = pinch * fade;
+ /* When reducing, scale reduction back by how close to the center we are,
+ * so we don't pinch into nothingness. */
+ if (pinch > 0.0f) {
+ /* Square to have even less impact for close vertices. */
+ pinch_fade *= pow2f(min_ff(1.0f, len_v3(delta_pinch) / ss->cache->radius));
+ }
+ mul_v3_fl(delta_pinch, 1.0f + pinch_fade);
+ sub_v3_v3v3(delta_pinch, delta_pinch_init, delta_pinch);
+ add_v3_v3(proxy[vd.i], delta_pinch);
+ }
+
+ if (do_rake_rotation) {
+ float delta_rotate[3];
+ sculpt_rake_rotate(ss, test.location, vd.co, fade, delta_rotate);
+ add_v3_v3(proxy[vd.i], delta_rotate);
+ }
+
+ if (do_elastic) {
+ float disp[3];
+ BKE_kelvinlet_grab_triscale(disp, &params, vd.co, ss->cache->location, proxy[vd.i]);
+ mul_v3_fl(disp, bstrength * 20.0f);
+ if (vd.mask) {
+ mul_v3_fl(disp, 1.0f - *vd.mask);
+ }
+ mul_v3_fl(disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index));
+ copy_v3_v3(proxy[vd.i], disp);
+ }
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ const float bstrength = ss->cache->bstrength;
+ float grab_delta[3];
+
+ SculptProjectVector spvc;
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ if (bstrength < 0.0f) {
+ negate_v3(grab_delta);
+ }
+
+ if (ss->cache->normal_weight > 0.0f) {
+ sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
+ }
+
+ /* Optionally pinch while painting. */
+ if (brush->crease_pinch_factor != 0.5f) {
+ sculpt_project_v3_cache_init(&spvc, grab_delta);
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .spvc = &spvc,
+ .grab_delta = grab_delta,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings);
+}
+
+static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *cono = data->cono;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], cono, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float grab_delta[3];
+ float tmp[3], cono[3];
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
+ cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .cono = cono,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings);
+}
+
+static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float angle = data->angle;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ float vec[3], rot[3][3];
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ sub_v3_v3v3(vec, orig_data.co, ss->cache->location);
+ axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade);
+ mul_v3_m3v3(proxy[vd.i], rot, vec);
+ add_v3_v3(proxy[vd.i], ss->cache->location);
+ sub_v3_v3(proxy[vd.i], orig_data.co);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ static const int flip[8] = {1, -1, -1, 1, -1, 1, 1, -1};
+ const float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass];
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .angle = angle,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings);
+}
+
+static void do_layer_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ const Brush *brush = data->brush;
+
+ const bool use_persistent_base = ss->persistent_base && brush->flag & BRUSH_PERSISTENT;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ const float bstrength = ss->cache->bstrength;
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ const float fade = SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ const int vi = vd.index;
+ float *disp_factor;
+ if (use_persistent_base) {
+ disp_factor = &ss->persistent_base[vi].disp;
+ }
+ else {
+ disp_factor = &ss->cache->layer_displacement_factor[vi];
+ }
+
+ /* When using persistent base, the layer brush (holding Control) invert mode resets the
+ * height of the layer to 0. This makes possible to clean edges of previously added layers
+ * on top of the base. */
+ /* The main direction of the layers is inverted using the regular brush strength with the
+ * brush direction property. */
+ if (use_persistent_base && ss->cache->invert) {
+ (*disp_factor) += fabsf(fade * bstrength * (*disp_factor)) *
+ ((*disp_factor) > 0.0f ? -1.0f : 1.0f);
+ }
+ else {
+ (*disp_factor) += fade * bstrength * (1.05f - fabsf(*disp_factor));
+ }
+ if (vd.mask) {
+ const float clamp_mask = 1.0f - *vd.mask;
+ *disp_factor = clamp_f(*disp_factor, -clamp_mask, clamp_mask);
+ }
+ else {
+ *disp_factor = clamp_f(*disp_factor, -1.0f, 1.0f);
+ }
+
+ float final_co[3];
+ float normal[3];
+
+ if (use_persistent_base) {
+ SCULPT_vertex_persistent_normal_get(ss, vi, normal);
+ mul_v3_fl(normal, brush->height);
+ madd_v3_v3v3fl(final_co, SCULPT_vertex_persistent_co_get(ss, vi), normal, *disp_factor);
+ }
+ else {
+ normal_short_to_float_v3(normal, orig_data.no);
+ mul_v3_fl(normal, brush->height);
+ madd_v3_v3v3fl(final_co, orig_data.co, normal, *disp_factor);
+ }
+
+ float vdisp[3];
+ sub_v3_v3v3(vdisp, final_co, vd.co);
+ mul_v3_fl(vdisp, fabsf(fade));
+ add_v3_v3v3(final_co, vd.co, vdisp);
+
+ SCULPT_clip(sd, ss, vd.co, final_co);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ if (ss->cache->layer_displacement_factor == NULL) {
+ ss->cache->layer_displacement_factor = MEM_callocN(sizeof(float) * SCULPT_vertex_count_get(ss),
+ "layer displacement factor");
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings);
+}
+
+static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+ float val[3];
+
+ if (vd.fno) {
+ copy_v3_v3(val, vd.fno);
+ }
+ else {
+ normal_short_to_float_v3(val, vd.no);
+ }
+
+ mul_v3_fl(val, fade * ss->cache->radius);
+ mul_v3_v3v3(proxy[vd.i], val, ss->cache->scale);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings);
+}
+
+static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *cono = data->cono;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], cono, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float grab_delta[3];
+ float tmp[3], cono[3];
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
+ cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .cono = cono,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings);
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Crease & Blob Brush
+ * \{ */
+
+/**
+ * Used for 'SCULPT_TOOL_CREASE' and 'SCULPT_TOOL_BLOB'
+ */
+static void do_crease_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ SculptProjectVector *spvc = data->spvc;
+ const float flippedbstrength = data->flippedbstrength;
+ const float *offset = data->offset;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ /* Offset vertex. */
+ const float fade = SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+ float val1[3];
+ float val2[3];
+
+ /* First we pinch. */
+ sub_v3_v3v3(val1, test.location, vd.co);
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(val1, val1, ss->cache->view_normal);
+ }
+
+ mul_v3_fl(val1, fade * flippedbstrength);
+
+ sculpt_project_v3(spvc, val1, val1);
+
+ /* Then we draw. */
+ mul_v3_v3fl(val2, offset, fade);
+
+ add_v3_v3v3(proxy[vd.i], val1, val2);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ const Scene *scene = ss->cache->vc->scene;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float offset[3];
+ float bstrength = ss->cache->bstrength;
+ float flippedbstrength, crease_correction;
+ float brush_alpha;
+
+ SculptProjectVector spvc;
+
+ /* Offset with as much as possible factored in already. */
+ mul_v3_v3fl(offset, ss->cache->sculpt_normal_symm, ss->cache->radius);
+ mul_v3_v3(offset, ss->cache->scale);
+ mul_v3_fl(offset, bstrength);
+
+ /* We divide out the squared alpha and multiply by the squared crease
+ * to give us the pinch strength. */
+ crease_correction = brush->crease_pinch_factor * brush->crease_pinch_factor;
+ brush_alpha = BKE_brush_alpha_get(scene, brush);
+ if (brush_alpha > 0.0f) {
+ crease_correction /= brush_alpha * brush_alpha;
+ }
+
+ /* We always want crease to pinch or blob to relax even when draw is negative. */
+ flippedbstrength = (bstrength < 0.0f) ? -crease_correction * bstrength :
+ crease_correction * bstrength;
+
+ if (brush->sculpt_tool == SCULPT_TOOL_BLOB) {
+ flippedbstrength *= -1.0f;
+ }
+
+ /* Use surface normal for 'spvc', so the vertices are pinched towards a line instead of a single
+ * point. Without this we get a 'flat' surface surrounding the pinch. */
+ sculpt_project_v3_cache_init(&spvc, ss->cache->sculpt_normal_symm);
+
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .spvc = &spvc,
+ .offset = offset,
+ .flippedbstrength = flippedbstrength,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings);
+}
+
+static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ float(*stroke_xz)[3] = data->stroke_xz;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ float x_object_space[3];
+ float z_object_space[3];
+ copy_v3_v3(x_object_space, stroke_xz[0]);
+ copy_v3_v3(z_object_space, stroke_xz[1]);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+ float disp_center[3];
+ float x_disp[3];
+ float z_disp[3];
+ /* Calculate displacement from the vertex to the brush center. */
+ sub_v3_v3v3(disp_center, test.location, vd.co);
+
+ /* Project the displacement into the X vector (aligned to the stroke). */
+ mul_v3_v3fl(x_disp, x_object_space, dot_v3v3(disp_center, x_object_space));
+
+ /* Project the displacement into the Z vector (aligned to the surface normal). */
+ mul_v3_v3fl(z_disp, z_object_space, dot_v3v3(disp_center, z_object_space));
+
+ /* Add the two projected vectors to calculate the final displacement.
+ * The Y component is removed. */
+ add_v3_v3v3(disp_center, x_disp, z_disp);
+
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(disp_center, disp_center, ss->cache->view_normal);
+ }
+ mul_v3_v3fl(proxy[vd.i], disp_center, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ float area_no[3];
+ float area_co[3];
+
+ float mat[4][4];
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
+
+ /* delay the first daub because grab delta is not setup */
+ if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
+ return;
+ }
+
+ if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
+ return;
+ }
+
+ /* Initialize `mat`. */
+ cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
+ mat[0][3] = 0.0f;
+ cross_v3_v3v3(mat[1], area_no, mat[0]);
+ mat[1][3] = 0.0f;
+ copy_v3_v3(mat[2], area_no);
+ mat[2][3] = 0.0f;
+ copy_v3_v3(mat[3], ss->cache->location);
+ mat[3][3] = 1.0f;
+ normalize_m4(mat);
+
+ float stroke_xz[2][3];
+ normalize_v3_v3(stroke_xz[0], mat[0]);
+ normalize_v3_v3(stroke_xz[1], mat[2]);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .stroke_xz = stroke_xz,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings);
+}
+
+static void do_grab_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *grab_delta = data->grab_delta;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ const bool grab_silhouette = brush->flag2 & BRUSH_GRAB_SILHOUETTE;
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ if (grab_silhouette) {
+ float silhouette_test_dir[3];
+ normalize_v3_v3(silhouette_test_dir, grab_delta);
+ if (dot_v3v3(ss->cache->initial_normal, ss->cache->grab_delta_symmetry) < 0.0f) {
+ mul_v3_fl(silhouette_test_dir, -1.0f);
+ }
+ float vno[3];
+ normal_short_to_float_v3(vno, orig_data.no);
+ fade *= max_ff(dot_v3v3(vno, silhouette_test_dir), 0.0f);
+ }
+
+ mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float grab_delta[3];
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ if (ss->cache->normal_weight > 0.0f) {
+ sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .grab_delta = grab_delta,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings);
+}
+
+static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *grab_delta = data->grab_delta;
+ const float *location = ss->cache->location;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+
+ const float bstrength = ss->cache->bstrength;
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ float dir;
+ if (ss->cache->mouse[0] > ss->cache->initial_mouse[0]) {
+ dir = 1.0f;
+ }
+ else {
+ dir = -1.0f;
+ }
+
+ if (brush->elastic_deform_type == BRUSH_ELASTIC_DEFORM_TWIST) {
+ int symm = ss->cache->mirror_symmetry_pass;
+ if (ELEM(symm, 1, 2, 4, 7)) {
+ dir = -dir;
+ }
+ }
+
+ KelvinletParams params;
+ float force = len_v3(grab_delta) * dir * bstrength;
+ BKE_kelvinlet_init_params(
+ &params, ss->cache->radius, force, 1.0f, brush->elastic_deform_volume_preservation);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+ float final_disp[3];
+ switch (brush->elastic_deform_type) {
+ case BRUSH_ELASTIC_DEFORM_GRAB:
+ BKE_kelvinlet_grab(final_disp, &params, orig_data.co, location, grab_delta);
+ mul_v3_fl(final_disp, bstrength * 20.0f);
+ break;
+ case BRUSH_ELASTIC_DEFORM_GRAB_BISCALE: {
+ BKE_kelvinlet_grab_biscale(final_disp, &params, orig_data.co, location, grab_delta);
+ mul_v3_fl(final_disp, bstrength * 20.0f);
+ break;
+ }
+ case BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE: {
+ BKE_kelvinlet_grab_triscale(final_disp, &params, orig_data.co, location, grab_delta);
+ mul_v3_fl(final_disp, bstrength * 20.0f);
+ break;
+ }
+ case BRUSH_ELASTIC_DEFORM_SCALE:
+ BKE_kelvinlet_scale(
+ final_disp, &params, orig_data.co, location, ss->cache->sculpt_normal_symm);
+ break;
+ case BRUSH_ELASTIC_DEFORM_TWIST:
+ BKE_kelvinlet_twist(
+ final_disp, &params, orig_data.co, location, ss->cache->sculpt_normal_symm);
+ break;
+ }
+
+ if (vd.mask) {
+ mul_v3_fl(final_disp, 1.0f - *vd.mask);
+ }
+
+ mul_v3_fl(final_disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index));
+
+ copy_v3_v3(proxy[vd.i], final_disp);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float grab_delta[3];
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ if (ss->cache->normal_weight > 0.0f) {
+ sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .grab_delta = grab_delta,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings);
+}
+/** \} */
+
+static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *offset = data->offset;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ /* Offset vertex. */
+ const float fade = SCULPT_brush_strength_factor(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], offset, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float offset[3];
+ const float bstrength = ss->cache->bstrength;
+
+ /* Offset with as much as possible factored in already. */
+ float effective_normal[3];
+ SCULPT_tilt_effective_normal_get(ss, brush, effective_normal);
+ mul_v3_v3fl(offset, effective_normal, ss->cache->radius);
+ mul_v3_v3(offset, ss->cache->scale);
+ mul_v3_fl(offset, bstrength);
+
+ /* XXX: this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise
+ * initialize before threads so they can do curve mapping. */
+ BKE_curvemapping_init(brush->curve);
+
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .offset = offset,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings);
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Topology Brush
+ * \{ */
+
+static void do_topology_slide_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ const float fade = SCULPT_brush_strength_factor(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+ float current_disp[3];
+ float current_disp_norm[3];
+ float final_disp[3] = {0.0f, 0.0f, 0.0f};
+
+ switch (brush->slide_deform_type) {
+ case BRUSH_SLIDE_DEFORM_DRAG:
+ sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location);
+ break;
+ case BRUSH_SLIDE_DEFORM_PINCH:
+ sub_v3_v3v3(current_disp, ss->cache->location, vd.co);
+ break;
+ case BRUSH_SLIDE_DEFORM_EXPAND:
+ sub_v3_v3v3(current_disp, vd.co, ss->cache->location);
+ break;
+ }
+
+ normalize_v3_v3(current_disp_norm, current_disp);
+ mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
+
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ float vertex_disp[3];
+ float vertex_disp_norm[3];
+ sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.index), vd.co);
+ normalize_v3_v3(vertex_disp_norm, vertex_disp);
+ if (dot_v3v3(current_disp_norm, vertex_disp_norm) > 0.0f) {
+ madd_v3_v3fl(final_disp, vertex_disp_norm, dot_v3v3(current_disp, vertex_disp));
+ }
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ mul_v3_v3fl(proxy[vd.i], final_disp, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_relax_vertex(SculptSession *ss,
+ PBVHVertexIter *vd,
+ float factor,
+ bool filter_boundary_face_sets,
+ float *r_final_pos)
+{
+ float smooth_pos[3];
+ float final_disp[3];
+ float boundary_normal[3];
+ int avg_count = 0;
+ int neighbor_count = 0;
+ zero_v3(smooth_pos);
+ zero_v3(boundary_normal);
+ const bool is_boundary = SCULPT_vertex_is_boundary(ss, vd->index);
+
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->index, ni) {
+ neighbor_count++;
+ if (!filter_boundary_face_sets ||
+ (filter_boundary_face_sets && !SCULPT_vertex_has_unique_face_set(ss, ni.index))) {
+
+ /* When the vertex to relax is boundary, use only connected boundary vertices for the average
+ * position. */
+ if (is_boundary) {
+ if (!SCULPT_vertex_is_boundary(ss, ni.index)) {
+ continue;
+ }
+ add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index));
+ avg_count++;
+
+ /* Calculate a normal for the constraint plane using the edges of the boundary. */
+ float to_neighbor[3];
+ sub_v3_v3v3(to_neighbor, SCULPT_vertex_co_get(ss, ni.index), vd->co);
+ normalize_v3(to_neighbor);
+ add_v3_v3(boundary_normal, to_neighbor);
+ }
+ else {
+ add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index));
+ avg_count++;
+ }
+ }
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ /* Don't modify corner vertices. */
+ if (neighbor_count <= 2) {
+ copy_v3_v3(r_final_pos, vd->co);
+ return;
+ }
+
+ if (avg_count > 0) {
+ mul_v3_fl(smooth_pos, 1.0f / avg_count);
+ }
+ else {
+ copy_v3_v3(r_final_pos, vd->co);
+ return;
+ }
+
+ float plane[4];
+ float smooth_closest_plane[3];
+ float vno[3];
+
+ if (is_boundary && avg_count == 2) {
+ normalize_v3_v3(vno, boundary_normal);
+ }
+ else {
+ SCULPT_vertex_normal_get(ss, vd->index, vno);
+ }
+
+ if (is_zero_v3(vno)) {
+ copy_v3_v3(r_final_pos, vd->co);
+ return;
+ }
+
+ plane_from_point_normal_v3(plane, vd->co, vno);
+ closest_to_plane_v3(smooth_closest_plane, plane, smooth_pos);
+ sub_v3_v3v3(final_disp, smooth_closest_plane, vd->co);
+
+ mul_v3_fl(final_disp, factor);
+ add_v3_v3v3(r_final_pos, vd->co, final_disp);
+}
+
+static void do_topology_relax_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float bstrength = ss->cache->bstrength;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n]);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ const float fade = SCULPT_brush_strength_factor(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ SCULPT_relax_vertex(ss, &vd, fade * bstrength, false, vd.co);
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_slide_relax_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
+ return;
+ }
+
+ BKE_curvemapping_init(brush->curve);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ if (ss->cache->alt_smooth) {
+ SCULPT_boundary_info_ensure(ob);
+ for (int i = 0; i < 4; i++) {
+ BLI_task_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings);
+ }
+ }
+ else {
+ BLI_task_parallel_range(0, totnode, &data, do_topology_slide_task_cb_ex, &settings);
+ }
+}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Multires Displacement Eraser Brush
+ * \{ */
+
+static void do_displacement_eraser_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f);
+
+ float(*proxy)[3] = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ float limit_co[3];
+ float disp[3];
+ SCULPT_vertex_limit_surface_get(ss, vd.index, limit_co);
+ sub_v3_v3v3(disp, limit_co, vd.co);
+ mul_v3_v3fl(proxy[vd.i], disp, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_displacement_eraser_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ BKE_curvemapping_init(brush->curve);
+
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_displacement_eraser_brush_task_cb_ex, &settings);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Multires Displacement Smear Brush
+ * \{ */
+
+static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ float current_disp[3];
+ float current_disp_norm[3];
+ float interp_limit_surface_disp[3];
+
+ copy_v3_v3(interp_limit_surface_disp, ss->cache->prev_displacement[vd.index]);
+
+ switch (brush->smear_deform_type) {
+ case BRUSH_SMEAR_DEFORM_DRAG:
+ sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location);
+ break;
+ case BRUSH_SMEAR_DEFORM_PINCH:
+ sub_v3_v3v3(current_disp, ss->cache->location, vd.co);
+ break;
+ case BRUSH_SMEAR_DEFORM_EXPAND:
+ sub_v3_v3v3(current_disp, vd.co, ss->cache->location);
+ break;
+ }
+
+ normalize_v3_v3(current_disp_norm, current_disp);
+ mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
+
+ float weights_accum = 1.0f;
+
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ float vertex_disp[3];
+ float vertex_disp_norm[3];
+ float neighbor_limit_co[3];
+ SCULPT_vertex_limit_surface_get(ss, ni.index, neighbor_limit_co);
+ sub_v3_v3v3(vertex_disp,
+ ss->cache->limit_surface_co[ni.index],
+ ss->cache->limit_surface_co[vd.index]);
+ const float *neighbor_limit_surface_disp = ss->cache->prev_displacement[ni.index];
+ normalize_v3_v3(vertex_disp_norm, vertex_disp);
+
+ if (dot_v3v3(current_disp_norm, vertex_disp_norm) >= 0.0f) {
+ continue;
+ }
+
+ const float disp_interp = clamp_f(
+ -dot_v3v3(current_disp_norm, vertex_disp_norm), 0.0f, 1.0f);
+ madd_v3_v3fl(interp_limit_surface_disp, neighbor_limit_surface_disp, disp_interp);
+ weights_accum += disp_interp;
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ mul_v3_fl(interp_limit_surface_disp, 1.0f / weights_accum);
+
+ float new_co[3];
+ add_v3_v3v3(new_co, ss->cache->limit_surface_co[vd.index], interp_limit_surface_disp);
+ interp_v3_v3v3(vd.co, vd.co, new_co, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_displacement_smear_store_prev_disp_task_cb_ex(
+ void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ sub_v3_v3v3(ss->cache->prev_displacement[vd.index],
+ SCULPT_vertex_co_get(ss, vd.index),
+ ss->cache->limit_surface_co[vd.index]);
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_displacement_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+
+ BKE_curvemapping_init(brush->curve);
+
+ const int totvert = SCULPT_vertex_count_get(ss);
+ if (!ss->cache->prev_displacement) {
+ ss->cache->prev_displacement = MEM_malloc_arrayN(
+ totvert, sizeof(float[3]), "prev displacement");
+ ss->cache->limit_surface_co = MEM_malloc_arrayN(totvert, sizeof(float[3]), "limit surface co");
+ for (int i = 0; i < totvert; i++) {
+ SCULPT_vertex_limit_surface_get(ss, i, ss->cache->limit_surface_co[i]);
+ sub_v3_v3v3(ss->cache->prev_displacement[i],
+ SCULPT_vertex_co_get(ss, i),
+ ss->cache->limit_surface_co[i]);
+ }
+ }
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(
+ 0, totnode, &data, do_displacement_smear_store_prev_disp_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_displacement_smear_brush_task_cb_ex, &settings);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Topology Rake (Shared Utility)
+ * \{ */
+
+static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ const Brush *brush = data->brush;
+
+ float direction[3];
+ copy_v3_v3(direction, ss->cache->grab_delta_symmetry);
+
+ float tmp[3];
+ mul_v3_v3fl(
+ tmp, ss->cache->sculpt_normal_symm, dot_v3v3(ss->cache->sculpt_normal_symm, direction));
+ sub_v3_v3(direction, tmp);
+ normalize_v3(direction);
+
+ /* Cancel if there's no grab data. */
+ if (is_zero_v3(direction)) {
+ return;
+ }
+
+ const float bstrength = clamp_f(data->strength, 0.0f, 1.0f);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ const float fade =
+ bstrength *
+ SCULPT_brush_strength_factor(
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, vd.index, thread_id) *
+ ss->cache->pressure;
+
+ float avg[3], val[3];
+
+ SCULPT_bmesh_four_neighbor_average(avg, direction, vd.bm_vert);
+
+ sub_v3_v3v3(val, avg, vd.co);
+
+ madd_v3_v3v3fl(val, vd.co, val, fade);
+
+ SCULPT_clip(sd, ss, vd.co, val);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_bmesh_topology_rake(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, float bstrength)
+{
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ const float strength = clamp_f(bstrength, 0.0f, 1.0f);
+
+ /* Interactions increase both strength and quality. */
+ const int iterations = 3;
+
+ int iteration;
+ const int count = iterations * strength + 1;
+ const float factor = iterations * strength / count;
+
+ for (iteration = 0; iteration <= count; iteration++) {
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .strength = factor,
+ };
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+
+ BLI_task_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Mask Brush
+ * \{ */
+
+static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float bstrength = ss->cache->bstrength;
+
+ PBVHVertexIter vd;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+
+ const float fade = SCULPT_brush_strength_factor(
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id);
+
+ if (bstrength > 0.0f) {
+ (*vd.mask) += fade * bstrength * (1.0f - *vd.mask);
+ }
+ else {
+ (*vd.mask) += fade * bstrength * (*vd.mask);
+ }
+ *vd.mask = clamp_f(*vd.mask, 0.0f, 1.0f);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+}
+
+void SCULPT_do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings);
+}
+
+void SCULPT_do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ switch ((BrushMaskTool)brush->mask_tool) {
+ case BRUSH_MASK_DRAW:
+ SCULPT_do_mask_brush_draw(sd, ob, nodes, totnode);
+ break;
+ case BRUSH_MASK_SMOOTH:
+ SCULPT_smooth(sd, ob, nodes, totnode, ss->cache->bstrength, true);
+ break;
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 4dd2a786922..b85b00fb636 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -29,13 +29,13 @@
#include "DNA_meshdata_types.h"
#include "DNA_vec_types.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
#include "BLI_bitmap.h"
+#include "BLI_compiler_compat.h"
#include "BLI_gsqueue.h"
#include "BLI_threads.h"
-#include "BKE_paint.h"
-#include "BKE_pbvh.h"
-
struct AutomaskingCache;
struct KeyBlock;
struct Object;
@@ -300,6 +300,10 @@ void SCULPT_calc_brush_plane(struct Sculpt *sd,
void SCULPT_calc_area_normal(
Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3]);
+void SCULPT_calc_area_normal_and_center(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3]);
+void SCULPT_calc_area_center(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_co[3]);
int SCULPT_nearest_vertex_get(struct Sculpt *sd,
struct Object *ob,
@@ -1506,3 +1510,115 @@ void SCULPT_OT_dyntopo_detail_size_edit(struct wmOperatorType *ot);
/* Dyntopo. */
void SCULPT_OT_dynamic_topology_toggle(struct wmOperatorType *ot);
+
+/* sculpt_brushes.c */
+
+float SCULPT_clay_thumb_get_stabilized_pressure(struct StrokeCache *cache);
+
+void SCULPT_do_draw_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+
+void SCULPT_do_fill_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_scrape_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_clay_thumb_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_flatten_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_clay_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_clay_strips_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_snake_hook_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_thumb_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_rotate_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_layer_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_inflate_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_nudge_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_crease_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_pinch_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_grab_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_elastic_deform_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_draw_sharp_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_slide_relax_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+
+void SCULPT_do_displacement_smear_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_displacement_eraser_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_mask_brush_draw(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_mask_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+
+void SCULPT_bmesh_topology_rake(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ const int totnode,
+ float bstrength);
+
+/* end sculpt_brushes.c */
+
+/* sculpt_ops.c */
+void SCULPT_OT_brush_stroke(struct wmOperatorType *ot);
+
+/* end sculpt_ops.c */
diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c
new file mode 100644
index 00000000000..119d246a770
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_ops.c
@@ -0,0 +1,1141 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 by Nicholas Bishop
+ * All rights reserved.
+ * Implements the Sculpt Mode tools
+ */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_array.h"
+#include "BLI_blenlib.h"
+#include "BLI_dial_2d.h"
+#include "BLI_ghash.h"
+#include "BLI_gsqueue.h"
+#include "BLI_hash.h"
+#include "BLI_link_utils.h"
+#include "BLI_linklist.h"
+#include "BLI_linklist_stack.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_math_color_blend.h"
+#include "BLI_memarena.h"
+#include "BLI_rand.h"
+#include "BLI_task.h"
+#include "BLI_utildefines.h"
+#include "atomic_ops.h"
+
+#include "BLT_translation.h"
+
+#include "PIL_time.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_listBase.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_attribute.h"
+#include "BKE_brush.h"
+#include "BKE_ccg.h"
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_image.h"
+#include "BKE_kelvinlet.h"
+#include "BKE_key.h"
+#include "BKE_lib_id.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_fair.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_mirror.h"
+#include "BKE_modifier.h"
+#include "BKE_multires.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_particle.h"
+#include "BKE_pbvh.h"
+#include "BKE_pointcache.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_subdiv_ccg.h"
+#include "BKE_subsurf.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "IMB_colormanagement.h"
+
+#include "GPU_batch.h"
+#include "GPU_batch_presets.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "ED_space_api.h"
+#include "ED_transform_snap_object_context.h"
+#include "ED_view3d.h"
+
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Reset the copy of the mesh that is being sculpted on (currently just for the layer brush). */
+
+static int sculpt_set_persistent_base_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+
+ if (!ss) {
+ return OPERATOR_FINISHED;
+ }
+ SCULPT_vertex_random_access_ensure(ss);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
+
+ MEM_SAFE_FREE(ss->persistent_base);
+
+ const int totvert = SCULPT_vertex_count_get(ss);
+ ss->persistent_base = MEM_mallocN(sizeof(SculptPersistentBase) * totvert,
+ "layer persistent base");
+
+ for (int i = 0; i < totvert; i++) {
+ copy_v3_v3(ss->persistent_base[i].co, SCULPT_vertex_co_get(ss, i));
+ SCULPT_vertex_normal_get(ss, i, ss->persistent_base[i].no);
+ ss->persistent_base[i].disp = 0.0f;
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Set Persistent Base";
+ ot->idname = "SCULPT_OT_set_persistent_base";
+ ot->description = "Reset the copy of the mesh that is being sculpted on";
+
+ /* API callbacks. */
+ ot->exec = sculpt_set_persistent_base_exec;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/************************* SCULPT_OT_optimize *************************/
+
+static int sculpt_optimize_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_active_object(C);
+
+ SCULPT_pbvh_clear(ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+/* The BVH gets less optimal more quickly with dynamic topology than
+ * regular sculpting. There is no doubt more clever stuff we can do to
+ * optimize it on the fly, but for now this gives the user a nicer way
+ * to recalculate it than toggling modes. */
+static void SCULPT_OT_optimize(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Rebuild BVH";
+ ot->idname = "SCULPT_OT_optimize";
+ ot->description = "Recalculate the sculpt BVH to improve performance";
+
+ /* API callbacks. */
+ ot->exec = sculpt_optimize_exec;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/********************* Dynamic topology symmetrize ********************/
+
+static bool sculpt_no_multires_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+ if (SCULPT_mode_poll(C) && ob->sculpt && ob->sculpt->pbvh) {
+ return BKE_pbvh_type(ob->sculpt->pbvh) != PBVH_GRIDS;
+ }
+ return false;
+}
+
+static int sculpt_symmetrize_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+ const Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ SculptSession *ss = ob->sculpt;
+ PBVH *pbvh = ss->pbvh;
+ const float dist = RNA_float_get(op->ptr, "merge_tolerance");
+
+ if (!pbvh) {
+ return OPERATOR_CANCELLED;
+ }
+
+ switch (BKE_pbvh_type(pbvh)) {
+ case PBVH_BMESH:
+ /* Dyntopo Symmetrize. */
+
+ /* To simplify undo for symmetrize, all BMesh elements are logged
+ * as deleted, then after symmetrize operation all BMesh elements
+ * are logged as added (as opposed to attempting to store just the
+ * parts that symmetrize modifies). */
+ SCULPT_undo_push_begin(ob, "Dynamic topology symmetrize");
+ SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE);
+ BM_log_before_all_removed(ss->bm, ss->bm_log);
+
+ BM_mesh_toolflags_set(ss->bm, true);
+
+ /* Symmetrize and re-triangulate. */
+ BMO_op_callf(ss->bm,
+ (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
+ "symmetrize input=%avef direction=%i dist=%f use_shapekey=%b",
+ sd->symmetrize_direction,
+ dist,
+ true);
+ SCULPT_dynamic_topology_triangulate(ss->bm);
+
+ /* Bisect operator flags edges (keep tags clean for edge queue). */
+ BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false);
+
+ BM_mesh_toolflags_set(ss->bm, false);
+
+ /* Finish undo. */
+ BM_log_all_added(ss->bm, ss->bm_log);
+ SCULPT_undo_push_end();
+
+ break;
+ case PBVH_FACES:
+ /* Mesh Symmetrize. */
+ ED_sculpt_undo_geometry_begin(ob, "mesh symmetrize");
+ Mesh *mesh = ob->data;
+
+ BKE_mesh_mirror_apply_mirror_on_axis(bmain, mesh, sd->symmetrize_direction, dist);
+
+ ED_sculpt_undo_geometry_end(ob);
+ BKE_mesh_calc_normals(ob->data);
+ BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+
+ break;
+ case PBVH_GRIDS:
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Redraw. */
+ SCULPT_pbvh_clear(ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_symmetrize(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Symmetrize";
+ ot->idname = "SCULPT_OT_symmetrize";
+ ot->description = "Symmetrize the topology modifications";
+
+ /* API callbacks. */
+ ot->exec = sculpt_symmetrize_exec;
+ ot->poll = sculpt_no_multires_poll;
+
+ RNA_def_float(ot->srna,
+ "merge_tolerance",
+ 0.001f,
+ 0.0f,
+ FLT_MAX,
+ "Merge Distance",
+ "Distance within which symmetrical vertices are merged",
+ 0.0f,
+ 1.0f);
+}
+
+/**** Toggle operator for turning sculpt mode on or off ****/
+
+static void sculpt_init_session(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
+{
+ /* Create persistent sculpt mode data. */
+ BKE_sculpt_toolsettings_data_ensure(scene);
+
+ /* Create sculpt mode session data. */
+ if (ob->sculpt != NULL) {
+ BKE_sculptsession_free(ob);
+ }
+ ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
+ ob->sculpt->mode_type = OB_MODE_SCULPT;
+
+ BKE_sculpt_ensure_orig_mesh_data(scene, ob);
+
+ BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
+
+ /* This function expects a fully evaluated depsgraph. */
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
+
+ /* Here we can detect geometry that was just added to Sculpt Mode as it has the
+ * SCULPT_FACE_SET_NONE assigned, so we can create a new Face Set for it. */
+ /* In sculpt mode all geometry that is assigned to SCULPT_FACE_SET_NONE is considered as not
+ * initialized, which is used is some operators that modify the mesh topology to perform certain
+ * actions in the new polys. After these operations are finished, all polys should have a valid
+ * face set ID assigned (different from SCULPT_FACE_SET_NONE) to manage their visibility
+ * correctly. */
+ /* TODO(pablodp606): Based on this we can improve the UX in future tools for creating new
+ * objects, like moving the transform pivot position to the new area or masking existing
+ * geometry. */
+ SculptSession *ss = ob->sculpt;
+ const int new_face_set = SCULPT_face_set_next_available_get(ss);
+ for (int i = 0; i < ss->totfaces; i++) {
+ if (ss->face_sets[i] == SCULPT_FACE_SET_NONE) {
+ ss->face_sets[i] = new_face_set;
+ }
+ }
+}
+
+void ED_object_sculptmode_enter_ex(Main *bmain,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ const bool force_dyntopo,
+ ReportList *reports)
+{
+ const int mode_flag = OB_MODE_SCULPT;
+ Mesh *me = BKE_mesh_from_object(ob);
+
+ /* Enter sculpt mode. */
+ ob->mode |= mode_flag;
+
+ sculpt_init_session(bmain, depsgraph, scene, ob);
+
+ if (!(fabsf(ob->scale[0] - ob->scale[1]) < 1e-4f &&
+ fabsf(ob->scale[1] - ob->scale[2]) < 1e-4f)) {
+ BKE_report(
+ reports, RPT_WARNING, "Object has non-uniform scale, sculpting may be unpredictable");
+ }
+ else if (is_negative_m4(ob->obmat)) {
+ BKE_report(reports, RPT_WARNING, "Object has negative scale, sculpting may be unpredictable");
+ }
+
+ Paint *paint = BKE_paint_get_active_from_paintmode(scene, PAINT_MODE_SCULPT);
+ BKE_paint_init(bmain, scene, PAINT_MODE_SCULPT, PAINT_CURSOR_SCULPT);
+
+ paint_cursor_start(paint, SCULPT_mode_poll_view3d);
+
+ /* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes,
+ * As long as no data was added that is not supported. */
+ if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
+ MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
+
+ const char *message_unsupported = NULL;
+ if (me->totloop != me->totpoly * 3) {
+ message_unsupported = TIP_("non-triangle face");
+ }
+ else if (mmd != NULL) {
+ message_unsupported = TIP_("multi-res modifier");
+ }
+ else {
+ enum eDynTopoWarnFlag flag = SCULPT_dynamic_topology_check(scene, ob);
+ if (flag == 0) {
+ /* pass */
+ }
+ else if (flag & DYNTOPO_WARN_VDATA) {
+ message_unsupported = TIP_("vertex data");
+ }
+ else if (flag & DYNTOPO_WARN_EDATA) {
+ message_unsupported = TIP_("edge data");
+ }
+ else if (flag & DYNTOPO_WARN_LDATA) {
+ message_unsupported = TIP_("face data");
+ }
+ else if (flag & DYNTOPO_WARN_MODIFIER) {
+ message_unsupported = TIP_("constructive modifier");
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+
+ if ((message_unsupported == NULL) || force_dyntopo) {
+ /* Needed because we may be entering this mode before the undo system loads. */
+ wmWindowManager *wm = bmain->wm.first;
+ bool has_undo = wm->undo_stack != NULL;
+ /* Undo push is needed to prevent memory leak. */
+ if (has_undo) {
+ SCULPT_undo_push_begin(ob, "Dynamic topology enable");
+ }
+ SCULPT_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob);
+ if (has_undo) {
+ SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
+ SCULPT_undo_push_end();
+ }
+ }
+ else {
+ BKE_reportf(
+ reports, RPT_WARNING, "Dynamic Topology found: %s, disabled", message_unsupported);
+ me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
+ }
+ }
+
+ /* Flush object mode. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+}
+
+void ED_object_sculptmode_enter(struct bContext *C, Depsgraph *depsgraph, ReportList *reports)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, reports);
+}
+
+void ED_object_sculptmode_exit_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
+{
+ const int mode_flag = OB_MODE_SCULPT;
+ Mesh *me = BKE_mesh_from_object(ob);
+
+ multires_flush_sculpt_updates(ob);
+
+ /* Not needed for now. */
+#if 0
+ MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
+ const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd);
+#endif
+
+ /* Always for now, so leaving sculpt mode always ensures scene is in
+ * a consistent state. */
+ if (true || /* flush_recalc || */ (ob->sculpt && ob->sculpt->bm)) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+
+ if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
+ /* Dynamic topology must be disabled before exiting sculpt
+ * mode to ensure the undo stack stays in a consistent
+ * state. */
+ sculpt_dynamic_topology_disable_with_undo(bmain, depsgraph, scene, ob);
+
+ /* Store so we know to re-enable when entering sculpt mode. */
+ me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
+ }
+
+ /* Leave sculpt mode. */
+ ob->mode &= ~mode_flag;
+
+ BKE_sculptsession_free(ob);
+
+ paint_cursor_delete_textures();
+
+ /* Never leave derived meshes behind. */
+ BKE_object_free_derived_caches(ob);
+
+ /* Flush object mode. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+}
+
+void ED_object_sculptmode_exit(bContext *C, Depsgraph *depsgraph)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ ED_object_sculptmode_exit_ex(bmain, depsgraph, scene, ob);
+}
+
+static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
+{
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_on_load(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ const int mode_flag = OB_MODE_SCULPT;
+ const bool is_mode_set = (ob->mode & mode_flag) != 0;
+
+ if (!is_mode_set) {
+ if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ if (is_mode_set) {
+ ED_object_sculptmode_exit_ex(bmain, depsgraph, scene, ob);
+ }
+ else {
+ if (depsgraph) {
+ depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ }
+ ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, op->reports);
+ BKE_paint_toolslots_brush_validate(bmain, &ts->sculpt->paint);
+
+ if (ob->mode & mode_flag) {
+ Mesh *me = ob->data;
+ /* Dyntopo adds its own undo step. */
+ if ((me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) == 0) {
+ /* Without this the memfile undo step is used,
+ * while it works it causes lag when undoing the first undo step, see T71564. */
+ wmWindowManager *wm = CTX_wm_manager(C);
+ if (wm->op_undo_depth <= 1) {
+ SCULPT_undo_push_begin(ob, op->type->name);
+ }
+ }
+ }
+ }
+
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
+
+ WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
+
+ WM_toolsystem_update_from_context_view3d(C);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_sculptmode_toggle(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Sculpt Mode";
+ ot->idname = "SCULPT_OT_sculptmode_toggle";
+ ot->description = "Toggle sculpt mode in 3D view";
+
+ /* API callbacks. */
+ ot->exec = sculpt_mode_toggle_exec;
+ ot->poll = ED_operator_object_active_editable_mesh;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float radius)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *ob = CTX_data_active_object(C);
+
+ ss->preview_vert_index_count = 0;
+ int totpoints = 0;
+
+ /* This function is called from the cursor drawing code, so the PBVH may not be build yet. */
+ if (!ss->pbvh) {
+ return;
+ }
+
+ if (!ss->deform_modifiers_active) {
+ return;
+ }
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
+ return;
+ }
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
+
+ if (!ss->pmap) {
+ return;
+ }
+
+ float brush_co[3];
+ copy_v3_v3(brush_co, SCULPT_active_vertex_co_get(ss));
+
+ BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(SCULPT_vertex_count_get(ss), "visited_vertices");
+
+ /* Assuming an average of 6 edges per vertex in a triangulated mesh. */
+ const int max_preview_vertices = SCULPT_vertex_count_get(ss) * 3 * 2;
+
+ if (ss->preview_vert_index_list == NULL) {
+ ss->preview_vert_index_list = MEM_callocN(max_preview_vertices * sizeof(int), "preview lines");
+ }
+
+ GSQueue *not_visited_vertices = BLI_gsqueue_new(sizeof(int));
+ int active_v = SCULPT_active_vertex_get(ss);
+ BLI_gsqueue_push(not_visited_vertices, &active_v);
+
+ while (!BLI_gsqueue_is_empty(not_visited_vertices)) {
+ int from_v;
+ BLI_gsqueue_pop(not_visited_vertices, &from_v);
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) {
+ if (totpoints + (ni.size * 2) < max_preview_vertices) {
+ int to_v = ni.index;
+ ss->preview_vert_index_list[totpoints] = from_v;
+ totpoints++;
+ ss->preview_vert_index_list[totpoints] = to_v;
+ totpoints++;
+ if (BLI_BITMAP_TEST(visited_vertices, to_v)) {
+ continue;
+ }
+ BLI_BITMAP_ENABLE(visited_vertices, to_v);
+ const float *co = SCULPT_vertex_co_for_grab_active_get(ss, to_v);
+ if (len_squared_v3v3(brush_co, co) < radius * radius) {
+ BLI_gsqueue_push(not_visited_vertices, &to_v);
+ }
+ }
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+ }
+
+ BLI_gsqueue_free(not_visited_vertices);
+
+ MEM_freeN(visited_vertices);
+
+ ss->preview_vert_index_count = totpoints;
+}
+
+static int vertex_to_loop_colors_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_active_object(C);
+
+ ID *data;
+ data = ob->data;
+ if (data && ID_IS_LINKED(data)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (ob->type != OB_MESH) {
+ return OPERATOR_CANCELLED;
+ }
+
+ Mesh *mesh = ob->data;
+
+ const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL);
+ if (mloopcol_layer_n == -1) {
+ return OPERATOR_CANCELLED;
+ }
+ MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n);
+
+ const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR);
+ if (MPropCol_layer_n == -1) {
+ return OPERATOR_CANCELLED;
+ }
+ MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n);
+
+ MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP);
+ MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY);
+
+ for (int i = 0; i < mesh->totpoly; i++) {
+ MPoly *c_poly = &polys[i];
+ for (int j = 0; j < c_poly->totloop; j++) {
+ int loop_index = c_poly->loopstart + j;
+ MLoop *c_loop = &loops[c_poly->loopstart + j];
+ float srgb_color[4];
+ linearrgb_to_srgb_v4(srgb_color, vertcols[c_loop->v].color);
+ loopcols[loop_index].r = (char)(srgb_color[0] * 255);
+ loopcols[loop_index].g = (char)(srgb_color[1] * 255);
+ loopcols[loop_index].b = (char)(srgb_color[2] * 255);
+ loopcols[loop_index].a = (char)(srgb_color[3] * 255);
+ }
+ }
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_vertex_to_loop_colors(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Sculpt Vertex Color to Vertex Color";
+ ot->description = "Copy the Sculpt Vertex Color to a regular color layer";
+ ot->idname = "SCULPT_OT_vertex_to_loop_colors";
+
+ /* api callbacks */
+ ot->poll = SCULPT_vertex_colors_poll;
+ ot->exec = vertex_to_loop_colors_exec;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int loop_to_vertex_colors_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_active_object(C);
+
+ ID *data;
+ data = ob->data;
+ if (data && ID_IS_LINKED(data)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (ob->type != OB_MESH) {
+ return OPERATOR_CANCELLED;
+ }
+
+ Mesh *mesh = ob->data;
+
+ const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL);
+ if (mloopcol_layer_n == -1) {
+ return OPERATOR_CANCELLED;
+ }
+ MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n);
+
+ const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR);
+ if (MPropCol_layer_n == -1) {
+ return OPERATOR_CANCELLED;
+ }
+ MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n);
+
+ MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP);
+ MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY);
+
+ for (int i = 0; i < mesh->totpoly; i++) {
+ MPoly *c_poly = &polys[i];
+ for (int j = 0; j < c_poly->totloop; j++) {
+ int loop_index = c_poly->loopstart + j;
+ MLoop *c_loop = &loops[c_poly->loopstart + j];
+ vertcols[c_loop->v].color[0] = (loopcols[loop_index].r / 255.0f);
+ vertcols[c_loop->v].color[1] = (loopcols[loop_index].g / 255.0f);
+ vertcols[c_loop->v].color[2] = (loopcols[loop_index].b / 255.0f);
+ vertcols[c_loop->v].color[3] = (loopcols[loop_index].a / 255.0f);
+ srgb_to_linearrgb_v4(vertcols[c_loop->v].color, vertcols[c_loop->v].color);
+ }
+ }
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_loop_to_vertex_colors(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Color to Sculpt Vertex Color";
+ ot->description = "Copy the active loop color layer to the vertex color";
+ ot->idname = "SCULPT_OT_loop_to_vertex_colors";
+
+ /* api callbacks */
+ ot->poll = SCULPT_vertex_colors_poll;
+ ot->exec = loop_to_vertex_colors_exec;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int sculpt_sample_color_invoke(bContext *C,
+ wmOperator *UNUSED(op),
+ const wmEvent *UNUSED(e))
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+ int active_vertex = SCULPT_active_vertex_get(ss);
+ const float *active_vertex_color = SCULPT_vertex_color_get(ss, active_vertex);
+ if (!active_vertex_color) {
+ return OPERATOR_CANCELLED;
+ }
+
+ float color_srgb[3];
+ copy_v3_v3(color_srgb, active_vertex_color);
+ IMB_colormanagement_scene_linear_to_srgb_v3(color_srgb);
+ BKE_brush_color_set(scene, brush, color_srgb);
+
+ WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_sample_color(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Sample Color";
+ ot->idname = "SCULPT_OT_sample_color";
+ ot->description = "Sample the vertex color of the active vertex";
+
+ /* api callbacks */
+ ot->invoke = sculpt_sample_color_invoke;
+ ot->poll = SCULPT_vertex_colors_poll;
+
+ ot->flag = OPTYPE_REGISTER;
+}
+
+/**
+ * #sculpt_mask_by_color_delta_get returns values in the (0,1) range that are used to generate the
+ * mask based on the difference between two colors (the active color and the color of any other
+ * vertex). Ideally, a threshold of 0 should mask only the colors that are equal to the active
+ * color and threshold of 1 should mask all colors. In order to avoid artifacts and produce softer
+ * falloffs in the mask, the MASK_BY_COLOR_SLOPE defines the size of the transition values between
+ * masked and unmasked vertices. The smaller this value is, the sharper the generated mask is going
+ * to be.
+ */
+#define MASK_BY_COLOR_SLOPE 0.25f
+
+static float sculpt_mask_by_color_delta_get(const float *color_a,
+ const float *color_b,
+ const float threshold,
+ const bool invert)
+{
+ float len = len_v3v3(color_a, color_b);
+ /* Normalize len to the (0, 1) range. */
+ len = len / M_SQRT3;
+
+ if (len < threshold - MASK_BY_COLOR_SLOPE) {
+ len = 1.0f;
+ }
+ else if (len >= threshold) {
+ len = 0.0f;
+ }
+ else {
+ len = (-len + threshold) / MASK_BY_COLOR_SLOPE;
+ }
+
+ if (invert) {
+ return 1.0f - len;
+ }
+ return len;
+}
+
+static float sculpt_mask_by_color_final_mask_get(const float current_mask,
+ const float new_mask,
+ const bool invert,
+ const bool preserve_mask)
+{
+ if (preserve_mask) {
+ if (invert) {
+ return min_ff(current_mask, new_mask);
+ }
+ return max_ff(current_mask, new_mask);
+ }
+ return new_mask;
+}
+
+typedef struct MaskByColorContiguousFloodFillData {
+ float threshold;
+ bool invert;
+ float *new_mask;
+ float initial_color[3];
+} MaskByColorContiguousFloodFillData;
+
+static void do_mask_by_color_contiguous_update_nodes_cb(
+ void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+
+ SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK);
+ bool update_node = false;
+
+ const bool invert = data->mask_by_color_invert;
+ const bool preserve_mask = data->mask_by_color_preserve_mask;
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ const float current_mask = *vd.mask;
+ const float new_mask = data->mask_by_color_floodfill[vd.index];
+ *vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask);
+ if (current_mask == *vd.mask) {
+ continue;
+ }
+ update_node = true;
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ if (update_node) {
+ BKE_pbvh_node_mark_redraw(data->nodes[n]);
+ }
+}
+
+static bool sculpt_mask_by_color_contiguous_floodfill_cb(
+ SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
+{
+ MaskByColorContiguousFloodFillData *data = userdata;
+ const float *current_color = SCULPT_vertex_color_get(ss, to_v);
+ float new_vertex_mask = sculpt_mask_by_color_delta_get(
+ current_color, data->initial_color, data->threshold, data->invert);
+ data->new_mask[to_v] = new_vertex_mask;
+
+ if (is_duplicate) {
+ data->new_mask[to_v] = data->new_mask[from_v];
+ }
+
+ float len = len_v3v3(current_color, data->initial_color);
+ len = len / M_SQRT3;
+ return len <= data->threshold;
+}
+
+static void sculpt_mask_by_color_contiguous(Object *object,
+ const int vertex,
+ const float threshold,
+ const bool invert,
+ const bool preserve_mask)
+{
+ SculptSession *ss = object->sculpt;
+ const int totvert = SCULPT_vertex_count_get(ss);
+
+ float *new_mask = MEM_calloc_arrayN(totvert, sizeof(float), "new mask");
+
+ if (invert) {
+ for (int i = 0; i < totvert; i++) {
+ new_mask[i] = 1.0f;
+ }
+ }
+
+ SculptFloodFill flood;
+ SCULPT_floodfill_init(ss, &flood);
+ SCULPT_floodfill_add_initial(&flood, vertex);
+
+ MaskByColorContiguousFloodFillData ffd;
+ ffd.threshold = threshold;
+ ffd.invert = invert;
+ ffd.new_mask = new_mask;
+ copy_v3_v3(ffd.initial_color, SCULPT_vertex_color_get(ss, vertex));
+
+ SCULPT_floodfill_execute(ss, &flood, sculpt_mask_by_color_contiguous_floodfill_cb, &ffd);
+ SCULPT_floodfill_free(&flood);
+
+ int totnode;
+ PBVHNode **nodes;
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+
+ SculptThreadedTaskData data = {
+ .ob = object,
+ .nodes = nodes,
+ .mask_by_color_floodfill = new_mask,
+ .mask_by_color_vertex = vertex,
+ .mask_by_color_threshold = threshold,
+ .mask_by_color_invert = invert,
+ .mask_by_color_preserve_mask = preserve_mask,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(
+ 0, totnode, &data, do_mask_by_color_contiguous_update_nodes_cb, &settings);
+
+ MEM_SAFE_FREE(nodes);
+
+ MEM_freeN(new_mask);
+}
+
+static void do_mask_by_color_task_cb(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+
+ SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK);
+ bool update_node = false;
+
+ const float threshold = data->mask_by_color_threshold;
+ const bool invert = data->mask_by_color_invert;
+ const bool preserve_mask = data->mask_by_color_preserve_mask;
+ const float *active_color = SCULPT_vertex_color_get(ss, data->mask_by_color_vertex);
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ const float current_mask = *vd.mask;
+ const float new_mask = sculpt_mask_by_color_delta_get(active_color, vd.col, threshold, invert);
+ *vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask);
+
+ if (current_mask == *vd.mask) {
+ continue;
+ }
+ update_node = true;
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ if (update_node) {
+ BKE_pbvh_node_mark_redraw(data->nodes[n]);
+ }
+}
+
+static void sculpt_mask_by_color_full_mesh(Object *object,
+ const int vertex,
+ const float threshold,
+ const bool invert,
+ const bool preserve_mask)
+{
+ SculptSession *ss = object->sculpt;
+
+ int totnode;
+ PBVHNode **nodes;
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+
+ SculptThreadedTaskData data = {
+ .ob = object,
+ .nodes = nodes,
+ .mask_by_color_vertex = vertex,
+ .mask_by_color_threshold = threshold,
+ .mask_by_color_invert = invert,
+ .mask_by_color_preserve_mask = preserve_mask,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_mask_by_color_task_cb, &settings);
+
+ MEM_SAFE_FREE(nodes);
+}
+
+static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
+
+ /* Color data is not available in Multires. */
+ if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!ss->vcol) {
+ return OPERATOR_CANCELLED;
+ }
+
+ SCULPT_vertex_random_access_ensure(ss);
+
+ /* Tools that are not brushes do not have the brush gizmo to update the vertex as the mouse move,
+ * so it needs to be updated here. */
+ SculptCursorGeometryInfo sgi;
+ float mouse[2];
+ mouse[0] = event->mval[0];
+ mouse[1] = event->mval[1];
+ SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+
+ SCULPT_undo_push_begin(ob, "Mask by color");
+
+ const int active_vertex = SCULPT_active_vertex_get(ss);
+ const float threshold = RNA_float_get(op->ptr, "threshold");
+ const bool invert = RNA_boolean_get(op->ptr, "invert");
+ const bool preserve_mask = RNA_boolean_get(op->ptr, "preserve_previous_mask");
+
+ if (RNA_boolean_get(op->ptr, "contiguous")) {
+ sculpt_mask_by_color_contiguous(ob, active_vertex, threshold, invert, preserve_mask);
+ }
+ else {
+ sculpt_mask_by_color_full_mesh(ob, active_vertex, threshold, invert, preserve_mask);
+ }
+
+ BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask);
+ SCULPT_undo_push_end();
+
+ SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_mask_by_color(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Mask by Color";
+ ot->idname = "SCULPT_OT_mask_by_color";
+ ot->description = "Creates a mask based on the sculpt vertex colors";
+
+ /* api callbacks */
+ ot->invoke = sculpt_mask_by_color_invoke;
+ ot->poll = SCULPT_vertex_colors_poll;
+
+ ot->flag = OPTYPE_REGISTER;
+
+ ot->prop = RNA_def_boolean(
+ ot->srna, "contiguous", false, "Contiguous", "Mask only contiguous color areas");
+
+ ot->prop = RNA_def_boolean(ot->srna, "invert", false, "Invert", "Invert the generated mask");
+ ot->prop = RNA_def_boolean(
+ ot->srna,
+ "preserve_previous_mask",
+ false,
+ "Preserve Previous Mask",
+ "Preserve the previous mask and add or subtract the new one generated by the colors");
+
+ RNA_def_float(ot->srna,
+ "threshold",
+ 0.35f,
+ 0.0f,
+ 1.0f,
+ "Threshold",
+ "How much changes in color affect the mask generation",
+ 0.0f,
+ 1.0f);
+}
+
+void ED_operatortypes_sculpt(void)
+{
+ WM_operatortype_append(SCULPT_OT_brush_stroke);
+ WM_operatortype_append(SCULPT_OT_sculptmode_toggle);
+ WM_operatortype_append(SCULPT_OT_set_persistent_base);
+ WM_operatortype_append(SCULPT_OT_dynamic_topology_toggle);
+ WM_operatortype_append(SCULPT_OT_optimize);
+ WM_operatortype_append(SCULPT_OT_symmetrize);
+ WM_operatortype_append(SCULPT_OT_detail_flood_fill);
+ WM_operatortype_append(SCULPT_OT_sample_detail_size);
+ WM_operatortype_append(SCULPT_OT_set_detail_size);
+ WM_operatortype_append(SCULPT_OT_mesh_filter);
+ WM_operatortype_append(SCULPT_OT_mask_filter);
+ WM_operatortype_append(SCULPT_OT_dirty_mask);
+ WM_operatortype_append(SCULPT_OT_mask_expand);
+ WM_operatortype_append(SCULPT_OT_set_pivot_position);
+ WM_operatortype_append(SCULPT_OT_face_sets_create);
+ WM_operatortype_append(SCULPT_OT_face_sets_change_visibility);
+ WM_operatortype_append(SCULPT_OT_face_sets_randomize_colors);
+ WM_operatortype_append(SCULPT_OT_face_sets_init);
+ WM_operatortype_append(SCULPT_OT_cloth_filter);
+ WM_operatortype_append(SCULPT_OT_face_sets_edit);
+ WM_operatortype_append(SCULPT_OT_face_set_lasso_gesture);
+ WM_operatortype_append(SCULPT_OT_face_set_box_gesture);
+ WM_operatortype_append(SCULPT_OT_trim_box_gesture);
+ WM_operatortype_append(SCULPT_OT_trim_lasso_gesture);
+ WM_operatortype_append(SCULPT_OT_project_line_gesture);
+
+ WM_operatortype_append(SCULPT_OT_sample_color);
+ WM_operatortype_append(SCULPT_OT_loop_to_vertex_colors);
+ WM_operatortype_append(SCULPT_OT_vertex_to_loop_colors);
+ WM_operatortype_append(SCULPT_OT_color_filter);
+ WM_operatortype_append(SCULPT_OT_mask_by_color);
+ WM_operatortype_append(SCULPT_OT_dyntopo_detail_size_edit);
+ WM_operatortype_append(SCULPT_OT_mask_init);
+
+ WM_operatortype_append(SCULPT_OT_expand);
+}
diff --git a/source/blender/editors/space_file/asset_catalog_tree_view.cc b/source/blender/editors/space_file/asset_catalog_tree_view.cc
index 86c4b78dea4..f6c449a0584 100644
--- a/source/blender/editors/space_file/asset_catalog_tree_view.cc
+++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc
@@ -679,7 +679,7 @@ using namespace blender::ed::asset_browser;
FileAssetCatalogFilterSettingsHandle *file_create_asset_catalog_filter_settings()
{
- AssetCatalogFilterSettings *filter_settings = OBJECT_GUARDED_NEW(AssetCatalogFilterSettings);
+ AssetCatalogFilterSettings *filter_settings = MEM_new<AssetCatalogFilterSettings>(__func__);
return reinterpret_cast<FileAssetCatalogFilterSettingsHandle *>(filter_settings);
}
@@ -688,7 +688,8 @@ void file_delete_asset_catalog_filter_settings(
{
AssetCatalogFilterSettings **filter_settings = reinterpret_cast<AssetCatalogFilterSettings **>(
filter_settings_handle);
- OBJECT_GUARDED_SAFE_DELETE(*filter_settings, AssetCatalogFilterSettings);
+ MEM_delete(*filter_settings);
+ *filter_settings = nullptr;
}
bool file_set_asset_catalog_filter_settings(
diff --git a/source/blender/editors/space_info/info_stats.cc b/source/blender/editors/space_info/info_stats.cc
index bcf26743030..005ae0214cd 100644
--- a/source/blender/editors/space_info/info_stats.cc
+++ b/source/blender/editors/space_info/info_stats.cc
@@ -43,6 +43,7 @@
#include "BLT_translation.h"
+#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_blender_version.h"
#include "BKE_context.h"
@@ -351,7 +352,7 @@ static void stats_object_pose(const Object *ob, SceneStats *stats)
LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
stats->totbone++;
if (pchan->bone && (pchan->bone->flag & BONE_SELECTED)) {
- if (pchan->bone->layer & arm->layer) {
+ if (BKE_pose_is_layer_visible(arm, pchan)) {
stats->totbonesel++;
}
}
diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc
index bbfd886ce56..90fd6e7d657 100644
--- a/source/blender/editors/space_node/drawnode.cc
+++ b/source/blender/editors/space_node/drawnode.cc
@@ -36,6 +36,7 @@
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_scene.h"
#include "BKE_tracking.h"
@@ -1558,7 +1559,8 @@ static void node_property_update_default(Main *bmain, Scene *UNUSED(scene), Poin
{
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNode *node = (bNode *)ptr->data;
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ BKE_ntree_update_tag_node_property(ntree, node);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
static void node_socket_template_properties_update(bNodeType *ntype, bNodeSocketTemplate *stemp)
diff --git a/source/blender/editors/space_node/link_drag_search.cc b/source/blender/editors/space_node/link_drag_search.cc
index e1ba36e81c0..a2dd32b7cc6 100644
--- a/source/blender/editors/space_node/link_drag_search.cc
+++ b/source/blender/editors/space_node/link_drag_search.cc
@@ -29,6 +29,8 @@
#include "WM_api.h"
+#include "ED_node.h"
+
#include "node_intern.hh"
using blender::nodes::SocketLinkOperation;
@@ -77,7 +79,7 @@ static void add_group_input_node_fn(nodes::LinkSearchOpParams &params)
bNode &group_input = params.add_node("NodeGroupInput");
/* This is necessary to create the new sockets in the other input nodes. */
- ntreeUpdateTree(CTX_data_main(&params.C), &params.node_tree);
+ ED_node_tree_propagate_change(&params.C, CTX_data_main(&params.C), &params.node_tree);
/* Hide the new input in all other group input nodes, to avoid making them taller. */
LISTBASE_FOREACH (bNode *, node, &params.node_tree.nodes) {
@@ -203,9 +205,7 @@ static void link_drag_search_exec_fn(bContext *C, void *arg1, void *arg2)
/* Ideally it would be possible to tag the node tree in some way so it updates only after the
* translate operation is finished, but normally moving nodes around doesn't cause updates. */
- ntreeUpdateTree(&bmain, snode.edittree);
- snode_notify(*C, snode);
- snode_dag_update(*C, snode);
+ ED_node_tree_propagate_change(C, &bmain, snode.edittree);
/* Start translation operator with the new node. */
wmOperatorType *ot = WM_operatortype_find("TRANSFORM_OT_translate", true);
@@ -288,4 +288,4 @@ void invoke_node_link_drag_add_menu(bContext &C,
UI_popup_block_invoke_ex(&C, create_search_popup_block, storage, nullptr, false);
}
-} // namespace blender::ed::space_node \ No newline at end of file
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc
index c6a5e8e68c0..0bb090f9a5f 100644
--- a/source/blender/editors/space_node/node_add.cc
+++ b/source/blender/editors/space_node/node_add.cc
@@ -36,6 +36,7 @@
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_texture.h"
@@ -83,15 +84,8 @@ bNode *node_add_node(const bContext &C, const char *idname, int type, float locx
nodeSetSelected(node, true);
- ntreeUpdateTree(&bmain, snode.edittree);
ED_node_set_active(&bmain, &snode, snode.edittree, node, nullptr);
-
- snode_update(snode, node);
-
- if (snode.nodetree->type == NTREE_TEXTURE) {
- ntreeTexCheckCyclics(snode.edittree);
- }
-
+ BKE_ntree_update_main_tree(&bmain, snode.edittree, nullptr);
return node;
}
@@ -281,10 +275,7 @@ static int add_reroute_exec(bContext *C, wmOperator *op)
BLI_freelistN(&input_links);
/* always last */
- ntreeUpdateTree(CTX_data_main(C), &ntree);
- snode_notify(*C, snode);
- snode_dag_update(*C, snode);
-
+ ED_node_tree_propagate_change(C, CTX_data_main(C), &ntree);
return OPERATOR_FINISHED;
}
@@ -385,12 +376,7 @@ static int node_add_group_exec(bContext *C, wmOperator *op)
id_us_plus(group_node->id);
nodeSetActive(ntree, group_node);
- ntreeUpdateTree(bmain, node_group);
- ntreeUpdateTree(bmain, ntree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
-
+ ED_node_tree_propagate_change(C, bmain, nullptr);
return OPERATOR_FINISHED;
}
@@ -479,12 +465,7 @@ static int node_add_object_exec(bContext *C, wmOperator *op)
id_us_plus(&object->id);
nodeSetActive(ntree, object_node);
- ntreeUpdateTree(bmain, ntree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
-
- ED_node_tag_update_nodetree(bmain, ntree, object_node);
+ ED_node_tree_propagate_change(C, bmain, ntree);
DEG_relations_tag_update(bmain);
return OPERATOR_FINISHED;
@@ -587,14 +568,9 @@ static int node_add_texture_exec(bContext *C, wmOperator *op)
id_us_plus(&texture->id);
nodeSetActive(ntree, texture_node);
- ntreeUpdateTree(bmain, ntree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, bmain, ntree);
DEG_relations_tag_update(bmain);
- ED_node_tag_update_nodetree(bmain, ntree, texture_node);
-
return OPERATOR_FINISHED;
}
@@ -701,14 +677,9 @@ static int node_add_collection_exec(bContext *C, wmOperator *op)
id_us_plus(&collection->id);
nodeSetActive(ntree, collection_node);
- ntreeUpdateTree(bmain, ntree);
-
- snode_notify(*C, snode);
- snode_dag_update(*C, snode);
+ ED_node_tree_propagate_change(C, bmain, ntree);
DEG_relations_tag_update(bmain);
- ED_node_tag_update_nodetree(bmain, ntree, collection_node);
-
return OPERATOR_FINISHED;
}
@@ -834,8 +805,7 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
}
- snode_notify(*C, snode);
- snode_dag_update(*C, snode);
+ ED_node_tree_propagate_change(C, bmain, snode.edittree);
DEG_relations_tag_update(bmain);
return OPERATOR_FINISHED;
@@ -937,8 +907,7 @@ static int node_add_mask_exec(bContext *C, wmOperator *op)
node->id = mask;
id_us_plus(mask);
- snode_notify(*C, snode);
- snode_dag_update(*C, snode);
+ ED_node_tree_propagate_change(C, bmain, snode.edittree);
DEG_relations_tag_update(bmain);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index d68f16f6197..635ef41d859 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -176,35 +176,6 @@ void ED_node_tag_update_id(ID *id)
}
}
-void ED_node_tag_update_nodetree(Main *bmain, bNodeTree *ntree, bNode *node)
-{
- if (!ntree) {
- return;
- }
-
- bool do_tag_update = true;
- if (node != nullptr) {
- if (!node_connected_to_output(*bmain, *ntree, *node)) {
- do_tag_update = false;
- }
- }
-
- /* Look through all datablocks to support groups. */
- if (do_tag_update) {
- FOREACH_NODETREE_BEGIN (bmain, tntree, id) {
- /* Check if nodetree uses the group. */
- if (ntreeHasTree(tntree, ntree)) {
- ED_node_tag_update_id(id);
- }
- }
- FOREACH_NODETREE_END;
- }
-
- if (ntree->type == NTREE_TEXTURE) {
- ntreeTexCheckCyclics(ntree);
- }
-}
-
static bool compare_nodes(const bNode *a, const bNode *b)
{
/* These tell if either the node or any of the parent nodes is selected.
@@ -365,6 +336,10 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node,
PointerRNA nodeptr;
RNA_pointer_create(&ntree.id, &RNA_Node, &node, &nodeptr);
+ const bool node_options = node.typeinfo->draw_buttons && (node.flag & NODE_OPTIONS);
+ const bool inputs_first = node.inputs.first &&
+ !(node.outputs.first || (node.flag & NODE_PREVIEW) || node_options);
+
/* Get "global" coordinates. */
float2 loc = node_to_view(node, float2(0));
/* Round the node origin because text contents are always pixel-aligned. */
@@ -377,7 +352,7 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node,
dy -= NODE_DY;
/* Add a little bit of padding above the top socket. */
- if (node.outputs.first || node.inputs.first) {
+ if (node.outputs.first || inputs_first) {
dy -= NODE_DYS / 2;
}
@@ -478,7 +453,7 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node,
}
/* Buttons rect? */
- if (node.typeinfo->draw_buttons && (node.flag & NODE_OPTIONS)) {
+ if (node_options) {
dy -= NODE_DYS / 2;
uiLayout *layout = UI_block_layout(&block,
@@ -2414,9 +2389,11 @@ static void node_update_nodetree(const bContext &C,
bNode &node = *nodes[i];
uiBlock &block = *blocks[i];
if (node.type == NODE_FRAME) {
- frame_node_prepare_for_draw(node, nodes);
+ /* Frame sizes are calculated after all other nodes have calculating their #totr. */
+ continue;
}
- else if (node.type == NODE_REROUTE) {
+
+ if (node.type == NODE_REROUTE) {
reroute_node_prepare_for_draw(node);
}
else {
@@ -2428,6 +2405,13 @@ static void node_update_nodetree(const bContext &C,
}
}
}
+
+ /* Now calculate the size of frame nodes, which can depend on the size of other nodes. */
+ for (const int i : nodes.index_range()) {
+ if (nodes[i]->type == NODE_FRAME) {
+ frame_node_prepare_for_draw(*nodes[i], nodes);
+ }
+ }
}
static void frame_node_draw_label(const bNodeTree &ntree,
diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc
index fb90e2bfe50..ba2327c742b 100644
--- a/source/blender/editors/space_node/node_edit.cc
+++ b/source/blender/editors/space_node/node_edit.cc
@@ -38,6 +38,7 @@
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_workspace.h"
@@ -383,31 +384,11 @@ bool composite_node_editable(bContext *C)
return false;
}
-void snode_dag_update(bContext &C, SpaceNode &snode)
+static void send_notifiers_after_tree_change(ID *id, bNodeTree *ntree)
{
- Main *bmain = CTX_data_main(&C);
+ WM_main_add_notifier(NC_NODE | NA_EDITED, nullptr);
- /* for groups, update all ID's using this */
- if ((snode.edittree->id.flag & LIB_EMBEDDED_DATA) == 0) {
- FOREACH_NODETREE_BEGIN (bmain, tntree, id) {
- if (ntreeHasTree(tntree, snode.edittree)) {
- DEG_id_tag_update(id, 0);
- }
- }
- FOREACH_NODETREE_END;
- }
-
- DEG_id_tag_update(snode.id, 0);
- DEG_id_tag_update(&snode.nodetree->id, 0);
-}
-
-void snode_notify(bContext &C, SpaceNode &snode)
-{
- ID *id = snode.id;
-
- WM_event_add_notifier(&C, NC_NODE | NA_EDITED, nullptr);
-
- if (ED_node_is_shader(&snode)) {
+ if (ntree->type == NTREE_SHADER) {
if (GS(id->name) == ID_MA) {
WM_main_add_notifier(NC_MATERIAL | ND_SHADING, id);
}
@@ -418,17 +399,37 @@ void snode_notify(bContext &C, SpaceNode &snode)
WM_main_add_notifier(NC_WORLD | ND_WORLD, id);
}
}
- else if (ED_node_is_compositor(&snode)) {
- WM_event_add_notifier(&C, NC_SCENE | ND_NODES, id);
+ else if (ntree->type == NTREE_COMPOSIT) {
+ WM_main_add_notifier(NC_SCENE | ND_NODES, id);
}
- else if (ED_node_is_texture(&snode)) {
- WM_event_add_notifier(&C, NC_TEXTURE | ND_NODES, id);
+ else if (ntree->type == NTREE_TEXTURE) {
+ WM_main_add_notifier(NC_TEXTURE | ND_NODES, id);
}
- else if (ED_node_is_geometry(&snode)) {
+ else if (ntree->type == NTREE_GEOMETRY) {
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, id);
}
}
+void ED_node_tree_propagate_change(const bContext *C, Main *bmain, bNodeTree *root_ntree)
+{
+ if (C != nullptr) {
+ SpaceNode *snode = CTX_wm_space_node(C);
+ if (snode != nullptr && root_ntree != nullptr) {
+ send_notifiers_after_tree_change(snode->id, root_ntree);
+ }
+ }
+
+ NodeTreeUpdateExtraParams params = {nullptr};
+ params.tree_changed_fn = [](ID *id, bNodeTree *ntree, void *UNUSED(user_data)) {
+ send_notifiers_after_tree_change(id, ntree);
+ };
+ params.tree_output_changed_fn = [](ID *UNUSED(id), bNodeTree *ntree, void *UNUSED(user_data)) {
+ DEG_id_tag_update(&ntree->id, ID_RECALC_NTREE_OUTPUT);
+ };
+
+ BKE_ntree_update_main_tree(bmain, root_ntree, &params);
+}
+
void ED_node_set_tree_type(SpaceNode *snode, bNodeTreeType *typeinfo)
{
if (typeinfo) {
@@ -477,7 +478,7 @@ void ED_node_shader_default(const bContext *C, ID *id)
}
ma->nodetree = ntreeCopyTree(bmain, ma_default->nodetree);
- ntreeUpdateTree(bmain, ma->nodetree);
+ BKE_ntree_update_main_tree(bmain, ma->nodetree, nullptr);
}
else if (ELEM(GS(id->name), ID_WO, ID_LA)) {
/* Emission */
@@ -517,7 +518,7 @@ void ED_node_shader_default(const bContext *C, ID *id)
output->locx = 300.0f;
output->locy = 300.0f;
nodeSetActive(ntree, output);
- ntreeUpdateTree(bmain, ntree);
+ BKE_ntree_update_main_tree(bmain, ntree, nullptr);
}
else {
printf("ED_node_shader_default called on wrong ID type.\n");
@@ -555,7 +556,7 @@ void ED_node_composit_default(const bContext *C, struct Scene *sce)
bNodeSocket *tosock = (bNodeSocket *)out->inputs.first;
nodeAddLink(sce->nodetree, in, fromsock, out, tosock);
- ntreeUpdateTree(CTX_data_main(C), sce->nodetree);
+ BKE_ntree_update_main_tree(CTX_data_main(C), sce->nodetree, nullptr);
}
void ED_node_texture_default(const bContext *C, Tex *tex)
@@ -583,7 +584,7 @@ void ED_node_texture_default(const bContext *C, Tex *tex)
bNodeSocket *tosock = (bNodeSocket *)out->inputs.first;
nodeAddLink(tex->nodetree, in, fromsock, out, tosock);
- ntreeUpdateTree(CTX_data_main(C), tex->nodetree);
+ BKE_ntree_update_main_tree(CTX_data_main(C), tex->nodetree, nullptr);
}
/**
@@ -628,28 +629,6 @@ void snode_set_context(const bContext &C)
}
}
-void snode_update(SpaceNode &snode, bNode *node)
-{
- /* XXX this only updates nodes in the current node space tree path.
- * The function supposedly should update any potential group node linking to changed tree,
- * this really requires a working depsgraph ...
- */
-
- /* update all edited group nodes */
- bNodeTreePath *path = (bNodeTreePath *)snode.treepath.last;
- if (path) {
- bNodeTree *ngroup = path->nodetree;
- for (path = path->prev; path; path = path->prev) {
- nodeUpdateID(path->nodetree, (ID *)ngroup);
- ngroup = path->nodetree;
- }
- }
-
- if (node) {
- nodeUpdate(snode.edittree, node);
- }
-}
-
void ED_node_set_active(
Main *bmain, SpaceNode *snode, bNodeTree *ntree, bNode *node, bool *r_active_texture_changed)
{
@@ -697,14 +676,10 @@ void ED_node_set_active(
}
node->flag |= NODE_DO_OUTPUT;
- if (was_output == 0) {
- ED_node_tag_update_nodetree(bmain, ntree, node);
- }
- }
- else if (do_update) {
- ED_node_tag_update_nodetree(bmain, ntree, node);
}
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
+
if ((node->flag & NODE_ACTIVE_TEXTURE) && !was_active_texture) {
/* If active texture changed, free glsl materials. */
LISTBASE_FOREACH (Material *, ma, &bmain->materials) {
@@ -750,7 +725,7 @@ void ED_node_set_active(
if (r_active_texture_changed) {
*r_active_texture_changed = true;
}
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
WM_main_add_notifier(NC_IMAGE, nullptr);
}
@@ -767,7 +742,7 @@ void ED_node_set_active(
node->flag |= NODE_DO_OUTPUT;
if (was_output == 0) {
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
/* Adding a node doesn't link this yet. */
@@ -782,11 +757,11 @@ void ED_node_set_active(
}
node->flag |= NODE_DO_OUTPUT;
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
}
else if (do_update) {
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
}
else if (ntree->type == NTREE_TEXTURE) {
@@ -1302,7 +1277,6 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
SpaceNode *snode = CTX_wm_space_node(C);
bNodeTree *ntree = snode->edittree;
const bool keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs");
- bool do_tag_update = false;
ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
@@ -1310,9 +1284,6 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->flag & SELECT) {
BKE_node_copy_store_new_pointers(ntree, node, LIB_ID_COPY_DEFAULT);
-
- /* To ensure redraws or re-renders happen. */
- ED_node_tag_update_id(snode->id);
}
/* make sure we don't copy new nodes again! */
@@ -1378,8 +1349,6 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
nodeSetSelected(node, false);
node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_TEXTURE);
nodeSetSelected(newnode, true);
-
- do_tag_update |= (do_tag_update || node_connected_to_output(*bmain, *ntree, *newnode));
}
/* make sure we don't copy new nodes again! */
@@ -1388,13 +1357,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
}
}
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
-
- snode_notify(*C, *snode);
- if (do_tag_update) {
- snode_dag_update(*C, *snode);
- }
-
+ ED_node_tree_propagate_change(C, bmain, snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1485,8 +1448,7 @@ static int node_read_viewlayers_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, bmain, snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1653,7 +1615,7 @@ static int node_preview_toggle_exec(bContext *C, wmOperator *UNUSED(op))
node_flag_toggle_exec(snode, NODE_PREVIEW);
- snode_notify(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1732,7 +1694,7 @@ static int node_socket_toggle_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -1760,23 +1722,16 @@ static int node_mute_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
SpaceNode *snode = CTX_wm_space_node(C);
- bool do_tag_update = false;
ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
if ((node->flag & SELECT) && !node->typeinfo->no_muting) {
node->flag ^= NODE_MUTED;
- snode_update(*snode, node);
- do_tag_update |= (do_tag_update ||
- node_connected_to_output(*bmain, *snode->edittree, *node));
}
}
- snode_notify(*C, *snode);
- if (do_tag_update) {
- snode_dag_update(*C, *snode);
- }
+ ED_node_tree_propagate_change(C, bmain, snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1802,24 +1757,16 @@ static int node_delete_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
SpaceNode *snode = CTX_wm_space_node(C);
- bool do_tag_update = false;
ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
LISTBASE_FOREACH_MUTABLE (bNode *, node, &snode->edittree->nodes) {
if (node->flag & SELECT) {
- do_tag_update |= (do_tag_update ||
- node_connected_to_output(*bmain, *snode->edittree, *node));
nodeRemoveNode(bmain, snode->edittree, node, true);
}
}
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
-
- snode_notify(*C, *snode);
- if (do_tag_update) {
- snode_dag_update(*C, *snode);
- }
+ ED_node_tree_propagate_change(C, bmain, snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1863,10 +1810,7 @@ static int node_switch_view_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1901,10 +1845,7 @@ static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, bmain, snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1951,7 +1892,7 @@ static int node_output_file_add_socket_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "file_path", file_path);
ntreeCompositOutputFileAddSocket(ntree, node, file_path, &scene->r.im_format);
- snode_notify(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree);
return OPERATOR_FINISHED;
}
@@ -2000,7 +1941,7 @@ static int node_output_file_remove_active_socket_exec(bContext *C, wmOperator *U
return OPERATOR_CANCELLED;
}
- snode_notify(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), ntree);
return OPERATOR_FINISHED;
}
@@ -2067,7 +2008,7 @@ static int node_output_file_move_active_socket_exec(bContext *C, wmOperator *op)
nimf->active_input++;
}
- snode_notify(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree);
return OPERATOR_FINISHED;
}
@@ -2313,10 +2254,7 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
}
Main *bmain = CTX_data_main(C);
- ntreeUpdateTree(bmain, snode->edittree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, bmain, snode->edittree);
/* Pasting nodes can create arbitrary new relations, because nodes can reference IDs. */
DEG_relations_tag_update(bmain);
@@ -2384,10 +2322,7 @@ static int ntree_socket_add_exec(bContext *C, wmOperator *op)
/* make the new socket active */
sock->flag |= SELECT;
- ntreeUpdateTree(CTX_data_main(C), ntree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -2434,10 +2369,7 @@ static int ntree_socket_remove_exec(bContext *C, wmOperator *op)
active_sock->flag |= SELECT;
}
- ntreeUpdateTree(CTX_data_main(C), ntree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -2488,7 +2420,7 @@ static int ntree_socket_change_type_exec(bContext *C, wmOperator *op)
/* Need the extra update here because the loop above does not check for valid links in the node
* group we're currently editing. */
- ntree->update |= NTREE_UPDATE_GROUP | NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_interface(ntree);
/* Deactivate sockets. */
LISTBASE_FOREACH (bNodeSocket *, socket_iter, sockets) {
@@ -2497,10 +2429,7 @@ static int ntree_socket_change_type_exec(bContext *C, wmOperator *op)
/* Make the new socket active. */
iosock->flag |= SELECT;
- ntreeUpdateTree(main, ntree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, main, ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -2611,11 +2540,8 @@ static int ntree_socket_move_exec(bContext *C, wmOperator *op)
}
}
- ntree->update |= NTREE_UPDATE_GROUP;
- ntreeUpdateTree(CTX_data_main(C), ntree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ BKE_ntree_update_tag_interface(ntree);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -2846,7 +2772,7 @@ static int viewer_border_exec(bContext *C, wmOperator *op)
btree->flag |= NTREE_VIEWER_BORDER;
}
- snode_notify(*C, *snode);
+ ED_node_tree_propagate_change(C, bmain, btree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
}
else {
@@ -2886,7 +2812,7 @@ static int clear_viewer_border_exec(bContext *C, wmOperator *UNUSED(op))
bNodeTree *btree = snode->nodetree;
btree->flag &= ~NTREE_VIEWER_BORDER;
- snode_notify(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), btree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
return OPERATOR_FINISHED;
@@ -2931,7 +2857,7 @@ static int node_cryptomatte_add_socket_exec(bContext *C, wmOperator *UNUSED(op))
ntreeCompositCryptomatteAddSocket(ntree, node);
- snode_notify(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), ntree);
return OPERATOR_FINISHED;
}
@@ -2977,7 +2903,7 @@ static int node_cryptomatte_remove_socket_exec(bContext *C, wmOperator *UNUSED(o
return OPERATOR_CANCELLED;
}
- snode_notify(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), ntree);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc
index 4890c3e39cf..6f96e08d749 100644
--- a/source/blender/editors/space_node/node_geometry_attribute_search.cc
+++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc
@@ -125,8 +125,8 @@ void node_geometry_add_attribute_search_button(const bContext &UNUSED(C),
0.0f,
"");
- AttributeSearchData *data = OBJECT_GUARDED_NEW(
- AttributeSearchData, {&node_tree, &node, (bNodeSocket *)socket_ptr.data});
+ AttributeSearchData *data = MEM_new<AttributeSearchData>(
+ __func__, AttributeSearchData{&node_tree, &node, (bNodeSocket *)socket_ptr.data});
UI_but_func_search_set_results_are_suggestions(but, true);
UI_but_func_search_set_sep_string(but, UI_MENU_ARROW_SEP);
diff --git a/source/blender/editors/space_node/node_group.cc b/source/blender/editors/space_node/node_group.cc
index 704ffe1e478..290ed172a48 100644
--- a/source/blender/editors/space_node/node_group.cc
+++ b/source/blender/editors/space_node/node_group.cc
@@ -40,6 +40,7 @@
#include "BKE_context.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
+#include "BKE_node_tree_update.h"
#include "BKE_report.h"
#include "DEG_depsgraph_build.h"
@@ -258,6 +259,7 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
/* migrate node */
BLI_remlink(&wgroup->nodes, node);
BLI_addtail(&ntree->nodes, node);
+ BKE_ntree_update_tag_node_new(ntree, node);
/* ensure unique node name in the node tree */
nodeUniqueName(ntree, node);
@@ -284,6 +286,7 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &wgroup->links) {
BLI_remlink(&wgroup->links, link);
BLI_addtail(&ntree->links, link);
+ BKE_ntree_update_tag_link_added(ntree, link);
}
bNodeLink *glinks_last = (bNodeLink *)ntree->links.last;
@@ -393,8 +396,6 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
/* delete the group instance and dereference group tree */
nodeRemoveNode(bmain, ntree, gnode, true);
- ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
-
return 1;
}
@@ -412,16 +413,13 @@ static int node_group_ungroup_exec(bContext *C, wmOperator *op)
}
if (gnode->id && node_group_ungroup(bmain, snode->edittree, gnode)) {
- ntreeUpdateTree(bmain, snode->nodetree);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), nullptr);
}
else {
BKE_report(op->reports, RPT_WARNING, "Cannot ungroup");
return OPERATOR_CANCELLED;
}
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
-
return OPERATOR_FINISHED;
}
@@ -558,9 +556,9 @@ static bool node_group_separate_selected(
}
}
- ntree.update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_all(&ntree);
if (!make_copy) {
- ngroup.update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_all(&ngroup);
}
return true;
@@ -614,10 +612,7 @@ static int node_group_separate_exec(bContext *C, wmOperator *op)
/* switch to parent tree */
ED_node_tree_pop(snode);
- ntreeUpdateTree(CTX_data_main(C), snode->nodetree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), nullptr);
return OPERATOR_FINISHED;
}
@@ -812,6 +807,8 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree,
/* change node-collection membership */
BLI_remlink(&ntree.nodes, node);
BLI_addtail(&ngroup->nodes, node);
+ BKE_ntree_update_tag_node_removed(&ntree);
+ BKE_ntree_update_tag_node_new(ngroup, node);
/* ensure unique node name in the ngroup */
nodeUniqueName(ngroup, node);
@@ -983,11 +980,6 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree,
}
}
}
-
- /* update of the group tree */
- ngroup->update |= NTREE_UPDATE | NTREE_UPDATE_LINKS;
- /* update of the tree containing the group instance node */
- ntree.update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
}
static bNode *node_group_make_from_selected(const bContext &C,
@@ -1016,9 +1008,6 @@ static bNode *node_group_make_from_selected(const bContext &C,
node_group_make_insert_selected(C, ntree, gnode);
- /* update of the tree containing the group instance node */
- ntree.update |= NTREE_UPDATE_NODES;
-
return gnode;
}
@@ -1047,14 +1036,10 @@ static int node_group_make_exec(bContext *C, wmOperator *op)
LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
sort_multi_input_socket_links(snode, *node, nullptr, nullptr);
}
- ntreeUpdateTree(bmain, ngroup);
}
}
- ntreeUpdateTree(bmain, &ntree);
-
- snode_notify(*C, snode);
- snode_dag_update(*C, snode);
+ ED_node_tree_propagate_change(C, bmain, nullptr);
/* We broke relations in node tree, need to rebuild them in the graphs. */
DEG_relations_tag_update(bmain);
@@ -1107,12 +1092,7 @@ static int node_group_insert_exec(bContext *C, wmOperator *op)
nodeSetActive(ntree, gnode);
ED_node_tree_push(snode, ngroup, gnode);
- ntreeUpdateTree(bmain, ngroup);
-
- ntreeUpdateTree(bmain, ntree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, bmain, nullptr);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh
index 2e55bb0cb28..52dde965114 100644
--- a/source/blender/editors/space_node/node_intern.hh
+++ b/source/blender/editors/space_node/node_intern.hh
@@ -235,7 +235,6 @@ void sort_multi_input_socket_links(SpaceNode &snode,
bNode &node,
bNodeLink *drag_link,
const blender::float2 *cursor);
-bool node_connected_to_output(Main &bmain, bNodeTree &ntree, bNode &node);
void NODE_OT_link(wmOperatorType *ot);
void NODE_OT_link_make(wmOperatorType *ot);
@@ -252,12 +251,8 @@ void NODE_OT_link_viewer(wmOperatorType *ot);
void NODE_OT_insert_offset(wmOperatorType *ot);
-void snode_notify(bContext &C, SpaceNode &snode);
-void snode_dag_update(bContext &C, SpaceNode &snode);
void snode_set_context(const bContext &C);
-void snode_update(SpaceNode &snode, bNode *node);
-/** Operator poll callback. */
bool composite_node_active(bContext *C);
/** Operator poll callback. */
bool composite_node_editable(bContext *C);
diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc
index 90b53258d5e..c441cf14683 100644
--- a/source/blender/editors/space_node/node_relationships.cc
+++ b/source/blender/editors/space_node/node_relationships.cc
@@ -34,6 +34,7 @@
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_screen.h"
#include "ED_node.h" /* own include */
@@ -73,121 +74,6 @@ using blender::StringRefNull;
using blender::Vector;
/* -------------------------------------------------------------------- */
-/** \name Relations Helpers
- * \{ */
-
-static bool ntree_has_drivers(bNodeTree &ntree)
-{
- const AnimData *adt = BKE_animdata_from_id(&ntree.id);
- if (adt == nullptr) {
- return false;
- }
- return !BLI_listbase_is_empty(&adt->drivers);
-}
-
-static bool ntree_check_nodes_connected_dfs(bNodeTree &ntree, bNode &from, bNode &to)
-{
- if (from.flag & NODE_TEST) {
- return false;
- }
- from.flag |= NODE_TEST;
- LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
- if (link->fromnode == &from) {
- if (link->tonode == &to) {
- return true;
- }
-
- if (ntree_check_nodes_connected_dfs(ntree, *link->tonode, to)) {
- return true;
- }
- }
- }
- return false;
-}
-
-static bool ntree_check_nodes_connected(bNodeTree &ntree, bNode &from, bNode &to)
-{
- if (&from == &to) {
- return true;
- }
- ntreeNodeFlagSet(&ntree, NODE_TEST, false);
- return ntree_check_nodes_connected_dfs(ntree, from, to);
-}
-
-static bool node_group_has_output_dfs(bNode &node)
-{
- bNodeTree *ntree = (bNodeTree *)node.id;
- if (ntree->id.tag & LIB_TAG_DOIT) {
- return false;
- }
- ntree->id.tag |= LIB_TAG_DOIT;
- LISTBASE_FOREACH (bNode *, current_node, &ntree->nodes) {
- if (current_node->type == NODE_GROUP) {
- if (current_node->id && node_group_has_output_dfs(*current_node)) {
- return true;
- }
- }
- if (current_node->flag & NODE_DO_OUTPUT && current_node->type != NODE_GROUP_OUTPUT) {
- return true;
- }
- }
- return false;
-}
-
-static bool node_group_has_output(Main &bmain, bNode &node)
-{
- BLI_assert(ELEM(node.type, NODE_GROUP, NODE_CUSTOM_GROUP));
- bNodeTree *ntree = (bNodeTree *)node.id;
- if (ntree == nullptr) {
- return false;
- }
- BKE_main_id_tag_listbase(&bmain.nodetrees, LIB_TAG_DOIT, false);
- return node_group_has_output_dfs(node);
-}
-
-bool node_connected_to_output(Main &bmain, bNodeTree &ntree, bNode &node)
-{
- /* Special case for drivers: if node tree has any drivers we assume it is
- * always to be tagged for update when node changes. Otherwise we will be
- * doomed to do some deep and nasty deep search of indirect dependencies,
- * which will be too complicated without real benefit.
- */
- if (ntree_has_drivers(ntree)) {
- return true;
- }
- LISTBASE_FOREACH (bNode *, current_node, &ntree.nodes) {
- /* Special case for group nodes -- if modified node connected to a group
- * with active output inside we consider refresh is needed.
- *
- * We could make check more grained here by taking which socket the node
- * is connected to and so eventually.
- */
- if (ELEM(current_node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
- if (current_node->id != nullptr && ntree_has_drivers((bNodeTree &)current_node->id)) {
- return true;
- }
- if (ntree_check_nodes_connected(ntree, node, *current_node) &&
- node_group_has_output(bmain, *current_node)) {
- return true;
- }
- }
- if (current_node->flag & NODE_DO_OUTPUT) {
- if (ntree_check_nodes_connected(ntree, node, *current_node)) {
- return true;
- }
- }
- if (current_node->type == GEO_NODE_VIEWER) {
- if (ntree_check_nodes_connected(ntree, node, *current_node)) {
- return true;
- }
- }
- }
- return false;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Add Node
* \{ */
@@ -214,7 +100,7 @@ static void clear_picking_highlight(ListBase *links)
}
}
-static bNodeLink *create_drag_link(Main &bmain, SpaceNode &snode, bNode &node, bNodeSocket &sock)
+static bNodeLink *create_drag_link(bNode &node, bNodeSocket &sock)
{
bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), __func__);
if (sock.in_out == SOCK_OUT) {
@@ -226,27 +112,17 @@ static bNodeLink *create_drag_link(Main &bmain, SpaceNode &snode, bNode &node, b
oplink->tosock = &sock;
}
oplink->flag |= NODE_LINK_VALID;
- oplink->flag &= ~NODE_LINK_TEST;
- if (node_connected_to_output(bmain, *snode.edittree, node)) {
- oplink->flag |= NODE_LINK_TEST;
- }
oplink->flag |= NODE_LINK_DRAGGED;
return oplink;
}
-static void pick_link(const bContext &C,
- wmOperator &op,
- bNodeLinkDrag &nldrag,
- SpaceNode &snode,
- bNode *node,
- bNodeLink &link_to_pick)
+static void pick_link(
+ wmOperator &op, bNodeLinkDrag &nldrag, SpaceNode &snode, bNode *node, bNodeLink &link_to_pick)
{
clear_picking_highlight(&snode.edittree->links);
RNA_boolean_set(op.ptr, "has_link_picked", true);
- Main *bmain = CTX_data_main(&C);
- bNodeLink *link = create_drag_link(
- *bmain, snode, *link_to_pick.fromnode, *link_to_pick.fromsock);
+ bNodeLink *link = create_drag_link(*link_to_pick.fromnode, *link_to_pick.fromsock);
nldrag.links.append(link);
nodeRemLink(snode.edittree, &link_to_pick);
@@ -258,7 +134,7 @@ static void pick_link(const bContext &C,
/* Send changed event to original link->tonode. */
if (node) {
- snode_update(snode, node);
+ BKE_ntree_update_tag_node_property(snode.edittree, node);
}
}
@@ -324,7 +200,7 @@ static void pick_input_link_by_link_intersect(const bContext &C,
ED_area_tag_redraw(CTX_wm_area(&C));
if (!node_find_indicated_socket(*snode, &node, &socket, cursor, SOCK_IN)) {
- pick_link(C, op, nldrag, *snode, node, *link_to_pick);
+ pick_link(op, nldrag, *snode, node, *link_to_pick);
}
}
}
@@ -566,7 +442,7 @@ static void snode_autoconnect(Main &bmain,
}
if (numlinks > 0) {
- ntreeUpdateTree(&bmain, ntree);
+ BKE_ntree_update_main_tree(&bmain, ntree, nullptr);
}
}
@@ -640,7 +516,7 @@ static bNodeSocket *node_link_viewer_get_socket(bNodeTree &ntree,
(eNodeSocketDatatype)src_socket.type);
BLI_assert(data_type != CD_AUTO_FROM_NAME);
storage->data_type = data_type;
- nodeUpdate(&ntree, &viewer_node);
+ viewer_node.typeinfo->updatefunc(&ntree, &viewer_node);
return viewer_socket;
}
}
@@ -810,7 +686,7 @@ static int link_socket_to_viewer(const bContext &C,
else {
link_to_change->fromnode = &bnode_to_view;
link_to_change->fromsock = &bsocket_to_view;
- btree.update |= NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_link_changed(&btree);
}
remove_links_to_unavailable_viewer_sockets(btree, *viewer_bnode);
@@ -819,10 +695,7 @@ static int link_socket_to_viewer(const bContext &C,
ED_spreadsheet_context_paths_set_geometry_node(CTX_data_main(&C), &snode, viewer_bnode);
}
- ntreeUpdateTree(CTX_data_main(&C), &btree);
- snode_update(snode, viewer_bnode);
- DEG_id_tag_update(&btree.id, 0);
-
+ BKE_ntree_update_main_tree(CTX_data_main(&C), &btree, nullptr);
return OPERATOR_FINISHED;
}
@@ -863,7 +736,7 @@ static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
- snode_notify(*C, snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree);
return OPERATOR_FINISHED;
}
@@ -1041,17 +914,10 @@ static void node_link_exit(bContext &C, wmOperator &op, const bool apply_links)
SpaceNode &snode = *CTX_wm_space_node(&C);
bNodeTree &ntree = *snode.edittree;
bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op.customdata;
- bool do_tag_update = false;
/* avoid updates while applying links */
ntree.is_updating = true;
for (bNodeLink *link : nldrag->links) {
- /* See note below, but basically TEST flag means that the link
- * was connected to output (or to a node which affects the
- * output).
- */
- do_tag_update |= (link->flag & NODE_LINK_TEST) != 0;
-
link->flag &= ~NODE_LINK_DRAGGED;
if (apply_links && link->tosock && link->fromsock) {
@@ -1067,18 +933,10 @@ static void node_link_exit(bContext &C, wmOperator &op, const bool apply_links)
/* add link to the node tree */
BLI_addtail(&ntree.links, link);
-
- ntree.update |= NTREE_UPDATE_LINKS;
-
- /* tag tonode for update */
- link->tonode->update |= NODE_UPDATE;
+ BKE_ntree_update_tag_link_added(&ntree, link);
/* we might need to remove a link */
node_remove_extra_links(snode, *link);
-
- if (link->tonode) {
- do_tag_update |= (do_tag_update || node_connected_to_output(*bmain, ntree, *link->tonode));
- }
}
else {
nodeRemLink(&ntree, link);
@@ -1086,11 +944,7 @@ static void node_link_exit(bContext &C, wmOperator &op, const bool apply_links)
}
ntree.is_updating = false;
- ntreeUpdateTree(bmain, &ntree);
- snode_notify(C, snode);
- if (do_tag_update) {
- snode_dag_update(C, snode);
- }
+ ED_node_tree_propagate_change(&C, bmain, &ntree);
/* Ensure draglink tooltip is disabled. */
draw_draglink_tooltip_deactivate(*CTX_wm_region(&C), *nldrag);
@@ -1250,8 +1104,7 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
-static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain,
- SpaceNode &snode,
+static std::unique_ptr<bNodeLinkDrag> node_link_init(SpaceNode &snode,
float2 cursor,
const bool detach)
{
@@ -1276,17 +1129,6 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain,
oplink->flag |= NODE_LINK_VALID;
oplink->flag |= NODE_LINK_DRAGGED;
- /* The link could be disconnected and in that case we
- * wouldn't be able to check whether tag update is
- * needed or not when releasing mouse button. So we
- * cache whether the link affects output or not here
- * using TEST flag.
- */
- oplink->flag &= ~NODE_LINK_TEST;
- if (node_connected_to_output(bmain, *snode.edittree, *link->tonode)) {
- oplink->flag |= NODE_LINK_TEST;
- }
-
nldrag->links.append(oplink);
nodeRemLink(snode.edittree, link);
}
@@ -1296,7 +1138,7 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain,
/* dragged links are fixed on output side */
nldrag->in_out = SOCK_OUT;
/* create a new link */
- nldrag->links.append(create_drag_link(bmain, snode, *node, *sock));
+ nldrag->links.append(create_drag_link(*node, *sock));
}
return nldrag;
}
@@ -1329,17 +1171,13 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain,
oplink->next = oplink->prev = nullptr;
oplink->flag |= NODE_LINK_VALID;
oplink->flag |= NODE_LINK_DRAGGED;
- oplink->flag &= ~NODE_LINK_TEST;
- if (node_connected_to_output(bmain, *snode.edittree, *link_to_pick->tonode)) {
- oplink->flag |= NODE_LINK_TEST;
- }
nldrag->links.append(oplink);
nodeRemLink(snode.edittree, link_to_pick);
/* send changed event to original link->tonode */
if (node) {
- snode_update(snode, node);
+ BKE_ntree_update_tag_node_property(snode.edittree, node);
}
}
}
@@ -1347,7 +1185,7 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain,
/* dragged links are fixed on input side */
nldrag->in_out = SOCK_IN;
/* create a new link */
- nldrag->links.append(create_drag_link(bmain, snode, *node, *sock));
+ nldrag->links.append(create_drag_link(*node, *sock));
}
return nldrag;
}
@@ -1370,7 +1208,7 @@ static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
ED_preview_kill_jobs(CTX_wm_manager(C), &bmain);
- std::unique_ptr<bNodeLinkDrag> nldrag = node_link_init(bmain, snode, cursor, detach);
+ std::unique_ptr<bNodeLinkDrag> nldrag = node_link_init(snode, cursor, detach);
if (nldrag) {
UI_view2d_edge_pan_operator_init(C, &nldrag->pan_data, op);
@@ -1473,9 +1311,7 @@ static int node_make_link_exec(bContext *C, wmOperator *op)
node_deselect_all_input_sockets(snode, false);
node_deselect_all_output_sockets(snode, false);
- ntreeUpdateTree(CTX_data_main(C), snode.edittree);
- snode_notify(*C, snode);
- snode_dag_update(*C, snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree);
return OPERATOR_FINISHED;
}
@@ -1532,7 +1368,6 @@ static int cut_links_exec(bContext *C, wmOperator *op)
Main &bmain = *CTX_data_main(C);
SpaceNode &snode = *CTX_wm_space_node(C);
ARegion &region = *CTX_wm_region(C);
- bool do_tag_update = false;
int i = 0;
float mcoords[256][2];
@@ -1567,23 +1402,14 @@ static int cut_links_exec(bContext *C, wmOperator *op)
found = true;
}
- do_tag_update |= (do_tag_update ||
- node_connected_to_output(bmain, *snode.edittree, *link->tonode));
-
- snode_update(snode, link->tonode);
bNode *to_node = link->tonode;
nodeRemLink(snode.edittree, link);
sort_multi_input_socket_links(snode, *to_node, nullptr, nullptr);
}
}
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree);
if (found) {
- ntreeUpdateTree(CTX_data_main(C), snode.edittree);
- snode_notify(*C, snode);
- if (do_tag_update) {
- snode_dag_update(*C, snode);
- }
-
return OPERATOR_FINISHED;
}
@@ -1629,7 +1455,6 @@ static int mute_links_exec(bContext *C, wmOperator *op)
Main &bmain = *CTX_data_main(C);
SpaceNode &snode = *CTX_wm_space_node(C);
ARegion &region = *CTX_wm_region(C);
- bool do_tag_update = false;
int i = 0;
float mcoords[256][2];
@@ -1671,10 +1496,6 @@ static int mute_links_exec(bContext *C, wmOperator *op)
}
if (node_links_intersect(*link, mcoords, i)) {
- do_tag_update |= (do_tag_update ||
- node_connected_to_output(bmain, *snode.edittree, *link->tonode));
-
- snode_update(snode, link->tonode);
nodeMuteLinkToggle(snode.edittree, link);
}
}
@@ -1687,12 +1508,7 @@ static int mute_links_exec(bContext *C, wmOperator *op)
link->flag &= ~NODE_LINK_TEST;
}
- ntreeUpdateTree(CTX_data_main(C), snode.edittree);
- snode_notify(*C, snode);
- if (do_tag_update) {
- snode_dag_update(*C, snode);
- }
-
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree);
return OPERATOR_FINISHED;
}
@@ -1743,11 +1559,7 @@ static int detach_links_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- ntreeUpdateTree(CTX_data_main(C), &ntree);
-
- snode_notify(*C, snode);
- snode_dag_update(*C, snode);
-
+ ED_node_tree_propagate_change(C, CTX_data_main(C), &ntree);
return OPERATOR_FINISHED;
}
@@ -2663,10 +2475,7 @@ void ED_node_link_insert(Main *bmain, ScrArea *area)
snode->runtime->iofsd = iofsd;
}
- ntreeUpdateTree(bmain, snode->edittree); /* needed for pointers */
- snode_update(*snode, select);
- ED_node_tag_update_id((ID *)snode->edittree);
- ED_node_tag_update_id(snode->id);
+ ED_node_tree_propagate_change(nullptr, bmain, snode->edittree);
}
}
}
diff --git a/source/blender/editors/space_node/node_templates.cc b/source/blender/editors/space_node/node_templates.cc
index 386178596af..defb1e82c3e 100644
--- a/source/blender/editors/space_node/node_templates.cc
+++ b/source/blender/editors/space_node/node_templates.cc
@@ -37,6 +37,7 @@
#include "BKE_context.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
+#include "BKE_node_tree_update.h"
#include "RNA_access.h"
@@ -84,7 +85,7 @@ static void node_link_item_apply(Main *bmain, bNode *node, NodeLinkItem *item)
{
if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
node->id = (ID *)item->ngroup;
- ntreeUpdateTree(bmain, item->ngroup);
+ BKE_ntree_update_main_tree(bmain, item->ngroup, nullptr);
}
else {
/* nothing to do for now */
@@ -179,10 +180,8 @@ static void node_socket_disconnect(Main *bmain,
nodeRemLink(ntree, sock_to->link);
sock_to->flag |= SOCK_COLLAPSED;
- nodeUpdate(ntree, node_to);
- ntreeUpdateTree(bmain, ntree);
-
- ED_node_tag_update_nodetree(bmain, ntree, node_to);
+ BKE_ntree_update_tag_node_property(ntree, node_to);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
/* remove all nodes connected to this socket, if they aren't connected to other nodes */
@@ -195,10 +194,8 @@ static void node_socket_remove(Main *bmain, bNodeTree *ntree, bNode *node_to, bN
node_remove_linked(bmain, ntree, sock_to->link->fromnode);
sock_to->flag |= SOCK_COLLAPSED;
- nodeUpdate(ntree, node_to);
- ntreeUpdateTree(bmain, ntree);
-
- ED_node_tag_update_nodetree(bmain, ntree, node_to);
+ BKE_ntree_update_tag_node_property(ntree, node_to);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
/* add new node connected to this socket, or replace an existing one */
@@ -299,11 +296,9 @@ static void node_socket_add_replace(const bContext *C,
node_remove_linked(bmain, ntree, node_prev);
}
- nodeUpdate(ntree, node_from);
- nodeUpdate(ntree, node_to);
- ntreeUpdateTree(CTX_data_main(C), ntree);
-
- ED_node_tag_update_nodetree(CTX_data_main(C), ntree, node_to);
+ BKE_ntree_update_tag_node_property(ntree, node_from);
+ BKE_ntree_update_tag_node_property(ntree, node_to);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
/****************************** Node Link Menu *******************************/
diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc
index 4cc0bed1928..96c6dd89447 100644
--- a/source/blender/editors/space_node/space_node.cc
+++ b/source/blender/editors/space_node/space_node.cc
@@ -313,6 +313,19 @@ static void node_init(struct wmWindowManager *UNUSED(wm), ScrArea *area)
}
}
+static bool any_node_uses_id(const bNodeTree *ntree, const ID *id)
+{
+ if (ELEM(nullptr, ntree, id)) {
+ return false;
+ }
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->id == id) {
+ return true;
+ }
+ }
+ return false;
+}
+
static void node_area_listener(const wmSpaceTypeListenerParams *params)
{
ScrArea *area = params->area;
@@ -436,10 +449,9 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params)
case NC_IMAGE:
if (wmn->action == NA_EDITED) {
if (ED_node_is_compositor(snode)) {
- /* note that nodeUpdateID is already called by BKE_image_signal() on all
- * scenes so really this is just to know if the images is used in the compo else
- * painting on images could become very slow when the compositor is open. */
- if (nodeUpdateID(snode->nodetree, (ID *)wmn->reference)) {
+ /* Without this check drawing on an image could become very slow when the compositor is
+ * open. */
+ if (any_node_uses_id(snode->nodetree, (ID *)wmn->reference)) {
ED_area_tag_refresh(area);
}
}
@@ -449,7 +461,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params)
case NC_MOVIECLIP:
if (wmn->action == NA_EDITED) {
if (ED_node_is_compositor(snode)) {
- if (nodeUpdateID(snode->nodetree, (ID *)wmn->reference)) {
+ if (any_node_uses_id(snode->nodetree, (ID *)wmn->reference)) {
ED_area_tag_refresh(area);
}
}
diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c
index a4d5f2635d4..85fee590447 100644
--- a/source/blender/editors/space_outliner/outliner_dragdrop.c
+++ b/source/blender/editors/space_outliner/outliner_dragdrop.c
@@ -123,7 +123,7 @@ static ID *outliner_ID_drop_find(bContext *C, const wmEvent *event, short idcode
/* Find tree element to drop into, with additional before and after reorder support. */
static TreeElement *outliner_drop_insert_find(bContext *C,
- const wmEvent *event,
+ const int xy[2],
TreeElementInsertType *r_insert_type)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
@@ -136,8 +136,11 @@ static TreeElement *outliner_drop_insert_find(bContext *C,
return NULL;
}
- UI_view2d_region_to_view(
- &region->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
+ int mval[2];
+ mval[0] = xy[0] - region->winrct.xmin;
+ mval[1] = xy[1] - region->winrct.ymin;
+
+ UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &view_mval[0], &view_mval[1]);
te_hovered = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]);
if (te_hovered) {
@@ -216,10 +219,10 @@ static bool is_pchan_element(TreeElement *te)
}
static TreeElement *outliner_drop_insert_collection_find(bContext *C,
- const wmEvent *event,
+ const int xy[2],
TreeElementInsertType *r_insert_type)
{
- TreeElement *te = outliner_drop_insert_find(C, event, r_insert_type);
+ TreeElement *te = outliner_drop_insert_find(C, xy, r_insert_type);
if (!te) {
return NULL;
}
@@ -707,7 +710,7 @@ static bool datastack_drop_init(bContext *C, const wmEvent *event, StackDropData
return false;
}
- TreeElement *te_target = outliner_drop_insert_find(C, event, &drop_data->insert_type);
+ TreeElement *te_target = outliner_drop_insert_find(C, event->xy, &drop_data->insert_type);
if (!te_target) {
return false;
}
@@ -1088,14 +1091,12 @@ static Collection *collection_parent_from_ID(ID *id)
return NULL;
}
-static bool collection_drop_init(bContext *C,
- wmDrag *drag,
- const wmEvent *event,
- CollectionDrop *data)
+static bool collection_drop_init(
+ bContext *C, wmDrag *drag, const int xy[2], const bool is_link, CollectionDrop *data)
{
/* Get collection to drop into. */
TreeElementInsertType insert_type;
- TreeElement *te = outliner_drop_insert_collection_find(C, event, &insert_type);
+ TreeElement *te = outliner_drop_insert_collection_find(C, xy, &insert_type);
if (!te) {
return false;
}
@@ -1123,7 +1124,7 @@ static bool collection_drop_init(bContext *C,
/* Get collection to drag out of. */
ID *parent = drag_id->from_parent;
Collection *from_collection = collection_parent_from_ID(parent);
- if (event->ctrl) {
+ if (is_link) {
from_collection = NULL;
}
@@ -1164,7 +1165,7 @@ static bool collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event
&space_outliner->tree, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false);
CollectionDrop data;
- if (!event->shift && collection_drop_init(C, drag, event, &data)) {
+ if (!event->shift && collection_drop_init(C, drag, event->xy, event->ctrl, &data)) {
TreeElement *te = data.te;
TreeStoreElem *tselem = TREESTORE(te);
if (!data.from || event->ctrl) {
@@ -1201,13 +1202,14 @@ static bool collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event
static char *collection_drop_tooltip(bContext *C,
wmDrag *drag,
- const int UNUSED(xy[2]),
+ const int xy[2],
wmDropBox *UNUSED(drop))
{
- wmWindowManager *wm = CTX_wm_manager(C);
- const wmEvent *event = wm->winactive ? wm->winactive->eventstate : NULL;
+ wmWindow *win = CTX_wm_window(C);
+ const wmEvent *event = win ? win->eventstate : NULL;
+
CollectionDrop data;
- if (event && !event->shift && collection_drop_init(C, drag, event, &data)) {
+ if (event && !event->shift && collection_drop_init(C, drag, xy, event->ctrl, &data)) {
TreeElement *te = data.te;
if (!data.from || event->ctrl) {
return BLI_strdup(TIP_("Link inside Collection"));
@@ -1260,7 +1262,7 @@ static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmE
wmDrag *drag = lb->first;
CollectionDrop data;
- if (!collection_drop_init(C, drag, event, &data)) {
+ if (!collection_drop_init(C, drag, event->xy, event->ctrl, &data)) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 9d4b14a1f57..ba4759826cd 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -38,6 +38,7 @@
#include "BLT_translation.h"
+#include "BKE_action.h"
#include "BKE_animsys.h"
#include "BKE_appdir.h"
#include "BKE_armature.h"
@@ -48,6 +49,7 @@
#include "BKE_lib_query.h"
#include "BKE_lib_remap.h"
#include "BKE_main.h"
+#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_workspace.h"
@@ -654,7 +656,7 @@ static int outliner_id_remap_invoke(bContext *C, wmOperator *op, const wmEvent *
outliner_id_remap_find_tree_element(C, op, &space_outliner->tree, fmval[1]);
}
- return WM_operator_props_dialog_popup(C, op, 200);
+ return WM_operator_props_dialog_popup(C, op, 400);
}
static const EnumPropertyItem *outliner_id_itemf(bContext *C,
@@ -703,6 +705,9 @@ void OUTLINER_OT_id_remap(wmOperatorType *ot)
prop = RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", "");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
+ /* Changing ID type wont make sense, would return early with "Invalid old/new ID pair" anyways.
+ */
+ RNA_def_property_flag(prop, PROP_HIDDEN);
prop = RNA_def_enum(ot->srna, "old_id", DummyRNA_NULL_items, 0, "Old ID", "Old ID to replace");
RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, outliner_id_itemf);
@@ -1262,7 +1267,8 @@ static TreeElement *outliner_show_active_get_element(bContext *C,
TreeElement *te_obact = te;
if (obact->mode & OB_MODE_POSE) {
- bPoseChannel *pchan = CTX_data_active_pose_bone(C);
+ Object *obpose = BKE_object_pose_armature_get(obact);
+ bPoseChannel *pchan = BKE_pose_channel_active(obpose, false);
if (pchan) {
te = outliner_find_posechannel(&te_obact->subtree, pchan);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 616953e720a..9f31e55439d 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -627,6 +627,19 @@ static void seq_build_proxy(bContext *C, Sequence *seq)
ED_area_tag_redraw(CTX_wm_area(C));
}
+static void sequencer_add_movie_clamp_sound_strip_length(Scene *scene,
+ ListBase *seqbase,
+ Sequence *seq_movie,
+ Sequence *seq_sound)
+{
+ if (ELEM(NULL, seq_movie, seq_sound) || seq_sound->len <= seq_movie->len) {
+ return;
+ }
+
+ SEQ_transform_set_right_handle_frame(seq_sound, SEQ_transform_get_right_handle_frame(seq_movie));
+ SEQ_time_update_sequence(scene, seqbase, seq_sound);
+}
+
static void sequencer_add_movie_multiple_strips(bContext *C,
wmOperator *op,
SeqLoadData *load_data)
@@ -689,6 +702,7 @@ static void sequencer_add_movie_multiple_strips(bContext *C,
else {
load_data->start_frame += seq_movie->enddisp - seq_movie->startdisp;
}
+ sequencer_add_movie_clamp_sound_strip_length(scene, ed->seqbasep, seq_movie, seq_sound);
seq_load_apply_generic_options(C, op, seq_sound);
seq_load_apply_generic_options(C, op, seq_movie);
seq_build_proxy(C, seq_movie);
@@ -740,6 +754,7 @@ static bool sequencer_add_movie_single_strip(bContext *C, wmOperator *op, SeqLoa
load_data->start_frame += audio_frame_offset;
seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data, audio_skip);
}
+ sequencer_add_movie_clamp_sound_strip_length(scene, ed->seqbasep, seq_movie, seq_sound);
seq_load_apply_generic_options(C, op, seq_sound);
seq_load_apply_generic_options(C, op, seq_movie);
seq_build_proxy(C, seq_movie);
diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
index 61cc70830af..7526a61bf4a 100644
--- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
+++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
@@ -114,7 +114,7 @@ static void spreadsheet_free(SpaceLink *sl)
{
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
- delete sspreadsheet->runtime;
+ MEM_delete(sspreadsheet->runtime);
LISTBASE_FOREACH_MUTABLE (SpreadsheetRowFilter *, row_filter, &sspreadsheet->row_filters) {
spreadsheet_row_filter_free(row_filter);
@@ -131,7 +131,7 @@ static void spreadsheet_init(wmWindowManager *UNUSED(wm), ScrArea *area)
{
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)area->spacedata.first;
if (sspreadsheet->runtime == nullptr) {
- sspreadsheet->runtime = new SpaceSpreadsheet_Runtime();
+ sspreadsheet->runtime = MEM_new<SpaceSpreadsheet_Runtime>(__func__);
}
}
@@ -140,10 +140,11 @@ static SpaceLink *spreadsheet_duplicate(SpaceLink *sl)
const SpaceSpreadsheet *sspreadsheet_old = (SpaceSpreadsheet *)sl;
SpaceSpreadsheet *sspreadsheet_new = (SpaceSpreadsheet *)MEM_dupallocN(sspreadsheet_old);
if (sspreadsheet_old->runtime) {
- sspreadsheet_new->runtime = new SpaceSpreadsheet_Runtime(*sspreadsheet_old->runtime);
+ sspreadsheet_new->runtime = MEM_new<SpaceSpreadsheet_Runtime>(__func__,
+ *sspreadsheet_old->runtime);
}
else {
- sspreadsheet_new->runtime = new SpaceSpreadsheet_Runtime();
+ sspreadsheet_new->runtime = MEM_new<SpaceSpreadsheet_Runtime>(__func__);
}
BLI_listbase_clear(&sspreadsheet_new->row_filters);
diff --git a/source/blender/editors/space_topbar/space_topbar.c b/source/blender/editors/space_topbar/space_topbar.c
index 41eddd32854..7f0f30624cb 100644
--- a/source/blender/editors/space_topbar/space_topbar.c
+++ b/source/blender/editors/space_topbar/space_topbar.c
@@ -35,6 +35,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_screen.h"
+#include "BKE_undo_system.h"
#include "ED_screen.h"
#include "ED_space_api.h"
@@ -236,6 +237,59 @@ static void recent_files_menu_register(void)
WM_menutype_add(mt);
}
+static void undo_history_draw_menu(const bContext *C, Menu *menu)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ if (wm->undo_stack == NULL) {
+ return;
+ }
+ int undo_step_count = 0;
+ for (UndoStep *us = wm->undo_stack->steps.first; us; us = us->next) {
+ if (us->skip) {
+ continue;
+ }
+ undo_step_count += 1;
+ }
+
+ uiLayout *split = uiLayoutSplit(menu->layout, 0.0f, false);
+ uiLayout *column = NULL;
+
+ const int col_size = 20 + (undo_step_count / 12);
+ int i = 0;
+
+ undo_step_count = 0;
+ for (UndoStep *us = wm->undo_stack->steps.first; us; us = us->next, i++) {
+ if (us->skip) {
+ continue;
+ }
+ if (!(undo_step_count % col_size)) {
+ column = uiLayoutColumn(split, false);
+ }
+ const bool is_active = (us == wm->undo_stack->step_active);
+ uiLayout *row = uiLayoutRow(column, false);
+ uiLayoutSetEnabled(row, !is_active);
+ uiItemIntO(row,
+ IFACE_(us->name),
+ is_active ? ICON_LAYER_ACTIVE : ICON_NONE,
+ "ED_OT_undo_history",
+ "item",
+ i);
+ undo_step_count += 1;
+ }
+}
+
+static void undo_history_menu_register(void)
+{
+ MenuType *mt;
+
+ mt = MEM_callocN(sizeof(MenuType), __func__);
+ strcpy(mt->idname, "TOPBAR_MT_undo_history");
+ strcpy(mt->label, N_("Undo History"));
+ strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ mt->draw = undo_history_draw_menu;
+ WM_menutype_add(mt);
+}
+
void ED_spacetype_topbar(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype topbar");
@@ -278,6 +332,7 @@ void ED_spacetype_topbar(void)
BLI_addhead(&st->regiontypes, art);
recent_files_menu_register();
+ undo_history_menu_register();
BKE_spacetype_register(st);
}
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index b79303551a1..5451aa5a2e0 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -1552,7 +1552,7 @@ static void v3d_posearmature_buts(uiLayout *layout, Object *ob)
PointerRNA pchanptr;
uiLayout *col;
- pchan = BKE_pose_channel_active(ob);
+ pchan = BKE_pose_channel_active_if_layer_visible(ob);
if (!pchan) {
uiItemL(layout, IFACE_("No Bone Active"), ICON_NONE);
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 830f7cbeff1..80089815284 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -3216,7 +3216,7 @@ static int view_lock_to_active_exec(bContext *C, wmOperator *UNUSED(op))
if (obact->mode & OB_MODE_POSE) {
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *obact_eval = DEG_get_evaluated_object(depsgraph, obact);
- bPoseChannel *pcham_act = BKE_pose_channel_active(obact_eval);
+ bPoseChannel *pcham_act = BKE_pose_channel_active_if_layer_visible(obact_eval);
if (pcham_act) {
BLI_strncpy(v3d->ob_center_bone, pcham_act->name, sizeof(v3d->ob_center_bone));
}
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_armature.c b/source/blender/editors/space_view3d/view3d_gizmo_armature.c
index 83d3286c8b3..31ae8a92f81 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_armature.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_armature.c
@@ -134,7 +134,7 @@ static bool WIDGETGROUP_armature_spline_poll(const bContext *C, wmGizmoGroupType
if (ob) {
const bArmature *arm = ob->data;
if (arm->drawtype == ARM_B_BONE) {
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
if (pchan && pchan->bone->segments > 1) {
return true;
}
@@ -148,7 +148,7 @@ static void WIDGETGROUP_armature_spline_setup(const bContext *C, wmGizmoGroup *g
{
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = BKE_object_pose_armature_get(OBACT(view_layer));
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
const wmGizmoType *gzt_move = WM_gizmotype_find("GIZMO_GT_move_3d", true);
@@ -187,7 +187,7 @@ static void WIDGETGROUP_armature_spline_refresh(const bContext *C, wmGizmoGroup
}
struct BoneSplineWidgetGroup *bspline_group = gzgroup->customdata;
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
/* Handles */
for (int i = 0; i < ARRAY_SIZE(bspline_group->handles); i++) {
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index 8f3d13176a3..4107cc3a71c 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -914,6 +914,9 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
case TC_SEQ_DATA:
special_aftertrans_update__sequencer(C, t);
break;
+ case TC_SEQ_IMAGE_DATA:
+ special_aftertrans_update__sequencer_image(C, t);
+ break;
case TC_TRACKING_DATA:
special_aftertrans_update__movieclip(C, t);
break;
@@ -930,7 +933,6 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
case TC_OBJECT_TEXSPACE:
case TC_PAINT_CURVE_VERTS:
case TC_PARTICLE_VERTS:
- case TC_SEQ_IMAGE_DATA:
case TC_NONE:
default:
break;
diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h
index 5ed8182857d..12f3b39927e 100644
--- a/source/blender/editors/transform/transform_convert.h
+++ b/source/blender/editors/transform/transform_convert.h
@@ -304,6 +304,7 @@ void special_aftertrans_update__sequencer(bContext *C, TransInfo *t);
/* transform_convert_sequencer_image.c */
void createTransSeqImageData(TransInfo *t);
void recalcData_sequencer_image(TransInfo *t);
+void special_aftertrans_update__sequencer_image(bContext *C, TransInfo *t);
/* transform_convert_tracking.c */
void createTransTrackingData(bContext *C, TransInfo *t);
diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c
index 63aada0f797..5d0a3bd9dd1 100644
--- a/source/blender/editors/transform/transform_convert_armature.c
+++ b/source/blender/editors/transform/transform_convert_armature.c
@@ -427,7 +427,7 @@ static short pose_grab_with_ik(Main *bmain, Object *ob)
/* Rule: allow multiple Bones
* (but they must be selected, and only one ik-solver per chain should get added) */
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone->layer & arm->layer) {
+ if (BKE_pose_is_layer_visible(arm, pchan)) {
if (pchan->bone->flag & (BONE_SELECTED | BONE_TRANSFORM_MIRROR)) {
/* Rule: no IK for solitary (unconnected) bones. */
for (bonec = pchan->bone->childbase.first; bonec; bonec = bonec->next) {
diff --git a/source/blender/editors/transform/transform_convert_mask.c b/source/blender/editors/transform/transform_convert_mask.c
index 1a25cfd1efb..e26172cd764 100644
--- a/source/blender/editors/transform/transform_convert_mask.c
+++ b/source/blender/editors/transform/transform_convert_mask.c
@@ -472,12 +472,7 @@ void special_aftertrans_update__mask(bContext *C, TransInfo *t)
}
if (t->scene->nodetree) {
- /* tracks can be used for stabilization nodes,
- * flush update for such nodes */
- // if (nodeUpdateID(t->scene->nodetree, &mask->id))
- {
- WM_event_add_notifier(C, NC_MASK | ND_DATA, &mask->id);
- }
+ WM_event_add_notifier(C, NC_MASK | ND_DATA, &mask->id);
}
/* TODO: don't key all masks. */
diff --git a/source/blender/editors/transform/transform_convert_node.c b/source/blender/editors/transform/transform_convert_node.c
index da11666d445..e8cdfaf1f40 100644
--- a/source/blender/editors/transform/transform_convert_node.c
+++ b/source/blender/editors/transform/transform_convert_node.c
@@ -31,6 +31,7 @@
#include "BKE_context.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_report.h"
#include "ED_node.h"
@@ -246,7 +247,7 @@ void special_aftertrans_update__node(bContext *C, TransInfo *t)
nodeRemoveNode(bmain, ntree, node, true);
}
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(C, bmain, ntree);
}
}
diff --git a/source/blender/editors/transform/transform_convert_sequencer_image.c b/source/blender/editors/transform/transform_convert_sequencer_image.c
index d5a59885014..3a5770c2863 100644
--- a/source/blender/editors/transform/transform_convert_sequencer_image.c
+++ b/source/blender/editors/transform/transform_convert_sequencer_image.c
@@ -38,8 +38,12 @@
#include "SEQ_transform.h"
#include "SEQ_utils.h"
+#include "ED_keyframing.h"
+
#include "UI_view2d.h"
+#include "RNA_access.h"
+
#include "transform.h"
#include "transform_convert.h"
@@ -215,3 +219,44 @@ void recalcData_sequencer_image(TransInfo *t)
SEQ_relations_invalidate_cache_preprocessed(t->scene, seq);
}
}
+
+void special_aftertrans_update__sequencer_image(bContext *UNUSED(C), TransInfo *t)
+{
+ if (t->state == TRANS_CANCEL) {
+ return;
+ }
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+ TransData *td = NULL;
+ TransData2D *td2d = NULL;
+ int i;
+
+ PointerRNA ptr;
+ PropertyRNA *prop;
+
+ for (i = 0, td = tc->data, td2d = tc->data_2d; i < tc->data_len; i++, td++, td2d++) {
+ TransDataSeq *tdseq = td->extra;
+ Sequence *seq = tdseq->seq;
+ StripTransform *transform = seq->strip->transform;
+ Scene *scene = t->scene;
+
+ RNA_pointer_create(&scene->id, &RNA_SequenceTransform, transform, &ptr);
+
+ if (t->mode == TFM_ROTATION) {
+ prop = RNA_struct_find_property(&ptr, "rotation");
+ ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA);
+ }
+ if (t->mode == TFM_TRANSLATION) {
+ prop = RNA_struct_find_property(&ptr, "offset_x");
+ ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA);
+ prop = RNA_struct_find_property(&ptr, "offset_y");
+ ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA);
+ }
+ if (t->mode == TFM_RESIZE) {
+ prop = RNA_struct_find_property(&ptr, "scale_x");
+ ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA);
+ prop = RNA_struct_find_property(&ptr, "scale_y");
+ ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA);
+ }
+ }
+}
diff --git a/source/blender/editors/transform/transform_convert_tracking.c b/source/blender/editors/transform/transform_convert_tracking.c
index dc37f2796bf..f2d0fb7ac2f 100644
--- a/source/blender/editors/transform/transform_convert_tracking.c
+++ b/source/blender/editors/transform/transform_convert_tracking.c
@@ -29,8 +29,10 @@
#include "BLI_math.h"
#include "BKE_context.h"
+#include "BKE_main.h"
#include "BKE_movieclip.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_tracking.h"
#include "ED_clip.h"
@@ -793,8 +795,12 @@ void special_aftertrans_update__movieclip(bContext *C, TransInfo *t)
/* Tracks can be used for stabilization nodes,
* flush update for such nodes.
*/
- nodeUpdateID(t->scene->nodetree, &clip->id);
- WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL);
+ if (t->context != NULL) {
+ Main *bmain = CTX_data_main(C);
+ BKE_ntree_update_tag_id_changed(bmain, &clip->id);
+ BKE_ntree_update_main(bmain, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL);
+ }
}
}
diff --git a/source/blender/editors/transform/transform_mode_timetranslate.c b/source/blender/editors/transform/transform_mode_timetranslate.c
index 5f2a2e472c5..84ca5d3ae54 100644
--- a/source/blender/editors/transform/transform_mode_timetranslate.c
+++ b/source/blender/editors/transform/transform_mode_timetranslate.c
@@ -62,27 +62,28 @@ static void headerTimeTranslate(TransInfo *t, char str[UI_MAX_DRAW_STR])
float ival = TRANS_DATA_CONTAINER_FIRST_OK(t)->data->ival;
float val = ival + t->values_final[0];
- float snap_val = val;
- snapFrameTransform(t, autosnap, ival, val, &snap_val);
+ snapFrameTransform(t, autosnap, ival, val, &val);
+ float delta_x = val - ival;
if (ELEM(autosnap, SACTSNAP_SECOND, SACTSNAP_TSTEP)) {
/* Convert to seconds. */
const Scene *scene = t->scene;
const double secf = FPS;
- snap_val /= secf;
+ delta_x /= secf;
+ val /= secf;
}
if (autosnap == SACTSNAP_FRAME) {
- BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f (%.4f)", snap_val, val);
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f (%.4f)", delta_x, val);
}
else if (autosnap == SACTSNAP_SECOND) {
- BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f sec (%.4f)", snap_val, val);
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f sec (%.4f)", delta_x, val);
}
else if (autosnap == SACTSNAP_TSTEP) {
- BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f sec", snap_val);
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f sec", delta_x);
}
else {
- BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", snap_val);
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", delta_x);
}
}
diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c
index 19d0c6d39a3..b8b043c650f 100644
--- a/source/blender/editors/transform/transform_mode_translate.c
+++ b/source/blender/editors/transform/transform_mode_translate.c
@@ -225,11 +225,12 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_
if (t->spacetype == SPACE_GRAPH) {
/* WORKAROUND:
* Special case where snapping is done in #recalData.
- * Update the header based on the first element. */
+ * Update the header based on the #center_local. */
const short autosnap = getAnimEdit_SnapMode(t);
- float ival = TRANS_DATA_CONTAINER_FIRST_OK(t)->data->ival;
+ float ival = TRANS_DATA_CONTAINER_FIRST_OK(t)->center_local[0];
float val = ival + dvec[0];
- snapFrameTransform(t, autosnap, ival, val, &dvec[0]);
+ snapFrameTransform(t, autosnap, ival, val, &val);
+ dvec[0] = val - ival;
}
if (t->con.mode & CON_APPLY) {
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index fa2485c33c2..5ac5bccd69c 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -513,7 +513,7 @@ short ED_transform_calc_orientation_from_type_ex(const Scene *scene,
if (ob) {
if (ob->mode & OB_MODE_POSE) {
- const bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ const bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
if (pchan && gimbal_axis_pose(ob, pchan, r_mat)) {
break;
}
@@ -1224,7 +1224,7 @@ int getTransformOrientation_ex(ViewLayer *view_layer,
float imat[3][3], mat[3][3];
bool ok = false;
- if (activeOnly && (pchan = BKE_pose_channel_active(ob))) {
+ if (activeOnly && (pchan = BKE_pose_channel_active_if_layer_visible(ob))) {
add_v3_v3(normal, pchan->pose_mat[2]);
add_v3_v3(plane, pchan->pose_mat[1]);
ok = true;
diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c
index aca99f81e7b..c6fa5acfff5 100644
--- a/source/blender/editors/undo/ed_undo.c
+++ b/source/blender/editors/undo/ed_undo.c
@@ -64,6 +64,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -759,81 +760,16 @@ void ED_undo_operator_repeat_cb_evt(bContext *C, void *arg_op, int UNUSED(arg_un
/* -------------------------------------------------------------------- */
/** \name Undo History Operator
+ *
+ * See `TOPBAR_MT_undo_history` which is used to access this operator.
* \{ */
-/* create enum based on undo items */
-static const EnumPropertyItem *rna_undo_itemf(bContext *C, int *totitem)
-{
- EnumPropertyItem item_tmp = {0}, *item = NULL;
- int i = 0;
-
- wmWindowManager *wm = CTX_wm_manager(C);
- if (wm->undo_stack == NULL) {
- return NULL;
- }
-
- for (UndoStep *us = wm->undo_stack->steps.first; us; us = us->next, i++) {
- if (us->skip == false) {
- item_tmp.identifier = us->name;
- item_tmp.name = IFACE_(us->name);
- if (us == wm->undo_stack->step_active) {
- item_tmp.icon = ICON_LAYER_ACTIVE;
- }
- else {
- item_tmp.icon = ICON_NONE;
- }
- item_tmp.value = i;
- RNA_enum_item_add(&item, totitem, &item_tmp);
- }
- }
- RNA_enum_item_end(&item, totitem);
-
- return item;
-}
-
-static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- int totitem = 0;
-
- {
- const EnumPropertyItem *item = rna_undo_itemf(C, &totitem);
-
- if (totitem > 0) {
- uiPopupMenu *pup = UI_popup_menu_begin(
- C, WM_operatortype_name(op->type, op->ptr), ICON_NONE);
- uiLayout *layout = UI_popup_menu_layout(pup);
- uiLayout *split = uiLayoutSplit(layout, 0.0f, false);
- uiLayout *column = NULL;
- const int col_size = 20 + totitem / 12;
- int i, c;
- bool add_col = true;
-
- for (c = 0, i = totitem; i--;) {
- if (add_col && !(c % col_size)) {
- column = uiLayoutColumn(split, false);
- add_col = false;
- }
- if (item[i].identifier) {
- uiItemIntO(column, item[i].name, item[i].icon, op->type->idname, "item", item[i].value);
- c++;
- add_col = true;
- }
- }
-
- MEM_freeN((void *)item);
-
- UI_popup_menu_end(C, pup);
- }
- }
- return OPERATOR_CANCELLED;
-}
-
/* NOTE: also check #ed_undo_step() in top if you change notifiers. */
static int undo_history_exec(bContext *C, wmOperator *op)
{
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "item");
if (RNA_property_is_set(op->ptr, prop)) {
- int item = RNA_property_int_get(op->ptr, prop);
+ const int item = RNA_property_int_get(op->ptr, prop);
const int ret = ed_undo_step_by_index(C, item, op->reports);
if (ret & OPERATOR_FINISHED) {
ed_undo_refresh_for_op(C);
@@ -845,14 +781,15 @@ static int undo_history_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-static bool undo_history_poll(bContext *C)
+static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- if (!ed_undo_is_init_and_screenactive_poll(C)) {
- return false;
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "item");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ return undo_history_exec(C, op);
}
- UndoStack *undo_stack = CTX_wm_manager(C)->undo_stack;
- /* More than just original state entry. */
- return BLI_listbase_count_at_most(&undo_stack->steps, 2) > 1;
+
+ WM_menu_name_call(C, "TOPBAR_MT_undo_history", WM_OP_INVOKE_DEFAULT);
+ return OPERATOR_FINISHED;
}
void ED_OT_undo_history(wmOperatorType *ot)
@@ -865,7 +802,7 @@ void ED_OT_undo_history(wmOperatorType *ot)
/* api callbacks */
ot->invoke = undo_history_invoke;
ot->exec = undo_history_exec;
- ot->poll = undo_history_poll;
+ ot->poll = ed_undo_is_init_and_screenactive_poll;
RNA_def_int(ot->srna, "item", 0, 0, INT_MAX, "Item", "", 0, INT_MAX);
}
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 342afa847b4..64e1fa2f768 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -180,7 +180,7 @@ void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *i
if (node && is_image_texture_node(node)) {
node->id = &ima->id;
- ED_node_tag_update_nodetree(bmain, ma->nodetree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ma->nodetree);
}
}
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index 0a82c237256..6b33e17070a 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -48,6 +48,7 @@
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_object.h"
#include "BKE_scene.h"
@@ -415,7 +416,7 @@ Material *BlenderStrokeRenderer::GetStrokeShader(Main *bmain,
}
nodeSetActive(ntree, output_material);
- ntreeUpdateTree(bmain, ntree);
+ BKE_ntree_update_main_tree(bmain, ntree, NULL);
return ma;
}
diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc
index ae513bf88e9..4022794d53f 100644
--- a/source/blender/geometry/intern/realize_instances.cc
+++ b/source/blender/geometry/intern/realize_instances.cc
@@ -1167,7 +1167,7 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options,
const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index];
const void *attribute_fallback = task.attribute_fallbacks.array[attribute_index];
const std::optional<GSpan> src_span_opt = src_point_attributes.get_for_read(attribute_id);
- void *dst_buffer = MEM_malloc_arrayN(spline_size, cpp_type.size(), __func__);
+ void *dst_buffer = MEM_malloc_arrayN(spline_size, cpp_type.size(), "Curve Attribute");
if (src_span_opt.has_value()) {
const GSpan src_span = *src_span_opt;
cpp_type.copy_construct_n(src_span.data(), dst_buffer, spline_size);
diff --git a/source/blender/gpu/GPU_state.h b/source/blender/gpu/GPU_state.h
index fa70a8934db..7b69012dcbc 100644
--- a/source/blender/gpu/GPU_state.h
+++ b/source/blender/gpu/GPU_state.h
@@ -40,9 +40,11 @@ typedef enum eGPUBarrier {
GPU_BARRIER_SHADER_IMAGE_ACCESS = (1 << 0),
GPU_BARRIER_TEXTURE_FETCH = (1 << 1),
GPU_BARRIER_SHADER_STORAGE = (1 << 2),
+ GPU_BARRIER_VERTEX_ATTRIB_ARRAY = (1 << 3),
+ GPU_BARRIER_ELEMENT_ARRAY = (1 << 4),
} eGPUBarrier;
-ENUM_OPERATORS(eGPUBarrier, GPU_BARRIER_SHADER_STORAGE)
+ENUM_OPERATORS(eGPUBarrier, GPU_BARRIER_ELEMENT_ARRAY)
/**
* Defines the fixed pipeline blending equation.
diff --git a/source/blender/gpu/intern/gpu_shader_interface.cc b/source/blender/gpu/intern/gpu_shader_interface.cc
index 1648446d21b..937f49ccaec 100644
--- a/source/blender/gpu/intern/gpu_shader_interface.cc
+++ b/source/blender/gpu/intern/gpu_shader_interface.cc
@@ -74,6 +74,8 @@ void ShaderInterface::sort_inputs()
sort_input_list(MutableSpan<ShaderInput>(inputs_, attr_len_));
sort_input_list(MutableSpan<ShaderInput>(inputs_ + attr_len_, ubo_len_));
sort_input_list(MutableSpan<ShaderInput>(inputs_ + attr_len_ + ubo_len_, uniform_len_));
+ sort_input_list(
+ MutableSpan<ShaderInput>(inputs_ + attr_len_ + ubo_len_ + uniform_len_, ssbo_len_));
}
void ShaderInterface::debug_print()
diff --git a/source/blender/gpu/opengl/gl_state.hh b/source/blender/gpu/opengl/gl_state.hh
index 979644b41c9..f5c38a33628 100644
--- a/source/blender/gpu/opengl/gl_state.hh
+++ b/source/blender/gpu/opengl/gl_state.hh
@@ -130,6 +130,12 @@ static inline GLbitfield to_gl(eGPUBarrier barrier_bits)
if (barrier_bits & GPU_BARRIER_SHADER_STORAGE) {
barrier |= GL_SHADER_STORAGE_BARRIER_BIT;
}
+ if (barrier_bits & GPU_BARRIER_VERTEX_ATTRIB_ARRAY) {
+ barrier |= GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT;
+ }
+ if (barrier_bits & GPU_BARRIER_ELEMENT_ARRAY) {
+ barrier |= GL_ELEMENT_ARRAY_BARRIER_BIT;
+ }
return barrier;
}
diff --git a/source/blender/imbuf/intern/transform.cc b/source/blender/imbuf/intern/transform.cc
index 3e071a9e4d7..e1c451a8412 100644
--- a/source/blender/imbuf/intern/transform.cc
+++ b/source/blender/imbuf/intern/transform.cc
@@ -305,19 +305,22 @@ class Sampler {
void sample(const ImBuf *source, const float u, const float v, SampleType &r_sample)
{
- const float wrapped_u = uv_wrapper.modify_u(source, u);
- const float wrapped_v = uv_wrapper.modify_v(source, v);
-
if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<StorageType, float> &&
NumChannels == 4) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
bilinear_interpolation_color_fl(source, nullptr, &r_sample[0], wrapped_u, wrapped_v);
}
else if constexpr (Filter == IMB_FILTER_NEAREST &&
std::is_same_v<StorageType, unsigned char> && NumChannels == 4) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
nearest_interpolation_color_char(source, &r_sample[0], nullptr, wrapped_u, wrapped_v);
}
else if constexpr (Filter == IMB_FILTER_BILINEAR &&
std::is_same_v<StorageType, unsigned char> && NumChannels == 4) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
bilinear_interpolation_color_char(source, &r_sample[0], nullptr, wrapped_u, wrapped_v);
}
else if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<StorageType, float>) {
@@ -326,6 +329,8 @@ class Sampler {
source->rect_float, &r_sample[0], source->x, source->y, NumChannels, u, v, true, true);
}
else {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
BLI_bilinear_interpolation_fl(source->rect_float,
&r_sample[0],
source->x,
@@ -336,6 +341,8 @@ class Sampler {
}
}
else if constexpr (Filter == IMB_FILTER_NEAREST && std::is_same_v<StorageType, float>) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
sample_nearest_float(source, wrapped_u, wrapped_v, r_sample);
}
else {
diff --git a/source/blender/io/collada/Materials.cpp b/source/blender/io/collada/Materials.cpp
index 1f358accc4e..6e17172f642 100644
--- a/source/blender/io/collada/Materials.cpp
+++ b/source/blender/io/collada/Materials.cpp
@@ -16,6 +16,8 @@
#include "Materials.h"
+#include "BKE_node_tree_update.h"
+
MaterialNode::MaterialNode(bContext *C, Material *ma, KeyImageMap &key_image_map)
: mContext(C), material(ma), effect(nullptr), key_image_map(&key_image_map)
{
@@ -106,7 +108,7 @@ bNodeTree *MaterialNode::prepare_material_nodetree()
void MaterialNode::update_material_nodetree()
{
- ntreeUpdateTree(CTX_data_main(mContext), ntree);
+ BKE_ntree_update_main_tree(CTX_data_main(mContext), ntree, nullptr);
}
bNode *MaterialNode::add_node(int node_type, int locx, int locy, std::string label)
diff --git a/source/blender/io/usd/intern/usd_reader_material.cc b/source/blender/io/usd/intern/usd_reader_material.cc
index db0c5785a68..645dea42971 100644
--- a/source/blender/io/usd/intern/usd_reader_material.cc
+++ b/source/blender/io/usd/intern/usd_reader_material.cc
@@ -23,6 +23,7 @@
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BLI_math_vector.h"
#include "BLI_string.h"
@@ -339,7 +340,7 @@ void USDMaterialReader::import_usd_preview(Material *mtl,
nodeSetActive(ntree, output);
- ntreeUpdateTree(bmain_, ntree);
+ BKE_ntree_update_main_tree(bmain_, ntree, nullptr);
/* Optionally, set the material blend mode. */
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 6a478f9abb5..17b3fb302e6 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -802,6 +802,9 @@ typedef enum IDRecalcFlag {
*/
ID_RECALC_TAG_FOR_UNDO = (1 << 24),
+ /* The node tree has changed in a way that affects its output nodes. */
+ ID_RECALC_NTREE_OUTPUT = (1 << 25),
+
/***************************************************************************
* Pseudonyms, to have more semantic meaning in the actual code without
* using too much low-level and implementation specific tags. */
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index 77cb553c7c7..c053baf9f7e 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -74,7 +74,7 @@ struct MLoopTri_Store {
int len_alloc;
};
-/* Runtime data, not saved in files. */
+/** Runtime data, not saved in files. */
typedef struct Mesh_Runtime {
/* Evaluated mesh for objects which do not have effective modifiers.
* This mesh is used as a result of modifier stack evaluation.
@@ -359,13 +359,13 @@ typedef enum eMeshWrapperType {
/* ME_WRAPPER_TYPE_SUBD = 2, */ /* TODO */
} eMeshWrapperType;
-/* texflag */
+/** #Mesh.texflag */
enum {
ME_AUTOSPACE = 1,
ME_AUTOSPACE_EVALUATED = 2,
};
-/* me->editflag */
+/** #Mesh.editflag */
enum {
ME_EDIT_MIRROR_VERTEX_GROUPS = 1 << 0,
ME_EDIT_MIRROR_Y = 1 << 1, /* unused so far */
@@ -387,7 +387,7 @@ enum {
((_me)->editflag & ME_EDIT_PAINT_VERT_SEL) ? SCE_SELECT_VERTEX : \
0)
-/* me->flag */
+/** #Mesh.flag */
enum {
ME_FLAG_UNUSED_0 = 1 << 0, /* cleared */
ME_FLAG_UNUSED_1 = 1 << 1, /* cleared */
@@ -407,26 +407,26 @@ enum {
ME_REMESH_REPROJECT_SCULPT_FACE_SETS = 1 << 15,
};
-/* me->cd_flag */
+/** #Mesh.cd_flag */
enum {
ME_CDFLAG_VERT_BWEIGHT = 1 << 0,
ME_CDFLAG_EDGE_BWEIGHT = 1 << 1,
ME_CDFLAG_EDGE_CREASE = 1 << 2,
};
-/* me->remesh_mode */
+/** #Mesh.remesh_mode */
enum {
REMESH_VOXEL = 0,
REMESH_QUAD = 1,
};
-/* Subsurf Type */
+/** #SubsurfModifierData.subdivType */
enum {
ME_CC_SUBSURF = 0,
ME_SIMPLE_SUBSURF = 1,
};
-/* me->symmetry */
+/** #Mesh.symmetry */
typedef enum eMeshSymmetryType {
ME_SYMMETRY_X = 1 << 0,
ME_SYMMETRY_Y = 1 << 1,
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index f7a468264c3..85cc1361adf 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -121,28 +121,28 @@ typedef struct ModifierData {
int type, mode;
char _pad0[4];
short flag;
- /* An "expand" bit for each of the modifier's (sub)panels (uiPanelDataExpansion). */
+ /** An "expand" bit for each of the modifier's (sub)panels (#uiPanelDataExpansion). */
short ui_expand_flag;
/** MAX_NAME. */
char name[64];
char *error;
- /* Pointer to a ModifierData in the original domain. */
+ /** Pointer to a #ModifierData in the original domain. */
struct ModifierData *orig_modifier_data;
- /* Runtime field which contains unique identifier of the modifier. */
+ /** Runtime field which contains unique identifier of the modifier. */
SessionUUID session_uuid;
- /* Runtime field which contains runtime data which is specific to a modifier type. */
+ /** Runtime field which contains runtime data which is specific to a modifier type. */
void *runtime;
void *_pad1;
} ModifierData;
typedef enum {
- /* This modifier has been inserted in local override, and hence can be fully edited. */
+ /** This modifier has been inserted in local override, and hence can be fully edited. */
eModifierFlag_OverrideLibrary_Local = (1 << 0),
- /* This modifier does not own its caches, but instead shares them with another modifier. */
+ /** This modifier does not own its caches, but instead shares them with another modifier. */
eModifierFlag_SharedCaches = (1 << 1),
/**
* This modifier is the object's active modifier. Used for context in the node editor.
@@ -151,7 +151,9 @@ typedef enum {
eModifierFlag_Active = (1 << 2),
} ModifierFlag;
-/* not a real modifier */
+/**
+ * \note Not a real modifier.
+ */
typedef struct MappingInfoModifierData {
ModifierData modifier;
@@ -219,7 +221,7 @@ typedef struct LatticeModifierData {
void *_pad1;
} LatticeModifierData;
-/* Lattice modifier flags. */
+/** #LatticeModifierData.flag */
enum {
MOD_LATTICE_INVERT_VGROUP = (1 << 0),
};
@@ -237,12 +239,12 @@ typedef struct CurveModifierData {
void *_pad1;
} CurveModifierData;
-/* Curve modifier flags */
+/** #CurveModifierData.flag */
enum {
MOD_CURVE_INVERT_VGROUP = (1 << 0),
};
-/* CurveModifierData->defaxis */
+/** #CurveModifierData.defaxis */
enum {
MOD_CURVE_POSX = 1,
MOD_CURVE_POSY = 2,
@@ -264,7 +266,7 @@ typedef struct BuildModifierData {
int seed;
} BuildModifierData;
-/* Build Modifier -> flag */
+/** #BuildModifierData.flag */
enum {
/** order of vertices is randomized */
MOD_BUILD_FLAG_RANDOMIZE = (1 << 0),
@@ -272,7 +274,7 @@ enum {
MOD_BUILD_FLAG_REVERSE = (1 << 1),
};
-/* Mask Modifier */
+/** Mask Modifier. */
typedef struct MaskModifierData {
ModifierData modifier;
@@ -289,13 +291,13 @@ typedef struct MaskModifierData {
void *_pad1;
} MaskModifierData;
-/* Mask Modifier -> mode */
+/** #MaskModifierData.mode */
enum {
MOD_MASK_MODE_VGROUP = 0,
MOD_MASK_MODE_ARM = 1,
};
-/* Mask Modifier -> flag */
+/** #MaskModifierData.flag */
enum {
MOD_MASK_INV = (1 << 0),
MOD_MASK_SMOOTH = (1 << 1),
@@ -304,63 +306,68 @@ enum {
typedef struct ArrayModifierData {
ModifierData modifier;
- /* the object with which to cap the start of the array. */
+ /** The object with which to cap the start of the array. */
struct Object *start_cap;
- /* the object with which to cap the end of the array. */
+ /** The object with which to cap the end of the array. */
struct Object *end_cap;
- /* the curve object to use for MOD_ARR_FITCURVE. */
+ /** The curve object to use for #MOD_ARR_FITCURVE. */
struct Object *curve_ob;
- /* the object to use for object offset. */
+ /** The object to use for object offset. */
struct Object *offset_ob;
- /* a constant duplicate offset;
- * 1 means the duplicates are 1 unit apart
+ /**
+ * A constant duplicate offset;
+ * 1 means the duplicates are 1 unit apart.
*/
float offset[3];
- /* a scaled factor for duplicate offsets;
- * 1 means the duplicates are 1 object-width apart
+ /**
+ * A scaled factor for duplicate offsets;
+ * 1 means the duplicates are 1 object-width apart.
*/
float scale[3];
- /* the length over which to distribute the duplicates */
+ /** The length over which to distribute the duplicates. */
float length;
- /* the limit below which to merge vertices in adjacent duplicates */
+ /** The limit below which to merge vertices in adjacent duplicates. */
float merge_dist;
- /* determines how duplicate count is calculated; one of:
- * - MOD_ARR_FIXEDCOUNT -> fixed
- * - MOD_ARR_FITLENGTH -> calculated to fit a set length
- * - MOD_ARR_FITCURVE -> calculated to fit the length of a Curve object
+ /**
+ * Determines how duplicate count is calculated; one of:
+ * - #MOD_ARR_FIXEDCOUNT -> fixed.
+ * - #MOD_ARR_FITLENGTH -> calculated to fit a set length.
+ * - #MOD_ARR_FITCURVE -> calculated to fit the length of a Curve object.
*/
int fit_type;
- /* flags specifying how total offset is calculated; binary OR of:
- * - MOD_ARR_OFF_CONST -> total offset += offset
- * - MOD_ARR_OFF_RELATIVE -> total offset += relative * object width
- * - MOD_ARR_OFF_OBJ -> total offset += offset_ob's matrix
- * total offset is the sum of the individual enabled offsets
+ /**
+ * Flags specifying how total offset is calculated; binary OR of:
+ * - #MOD_ARR_OFF_CONST -> total offset += offset.
+ * - #MOD_ARR_OFF_RELATIVE -> total offset += relative * object width.
+ * - #MOD_ARR_OFF_OBJ -> total offset += offset_ob's matrix.
+ * Total offset is the sum of the individual enabled offsets.
*/
int offset_type;
- /* general flags:
- * MOD_ARR_MERGE -> merge vertices in adjacent duplicates
+ /**
+ * General flags:
+ * #MOD_ARR_MERGE -> merge vertices in adjacent duplicates.
*/
int flags;
- /* the number of duplicates to generate for MOD_ARR_FIXEDCOUNT */
+ /** The number of duplicates to generate for #MOD_ARR_FIXEDCOUNT. */
int count;
float uv_offset[2];
} ArrayModifierData;
-/* ArrayModifierData->fit_type */
+/** #ArrayModifierData.fit_type */
enum {
MOD_ARR_FIXEDCOUNT = 0,
MOD_ARR_FITLENGTH = 1,
MOD_ARR_FITCURVE = 2,
};
-/* ArrayModifierData->offset_type */
+/** #ArrayModifierData.offset_type */
enum {
MOD_ARR_OFF_CONST = (1 << 0),
MOD_ARR_OFF_RELATIVE = (1 << 1),
MOD_ARR_OFF_OBJ = (1 << 2),
};
-/* ArrayModifierData->flags */
+/** #ArrayModifierData.flags */
enum {
MOD_ARR_MERGE = (1 << 0),
MOD_ARR_MERGEFINAL = (1 << 1),
@@ -389,7 +396,7 @@ typedef struct MirrorModifierData {
void *_pad1;
} MirrorModifierData;
-/* MirrorModifierData->flag */
+/** #MirrorModifierData.flag */
enum {
MOD_MIR_CLIPPING = (1 << 0),
MOD_MIR_MIRROR_U = (1 << 1),
@@ -416,7 +423,7 @@ typedef struct EdgeSplitModifierData {
int flags;
} EdgeSplitModifierData;
-/* EdgeSplitModifierData->flags */
+/** #EdgeSplitModifierData.flags */
enum {
MOD_EDGESPLIT_FROMANGLE = (1 << 1),
MOD_EDGESPLIT_FROMFLAG = (1 << 2),
@@ -468,7 +475,7 @@ typedef struct BevelModifierData {
void *_pad2;
} BevelModifierData;
-/* BevelModifierData->flags and BevelModifierData->lim_flags */
+/** #BevelModifierData.flags and BevelModifierData.lim_flags */
enum {
#ifdef DNA_DEPRECATED_ALLOW
MOD_BEVEL_VERT_DEPRECATED = (1 << 1),
@@ -491,7 +498,7 @@ enum {
MOD_BEVEL_HARDEN_NORMALS = (1 << 15),
};
-/* BevelModifierData->val_flags (not used as flags any more) */
+/** #BevelModifierData.val_flags (not used as flags any more) */
enum {
MOD_BEVEL_AMT_OFFSET = 0,
MOD_BEVEL_AMT_WIDTH = 1,
@@ -500,19 +507,19 @@ enum {
MOD_BEVEL_AMT_ABSOLUTE = 4,
};
-/* BevelModifierData->profile_type */
+/** #BevelModifierData.profile_type */
enum {
MOD_BEVEL_PROFILE_SUPERELLIPSE = 0,
MOD_BEVEL_PROFILE_CUSTOM = 1,
};
-/* BevelModifierData->edge_flags */
+/** #BevelModifierData.edge_flags */
enum {
MOD_BEVEL_MARK_SEAM = (1 << 0),
MOD_BEVEL_MARK_SHARP = (1 << 1),
};
-/* BevelModifierData->face_str_mode */
+/** #BevelModifierData.face_str_mode */
enum {
MOD_BEVEL_FACE_STRENGTH_NONE = 0,
MOD_BEVEL_FACE_STRENGTH_NEW = 1,
@@ -520,20 +527,20 @@ enum {
MOD_BEVEL_FACE_STRENGTH_ALL = 3,
};
-/* BevelModifier->miter_inner and ->miter_outer */
+/** #BevelModifier.miter_inner & #BevelModifier.miter_outer */
enum {
MOD_BEVEL_MITER_SHARP = 0,
MOD_BEVEL_MITER_PATCH = 1,
MOD_BEVEL_MITER_ARC = 2,
};
-/* BevelModifier->vmesh_method */
+/** #BevelModifier.vmesh_method */
enum {
MOD_BEVEL_VMESH_ADJ = 0,
MOD_BEVEL_VMESH_CUTOFF = 1,
};
-/* BevelModifier->affect_type */
+/** #BevelModifier.affect_type */
enum {
MOD_BEVEL_AFFECT_VERTICES = 0,
MOD_BEVEL_AFFECT_EDGES = 1,
@@ -553,7 +560,7 @@ typedef struct FluidModifierData {
void *_pad1;
} FluidModifierData;
-/* Fluid modifier flags */
+/** #FluidModifierData.type */
enum {
MOD_FLUID_TYPE_DOMAIN = (1 << 0),
MOD_FLUID_TYPE_FLOW = (1 << 1),
@@ -563,7 +570,8 @@ enum {
typedef struct DisplaceModifierData {
ModifierData modifier;
- /* keep in sync with MappingInfoModifierData */
+ /* Keep in sync with #MappingInfoModifierData. */
+
struct Tex *texture;
struct Object *map_object;
char map_bone[64];
@@ -583,12 +591,12 @@ typedef struct DisplaceModifierData {
char _pad[6];
} DisplaceModifierData;
-/* DisplaceModifierData->flag */
+/** #DisplaceModifierData.flag */
enum {
MOD_DISP_INVERT_VGROUP = (1 << 0),
};
-/* DisplaceModifierData->direction */
+/** #DisplaceModifierData.direction */
enum {
MOD_DISP_DIR_X = 0,
MOD_DISP_DIR_Y = 1,
@@ -598,7 +606,7 @@ enum {
MOD_DISP_DIR_CLNOR = 5,
};
-/* DisplaceModifierData->texmapping */
+/** #DisplaceModifierData.texmapping */
enum {
MOD_DISP_MAP_LOCAL = 0,
MOD_DISP_MAP_GLOBAL = 1,
@@ -606,7 +614,7 @@ enum {
MOD_DISP_MAP_UV = 3,
};
-/* DisplaceModifierData->space */
+/** #DisplaceModifierData.space */
enum {
MOD_DISP_SPACE_LOCAL = 0,
MOD_DISP_SPACE_GLOBAL = 1,
@@ -614,9 +622,10 @@ enum {
typedef struct UVProjectModifierData {
ModifierData modifier;
-
- /* the objects which do the projecting */
- /** MOD_UVPROJECT_MAXPROJECTORS. */
+ /**
+ * The objects which do the projecting.
+ * \note 10=MOD_UVPROJECT_MAXPROJECTORS.
+ */
struct Object *projectors[10];
char _pad2[4];
int num_projectors;
@@ -649,7 +658,7 @@ typedef struct DecimateModifierData {
float defgrp_factor;
short flag, mode;
- /* runtime only */
+ /** runtime only. */
int face_count;
} DecimateModifierData;
@@ -678,7 +687,7 @@ typedef struct SmoothModifierData {
} SmoothModifierData;
-/* Smooth modifier flags */
+/** #SmoothModifierData.flag */
enum {
MOD_SMOOTH_INVERT_VGROUP = (1 << 0),
MOD_SMOOTH_X = (1 << 1),
@@ -695,11 +704,13 @@ typedef struct CastModifierData {
float size;
/** MAX_VGROUP_NAME. */
char defgrp_name[64];
- short flag, type;
+ short flag;
+ /** Cast modifier projection type. */
+ short type;
void *_pad1;
} CastModifierData;
-/* Cast modifier flags */
+/** #CastModifierData.flag */
enum {
/* And what bout (1 << 0) flag? ;) */
MOD_CAST_INVERT_VGROUP = (1 << 0),
@@ -710,7 +721,7 @@ enum {
MOD_CAST_SIZE_FROM_RADIUS = (1 << 5),
};
-/* Cast modifier projection types */
+/** #CastModifierData.type */
enum {
MOD_CAST_TYPE_SPHERE = 0,
MOD_CAST_TYPE_CYLINDER = 1,
@@ -720,7 +731,8 @@ enum {
typedef struct WaveModifierData {
ModifierData modifier;
- /* keep in sync with MappingInfoModifierData */
+ /* Keep in sync with #MappingInfoModifierData. */
+
struct Tex *texture;
struct Object *map_object;
char map_bone[64];
@@ -728,7 +740,7 @@ typedef struct WaveModifierData {
char uvlayer_name[64];
int uvlayer_tmp;
int texmapping;
- /* end MappingInfoModifierData */
+ /* End MappingInfoModifierData. */
struct Object *objectcenter;
/** MAX_VGROUP_NAME. */
@@ -745,7 +757,7 @@ typedef struct WaveModifierData {
void *_pad2;
} WaveModifierData;
-/* WaveModifierData.flag */
+/** #WaveModifierData.flag */
enum {
MOD_WAVE_INVERT_VGROUP = (1 << 0),
MOD_WAVE_X = (1 << 1),
@@ -775,7 +787,7 @@ enum {
MOD_HOOK_INVERT_VGROUP = (1 << 1),
};
-/* same as WarpModifierFalloff */
+/** \note same as #WarpModifierFalloff */
typedef enum {
eHook_Falloff_None = 0,
eHook_Falloff_Curve = 1,
@@ -832,15 +844,17 @@ typedef struct ClothModifierData {
/** Definition is in DNA_cloth_types.h. */
struct ClothCollSettings *coll_parms;
- /* PointCache can be shared with other instances of ClothModifierData.
- * Inspect (modifier.flag & eModifierFlag_SharedCaches) to find out. */
+ /**
+ * PointCache can be shared with other instances of #ClothModifierData.
+ * Inspect `modifier.flag & eModifierFlag_SharedCaches` to find out.
+ */
/** Definition is in DNA_object_force_types.h. */
struct PointCache *point_cache;
struct ListBase ptcaches;
- /* XXX nasty hack, remove once hair can be separated from cloth modifier data */
+ /** XXX: nasty hack, remove once hair can be separated from cloth modifier data. */
struct ClothHairData *hairdata;
- /* grid geometry values of hair continuum */
+ /** Grid geometry values of hair continuum. */
float hair_grid_min[3];
float hair_grid_max[3];
int hair_grid_res[3];
@@ -907,20 +921,20 @@ typedef struct BooleanModifierData {
char bm_flag;
} BooleanModifierData;
-/* BooleanModifierData->operation */
+/** #BooleanModifierData.operation */
typedef enum {
eBooleanModifierOp_Intersect = 0,
eBooleanModifierOp_Union = 1,
eBooleanModifierOp_Difference = 2,
} BooleanModifierOp;
-/* BooleanModifierData->solver */
+/** #BooleanModifierData.solver */
typedef enum {
eBooleanModifierSolver_Fast = 0,
eBooleanModifierSolver_Exact = 1,
} BooleanModifierSolver;
-/* BooleanModifierData->flag */
+/** #BooleanModifierData.flag */
enum {
eBooleanModifierFlag_Self = (1 << 0),
eBooleanModifierFlag_Object = (1 << 1),
@@ -928,7 +942,7 @@ enum {
eBooleanModifierFlag_HoleTolerant = (1 << 3),
};
-/* bm_flag only used when G_DEBUG. */
+/** #BooleanModifierData.bm_flag (only used when #G_DEBUG is set). */
enum {
eBooleanModifierBMeshFlag_BMesh_Separate = (1 << 0),
eBooleanModifierBMeshFlag_BMesh_NoDissolve = (1 << 1),
@@ -1102,7 +1116,7 @@ typedef enum {
eMultiresModifierFlag_UseSculptBaseMesh = (1 << 4),
} MultiresModifierFlag;
-/* DEPRECATED, only used for versioning. */
+/** DEPRECATED: only used for versioning. */
typedef struct FluidsimModifierData {
ModifierData modifier;
@@ -1111,7 +1125,7 @@ typedef struct FluidsimModifierData {
void *_pad1;
} FluidsimModifierData;
-/* DEPRECATED, only used for versioning. */
+/** DEPRECATED: only used for versioning. */
typedef struct SmokeModifierData {
ModifierData modifier;
@@ -1150,7 +1164,7 @@ typedef struct ShrinkwrapModifierData {
char _pad[2];
} ShrinkwrapModifierData;
-/* Shrinkwrap->shrinkType */
+/** #ShrinkwrapModifierData.shrinkType */
enum {
MOD_SHRINKWRAP_NEAREST_SURFACE = 0,
MOD_SHRINKWRAP_PROJECT = 1,
@@ -1158,7 +1172,7 @@ enum {
MOD_SHRINKWRAP_TARGET_PROJECT = 3,
};
-/* Shrinkwrap->shrinkMode */
+/** #ShrinkwrapModifierData.shrinkMode */
enum {
/** Move vertex to the surface of the target object (keepDist towards original position) */
MOD_SHRINKWRAP_ON_SURFACE = 0,
@@ -1172,7 +1186,7 @@ enum {
MOD_SHRINKWRAP_ABOVE_SURFACE = 4,
};
-/* Shrinkwrap->shrinkOpts */
+/** #ShrinkwrapModifierData.shrinkOpts */
enum {
/** allow shrinkwrap to move the vertex in the positive direction of axis */
MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR = (1 << 0),
@@ -1196,7 +1210,7 @@ enum {
#define MOD_SHRINKWRAP_CULL_TARGET_MASK \
(MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE | MOD_SHRINKWRAP_CULL_TARGET_BACKFACE)
-/* Shrinkwrap->projAxis */
+/** #ShrinkwrapModifierData.projAxis */
enum {
/** projection over normal is used if no axis is selected */
MOD_SHRINKWRAP_PROJECT_OVER_NORMAL = 0,
@@ -1228,7 +1242,7 @@ typedef struct SimpleDeformModifierData {
void *_pad1;
} SimpleDeformModifierData;
-/* SimpleDeform->flag */
+/** #SimpleDeformModifierData.flag */
enum {
MOD_SIMPLEDEFORM_FLAG_INVERT_VGROUP = (1 << 0),
};
@@ -1434,7 +1448,9 @@ enum {
typedef struct WarpModifierData {
ModifierData modifier;
- /* keep in sync with MappingInfoModifierData */
+
+ /* Keep in sync with #MappingInfoModifierData. */
+
struct Tex *texture;
struct Object *map_object;
char map_bone[64];
@@ -1442,7 +1458,7 @@ typedef struct WarpModifierData {
char uvlayer_name[64];
int uvlayer_tmp;
int texmapping;
- /* end MappingInfoModifierData */
+ /* End #MappingInfoModifierData. */
struct Object *object_from;
struct Object *object_to;
@@ -1462,12 +1478,13 @@ typedef struct WarpModifierData {
void *_pad1;
} WarpModifierData;
-/* WarpModifierData->flag */
+/** #WarpModifierData.flag */
enum {
MOD_WARP_VOLUME_PRESERVE = (1 << 0),
MOD_WARP_INVERT_VGROUP = (1 << 1),
};
+/** \note same as #HookModifierFalloff. */
typedef enum {
eWarp_Falloff_None = 0,
eWarp_Falloff_Curve = 1,
@@ -1508,7 +1525,7 @@ typedef struct WeightVGEditModifierData {
char mask_defgrp_name[64];
/* Texture masking. */
- /** Which channel to use as weightf. */
+ /** Which channel to use as weight/mask. */
int mask_tex_use_channel;
/** The texture. */
struct Tex *mask_texture;
@@ -1526,7 +1543,7 @@ typedef struct WeightVGEditModifierData {
void *_pad1;
} WeightVGEditModifierData;
-/* WeightVGEdit flags. */
+/** #WeightVGEdit.edit_flags */
enum {
MOD_WVG_EDIT_WEIGHTS_NORMALIZE = (1 << 0),
MOD_WVG_INVERT_FALLOFF = (1 << 1),
@@ -1581,7 +1598,7 @@ typedef struct WeightVGMixModifierData {
char _pad1[3];
} WeightVGMixModifierData;
-/* How second vgroup's weights affect first ones. */
+/** #WeightVGMixModifierData.mix_mode (how second vgroup's weights affect first ones). */
enum {
/** Second weights replace weights. */
MOD_WVG_MIX_SET = 1,
@@ -1599,7 +1616,7 @@ enum {
MOD_WVG_MIX_AVG = 7,
};
-/* What vertices to affect. */
+/** #WeightVGMixModifierData.mix_set (what vertices to affect). */
enum {
/** Affect all vertices. */
MOD_WVG_SET_ALL = 1,
@@ -1613,7 +1630,7 @@ enum {
MOD_WVG_SET_AND = 5,
};
-/* WeightVGMix->flag */
+/** #WeightVGMixModifierData.flag */
enum {
MOD_WVG_MIX_INVERT_VGROUP_MASK = (1 << 0),
MOD_WVG_MIX_WEIGHTS_NORMALIZE = (1 << 1),
@@ -1631,8 +1648,9 @@ typedef struct WeightVGProximityModifierData {
/** The custom mapping curve. */
struct CurveMapping *cmap_curve;
- /* Proximity modes. */
+ /** Modes of proximity weighting. */
int proximity_mode;
+ /** Options for proximity weighting. */
int proximity_flags;
/* Target object from which to calculate vertices distances. */
@@ -1662,20 +1680,21 @@ typedef struct WeightVGProximityModifierData {
float min_dist, max_dist;
/* Put here to avoid breaking existing struct... */
- /** Using MOD_WVG_MAPPING_* enums. */
+ /**
+ * Mapping modes (using MOD_WVG_MAPPING_* enums). */
short falloff_type;
/* Padding... */
char _pad0[2];
} WeightVGProximityModifierData;
-/* Modes of proximity weighting. */
+/** #WeightVGProximityModifierData.proximity_mode */
enum {
MOD_WVG_PROXIMITY_OBJECT = 1, /* source vertex to other location */
MOD_WVG_PROXIMITY_GEOMETRY = 2, /* source vertex to other geometry */
};
-/* Flags options for proximity weighting. */
+/** #WeightVGProximityModifierData.proximity_flags */
enum {
/* Use nearest vertices of target obj, in MOD_WVG_PROXIMITY_GEOMETRY mode. */
MOD_WVG_PROXIMITY_GEOM_VERTS = (1 << 0),
@@ -1689,7 +1708,8 @@ enum {
};
/* Defines common to all WeightVG modifiers. */
-/* Mapping modes. */
+
+/** #WeightVGProximityModifierData.falloff_type */
enum {
MOD_WVG_MAPPING_NONE = 0,
MOD_WVG_MAPPING_CURVE = 1,
@@ -1703,7 +1723,7 @@ enum {
MOD_WVG_MAPPING_STEP = 9, /* Median Step. */
};
-/* Tex channel to be used as mask. */
+/** #WeightVGProximityModifierData.mask_tex_use_channel */
enum {
MOD_WVG_MASK_TEX_USE_INT = 1,
MOD_WVG_MASK_TEX_USE_RED = 2,
@@ -1725,13 +1745,13 @@ typedef struct DynamicPaintModifierData {
char _pad[4];
} DynamicPaintModifierData;
-/* Dynamic paint modifier flags */
+/** #DynamicPaintModifierData.type */
enum {
MOD_DYNAMICPAINT_TYPE_CANVAS = (1 << 0),
MOD_DYNAMICPAINT_TYPE_BRUSH = (1 << 1),
};
-/* Remesh modifier */
+/** Remesh modifier. */
typedef enum eRemeshModifierFlags {
MOD_REMESH_FLOOD_FILL = (1 << 0),
MOD_REMESH_SMOOTH_SHADING = (1 << 1),
@@ -1770,7 +1790,7 @@ typedef struct RemeshModifierData {
float adaptivity;
} RemeshModifierData;
-/* Skin modifier */
+/** Skin modifier. */
typedef struct SkinModifierData {
ModifierData modifier;
@@ -1783,19 +1803,19 @@ typedef struct SkinModifierData {
char _pad[2];
} SkinModifierData;
-/* SkinModifierData.symmetry_axes */
+/** #SkinModifierData.symmetry_axes */
enum {
MOD_SKIN_SYMM_X = (1 << 0),
MOD_SKIN_SYMM_Y = (1 << 1),
MOD_SKIN_SYMM_Z = (1 << 2),
};
-/* SkinModifierData.flag */
+/** #SkinModifierData.flag */
enum {
MOD_SKIN_SMOOTH_SHADING = 1,
};
-/* Triangulate modifier */
+/** Triangulate modifier. */
typedef struct TriangulateModifierData {
ModifierData modifier;
@@ -1805,7 +1825,7 @@ typedef struct TriangulateModifierData {
int min_vertices;
} TriangulateModifierData;
-/* TriangulateModifierData.flag */
+/** #TriangulateModifierData.flag */
enum {
#ifdef DNA_DEPRECATED_ALLOW
MOD_TRIANGULATE_BEAUTY = (1 << 0), /* deprecated */
@@ -1813,13 +1833,13 @@ enum {
MOD_TRIANGULATE_KEEP_CUSTOMLOOP_NORMALS = 1 << 1,
};
-/* Triangulate methods - NGons */
+/** #TriangulateModifierData.ngon_method triangulate method (N-gons). */
enum {
MOD_TRIANGULATE_NGON_BEAUTY = 0,
MOD_TRIANGULATE_NGON_EARCLIP = 1,
};
-/* Triangulate methods - Quads */
+/** #TriangulateModifierData.quad_method triangulate method (quads). */
enum {
MOD_TRIANGULATE_QUAD_BEAUTY = 0,
MOD_TRIANGULATE_QUAD_FIXED = 1,
@@ -1837,7 +1857,7 @@ typedef struct LaplacianSmoothModifierData {
short flag, repeat;
} LaplacianSmoothModifierData;
-/* Smooth modifier flags */
+/** #LaplacianSmoothModifierData.flag */
enum {
MOD_LAPLACIANSMOOTH_X = (1 << 1),
MOD_LAPLACIANSMOOTH_Y = (1 << 2),
@@ -1892,7 +1912,7 @@ enum {
MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND = 1,
};
-/* Corrective Smooth modifier flags */
+/** #CorrectiveSmoothModifierData.flag */
enum {
MOD_CORRECTIVESMOOTH_INVERT_VGROUP = (1 << 0),
MOD_CORRECTIVESMOOTH_ONLY_SMOOTH = (1 << 1),
@@ -1926,12 +1946,12 @@ typedef struct UVWarpModifierData {
char uvlayer_name[64];
} UVWarpModifierData;
-/* UVWarp modifier flags */
+/** #UVWarpModifierData.flag */
enum {
MOD_UVWARP_INVERT_VGROUP = 1 << 0,
};
-/* cache modifier */
+/** Mesh cache modifier. */
typedef struct MeshCacheModifierData {
ModifierData modifier;
@@ -1967,7 +1987,7 @@ typedef struct MeshCacheModifierData {
char filepath[1024];
} MeshCacheModifierData;
-/* MeshCache modifier flags. */
+/** #MeshCacheModifierData.flag */
enum {
MOD_MESHCACHE_INVERT_VERTEX_GROUP = 1 << 0,
};
@@ -2012,13 +2032,15 @@ typedef struct LaplacianDeformModifierData {
} LaplacianDeformModifierData;
-/* Laplacian Deform modifier flags */
+/** #LaplacianDeformModifierData.flag */
enum {
MOD_LAPLACIANDEFORM_BIND = 1 << 0,
MOD_LAPLACIANDEFORM_INVERT_VGROUP = 1 << 1,
};
-/* many of these options match 'solidify' */
+/**
+ * \note many of these options match 'solidify'.
+ */
typedef struct WireframeModifierData {
ModifierData modifier;
/** MAX_VGROUP_NAME. */
@@ -2053,13 +2075,13 @@ typedef struct WeldModifierData {
char _pad[2];
} WeldModifierData;
-/* WeldModifierData->flag */
+/** #WeldModifierData.flag */
enum {
MOD_WELD_INVERT_VGROUP = (1 << 0),
MOD_WELD_LOOSE_EDGES = (1 << 1),
};
-/* #WeldModifierData.mode */
+/** #WeldModifierData.mode */
enum {
MOD_WELD_MODE_ALL = 0,
MOD_WELD_MODE_CONNECTED = 1,
@@ -2100,7 +2122,7 @@ typedef struct DataTransferModifierData {
void *_pad2;
} DataTransferModifierData;
-/* DataTransferModifierData.flags */
+/** #DataTransferModifierData.flags */
enum {
MOD_DATATRANSFER_OBSRC_TRANSFORM = 1 << 0,
MOD_DATATRANSFER_MAP_MAXDIST = 1 << 1,
@@ -2113,7 +2135,7 @@ enum {
MOD_DATATRANSFER_USE_POLY = 1u << 31,
};
-/* Set Split Normals modifier */
+/** Set Split Normals modifier. */
typedef struct NormalEditModifierData {
ModifierData modifier;
/** MAX_VGROUP_NAME. */
@@ -2131,20 +2153,20 @@ typedef struct NormalEditModifierData {
void *_pad1;
} NormalEditModifierData;
-/* NormalEditModifierData.mode */
+/** #NormalEditModifierData.mode */
enum {
MOD_NORMALEDIT_MODE_RADIAL = 0,
MOD_NORMALEDIT_MODE_DIRECTIONAL = 1,
};
-/* NormalEditModifierData.flags */
+/** #NormalEditModifierData.flags */
enum {
MOD_NORMALEDIT_INVERT_VGROUP = (1 << 0),
MOD_NORMALEDIT_USE_DIRECTION_PARALLEL = (1 << 1),
MOD_NORMALEDIT_NO_POLYNORS_FIX = (1 << 2),
};
-/* NormalEditModifierData.mix_mode */
+/** #NormalEditModifierData.mix_mode */
enum {
MOD_NORMALEDIT_MIX_COPY = 0,
MOD_NORMALEDIT_MIX_ADD = 1,
@@ -2169,7 +2191,7 @@ typedef struct MeshSeqCacheModifierData {
char reader_object_path[1024];
} MeshSeqCacheModifierData;
-/* MeshSeqCacheModifierData.read_flag */
+/** #MeshSeqCacheModifierData.read_flag */
enum {
MOD_MESHSEQ_READ_VERT = (1 << 0),
MOD_MESHSEQ_READ_POLY = (1 << 1),
@@ -2214,7 +2236,7 @@ typedef struct SurfaceDeformModifierData {
void *_pad1;
} SurfaceDeformModifierData;
-/* Surface Deform modifier flags */
+/** Surface Deform modifier flags. */
enum {
/* This indicates "do bind on next modifier evaluation" as well as "is bound". */
MOD_SDEF_BIND = (1 << 0),
@@ -2223,7 +2245,7 @@ enum {
MOD_SDEF_SPARSE_BIND = (1 << 2),
};
-/* Surface Deform vertex bind modes */
+/** Surface Deform vertex bind modes. */
enum {
MOD_SDEF_MODE_LOOPTRI = 0,
MOD_SDEF_MODE_NGON = 1,
@@ -2243,14 +2265,14 @@ typedef struct WeightedNormalModifierData {
/* Name/id of the generic PROP_INT cdlayer storing face weights. */
#define MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID "__mod_weightednormals_faceweight"
-/* WeightedNormalModifierData.mode */
+/** #WeightedNormalModifierData.mode */
enum {
MOD_WEIGHTEDNORMAL_MODE_FACE = 0,
MOD_WEIGHTEDNORMAL_MODE_ANGLE = 1,
MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE = 2,
};
-/* WeightedNormalModifierData.flag */
+/** #WeightedNormalModifierData.flag */
enum {
MOD_WEIGHTEDNORMAL_KEEP_SHARP = (1 << 0),
MOD_WEIGHTEDNORMAL_INVERT_VGROUP = (1 << 1),
@@ -2270,8 +2292,10 @@ typedef struct NodesModifierData {
struct bNodeTree *node_group;
struct NodesModifierSettings settings;
- /* Contains logged information from the last evaluation. This can be used to help the user to
- * debug a node tree. */
+ /**
+ * Contains logged information from the last evaluation.
+ * This can be used to help the user to debug a node tree.
+ */
void *runtime_eval_log;
void *_pad1;
} NodesModifierData;
@@ -2304,7 +2328,7 @@ typedef struct MeshToVolumeModifierData {
void *_pad3;
} MeshToVolumeModifierData;
-/* MeshToVolumeModifierData->resolution_mode */
+/** #MeshToVolumeModifierData.resolution_mode */
typedef enum MeshToVolumeModifierResolutionMode {
MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT = 0,
MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE = 1,
@@ -2322,7 +2346,7 @@ typedef struct VolumeDisplaceModifierData {
float texture_sample_radius;
} VolumeDisplaceModifierData;
-/* VolumeDisplaceModifierData->texture_map_mode */
+/** #VolumeDisplaceModifierData.texture_map_mode */
enum {
MOD_VOLUME_DISPLACE_MAP_LOCAL = 0,
MOD_VOLUME_DISPLACE_MAP_GLOBAL = 1,
diff --git a/source/blender/makesdna/DNA_movieclip_types.h b/source/blender/makesdna/DNA_movieclip_types.h
index 8e01a9e1f1f..08064e6242b 100644
--- a/source/blender/makesdna/DNA_movieclip_types.h
+++ b/source/blender/makesdna/DNA_movieclip_types.h
@@ -160,7 +160,7 @@ typedef struct MovieClipScopes {
float slide_scale[2];
} MovieClipScopes;
-/* MovieClipProxy->build_size_flag */
+/** #MovieClipProxy.build_size_flag */
enum {
MCLIP_PROXY_SIZE_25 = (1 << 0),
MCLIP_PROXY_SIZE_50 = (1 << 1),
@@ -172,13 +172,13 @@ enum {
MCLIP_PROXY_UNDISTORTED_SIZE_100 = (1 << 7),
};
-/* MovieClip->source */
+/** #MovieClip.source */
enum {
MCLIP_SRC_SEQUENCE = 1,
MCLIP_SRC_MOVIE = 2,
};
-/* MovieClip->flag */
+/** #MovieClip.flag */
enum {
MCLIP_USE_PROXY = (1 << 0),
MCLIP_USE_PROXY_CUSTOM_DIR = (1 << 1),
@@ -188,7 +188,7 @@ enum {
MCLIP_TIMECODE_FLAGS = (MCLIP_USE_PROXY | MCLIP_USE_PROXY_CUSTOM_DIR),
};
-/* MovieClip->render_size */
+/** #MovieClip.render_size */
enum {
MCLIP_PROXY_RENDER_SIZE_FULL = 0,
MCLIP_PROXY_RENDER_SIZE_25 = 1,
@@ -197,7 +197,7 @@ enum {
MCLIP_PROXY_RENDER_SIZE_100 = 4,
};
-/* MovieClip->render_flag */
+/** #MovieClip.render_flag */
enum {
MCLIP_PROXY_RENDER_UNDISTORT = 1,
/** Use original, if proxy is not found. */
diff --git a/source/blender/makesdna/DNA_nla_types.h b/source/blender/makesdna/DNA_nla_types.h
index 7808dd68384..82edc0e1816 100644
--- a/source/blender/makesdna/DNA_nla_types.h
+++ b/source/blender/makesdna/DNA_nla_types.h
@@ -33,7 +33,7 @@ struct Ipo;
struct Object;
struct bAction;
-/* simple uniform modifier structure, assumed it can hold all type info */
+/** Simple uniform modifier structure, assumed it can hold all type info. */
typedef struct bActionModifier {
struct bActionModifier *next, *prev;
short type, flag;
@@ -95,7 +95,7 @@ typedef struct bActionStrip {
#define ACTSTRIPMODE_BLEND 0
#define ACTSTRIPMODE_ADD 1
-/* strip->flag */
+/** #bActionStrip.flag */
typedef enum eActStrip_Flag {
ACTSTRIP_SELECT = (1 << 0),
ACTSTRIP_USESTRIDE = (1 << 1),
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index dc5acb9d5b2..5d51d8eb606 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -159,7 +159,7 @@ typedef struct bNodeSocket {
* restores pointer from matching own_index. */
struct bNodeSocket *groupsock DNA_DEPRECATED;
- /** A link pointer, set in ntreeUpdateTree. */
+ /** A link pointer, set in #BKE_ntree_update_main. */
struct bNodeLink *link;
/* XXX deprecated, socket input values are stored in default_value now.
@@ -172,9 +172,13 @@ typedef struct bNodeSocket {
* data. It has to be updated when the node declaration changes.
*/
const SocketDeclarationHandle *declaration;
+
+ /** #eNodeTreeChangedFlag. */
+ uint32_t changed_flag;
+ char _pad[4];
} bNodeSocket;
-/* sock->type */
+/** #bNodeSocket.type & #bNodeSocketType.type */
typedef enum eNodeSocketDatatype {
SOCK_CUSTOM = -1, /* socket has no integer type */
SOCK_FLOAT = 0,
@@ -193,7 +197,7 @@ typedef enum eNodeSocketDatatype {
SOCK_MATERIAL = 13,
} eNodeSocketDatatype;
-/* Socket shape. */
+/** Socket shape. */
typedef enum eNodeSocketDisplayShape {
SOCK_DISPLAY_SHAPE_CIRCLE = 0,
SOCK_DISPLAY_SHAPE_SQUARE = 1,
@@ -203,13 +207,13 @@ typedef enum eNodeSocketDisplayShape {
SOCK_DISPLAY_SHAPE_DIAMOND_DOT = 5,
} eNodeSocketDisplayShape;
-/* Socket side (input/output). */
+/** Socket side (input/output). */
typedef enum eNodeSocketInOut {
SOCK_IN = 1 << 0,
SOCK_OUT = 1 << 1,
} eNodeSocketInOut;
-/* #bNodeSocket.flag, first bit is selection. */
+/** #bNodeSocket.flag, first bit is selection. */
typedef enum eNodeSocketFlag {
/** Hidden is user defined, to hide unused sockets. */
SOCK_HIDDEN = (1 << 1),
@@ -239,7 +243,7 @@ typedef enum eNodeSocketFlag {
SOCK_HIDE_LABEL = (1 << 12),
} eNodeSocketFlag;
-/* TODO: Limit data in bNode to what we want to see saved. */
+/** TODO: Limit data in #bNode to what we want to see saved. */
typedef struct bNode {
struct bNode *next, *prev, *new_node;
@@ -260,8 +264,9 @@ typedef struct bNode {
/** Used as a boolean for execution. */
uint8_t need_exec;
-
- char _pad[1];
+ char _pad2[5];
+ /** #eNodeTreeChangedFlag. */
+ uint32_t changed_flag;
/** Custom user-defined color. */
float color[3];
@@ -400,10 +405,6 @@ typedef struct bNode {
#define __NODE_ACTIVE_PREVIEW (1 << 18) /* deprecated */
/* node->update */
-/* XXX NODE_UPDATE is a generic update flag. More fine-grained updates
- * might be used in the future, but currently all work the same way.
- */
-#define NODE_UPDATE 0xFFFF /* generic update flag (includes all others) */
#define NODE_UPDATE_ID 1 /* associated id data block has changed */
#define NODE_UPDATE_OPERATOR 2 /* node update triggered from update operator */
@@ -511,8 +512,12 @@ typedef struct bNodeTree {
*/
int cur_index;
int flag;
- /** Update flags. */
- int update;
+ /**
+ * Keeps track of what changed in the node tree until the next update.
+ * Should not be changed directly, instead use the functions in `BKE_node_tree_update.h`.
+ * #eNodeTreeChangedFlag.
+ */
+ uint32_t changed_flag;
/** Flag to prevent re-entrant update calls. */
short is_updating;
/** Generic temporary flag for recursion check (DFS/BFS). */
@@ -546,7 +551,11 @@ typedef struct bNodeTree {
* in case multiple different editors are used and make context ambiguous.
*/
bNodeInstanceKey active_viewer_key;
- char _pad[4];
+ /**
+ * A hash of the topology of the node tree leading up to the outputs. This is used to determine
+ * of the node tree changed in a way that requires updating geometry nodes or shaders.
+ */
+ uint32_t output_topology_hash;
/** Execution data.
*
@@ -571,7 +580,7 @@ typedef struct bNodeTree {
struct PreviewImage *preview;
} bNodeTree;
-/* ntree->type, index */
+/** #NodeTree.type, index */
#define NTREE_UNDEFINED -2 /* Represents #NodeTreeTypeUndefined type. */
#define NTREE_CUSTOM -1 /* for dynamically registered custom types */
@@ -580,10 +589,10 @@ typedef struct bNodeTree {
#define NTREE_TEXTURE 2
#define NTREE_GEOMETRY 3
-/* ntree->init, flag */
+/** #NodeTree.init, flag */
#define NTREE_TYPE_INIT 1
-/* ntree->flag */
+/** #NodeTree.flag */
#define NTREE_DS_EXPAND (1 << 0) /* for animation editors */
#define NTREE_COM_OPENCL (1 << 1) /* use opencl */
#define NTREE_TWO_PASS (1 << 2) /* two pass */
@@ -594,20 +603,6 @@ typedef struct bNodeTree {
/* tree is localized copy, free when deleting node groups */
/* #define NTREE_IS_LOCALIZED (1 << 5) */
-/* ntree->update */
-typedef enum eNodeTreeUpdate {
- NTREE_UPDATE = 0xFFFF, /* generic update flag (includes all others) */
- NTREE_UPDATE_LINKS = (1 << 0), /* links have been added or removed */
- NTREE_UPDATE_NODES = (1 << 1), /* nodes or sockets have been added or removed */
- NTREE_UPDATE_GROUP_IN = (1 << 4), /* group inputs have changed */
- NTREE_UPDATE_GROUP_OUT = (1 << 5), /* group outputs have changed */
- /* The field interface has changed. So e.g. an output that was always a field before is not
- * anymore. This implies that the field type inferencing has to be done again. */
- NTREE_UPDATE_FIELD_INFERENCING = (1 << 6),
- /* group has changed (generic flag including all other group flags) */
- NTREE_UPDATE_GROUP = (NTREE_UPDATE_GROUP_IN | NTREE_UPDATE_GROUP_OUT),
-} eNodeTreeUpdate;
-
/* tree->execution_mode */
typedef enum eNodeTreeExecutionMode {
NTREE_EXECUTION_MODE_TILED = 0,
@@ -674,7 +669,8 @@ typedef struct bNodeSocketValueMaterial {
struct Material *value;
} bNodeSocketValueMaterial;
-/* Data structs, for node->storage. */
+/* Data structs, for `node->storage`. */
+
enum {
CMP_NODE_MASKTYPE_ADD = 0,
CMP_NODE_MASKTYPE_SUBTRACT = 1,
@@ -713,7 +709,7 @@ typedef struct NodeFrame {
short label_size;
} NodeFrame;
-/* This one has been replaced with ImageUser, keep it for do_versions(). */
+/** \note This one has been replaced with #ImageUser, keep it for do_versions(). */
typedef struct NodeImageAnim {
int frames DNA_DEPRECATED;
int sfra DNA_DEPRECATED;
@@ -767,7 +763,7 @@ typedef struct NodeEllipseMask {
char _pad[4];
} NodeEllipseMask;
-/* Layer info for image node outputs. */
+/** Layer info for image node outputs. */
typedef struct NodeImageLayer {
/* index in the Image->layers->passes lists */
int pass_index DNA_DEPRECATED;
@@ -805,7 +801,7 @@ typedef struct NodeAntiAliasingData {
float corner_rounding;
} NodeAntiAliasingData;
-/* NOTE: Only for do-version code. */
+/** \note Only for do-version code. */
typedef struct NodeHueSat {
float hue, sat, val;
} NodeHueSat;
@@ -817,7 +813,9 @@ typedef struct NodeImageFile {
int sfra, efra;
} NodeImageFile;
-/* XXX first struct fields should match NodeImageFile to ensure forward compatibility */
+/**
+ * XXX: first struct fields should match #NodeImageFile to ensure forward compatibility.
+ */
typedef struct NodeImageMultiFile {
/** 1024 = FILE_MAX. */
char base_path[1024];
@@ -1066,7 +1064,7 @@ typedef struct NodeShaderPrincipled {
char _pad[3];
} NodeShaderPrincipled;
-/* TEX_output */
+/** TEX_output. */
typedef struct TexNodeOutput {
char name[64];
} TexNodeOutput;
@@ -1632,14 +1630,17 @@ typedef struct NodeFunctionCompare {
#define NODE_IES_INTERNAL 0
#define NODE_IES_EXTERNAL 1
-/* frame node flags */
+/* Frame node flags. */
+
#define NODE_FRAME_SHRINK 1 /* keep the bounding box minimal */
#define NODE_FRAME_RESIZEABLE 2 /* test flag, if frame can be resized by user */
-/* proxy node flags */
+/* Proxy node flags. */
+
#define NODE_PROXY_AUTOTYPE 1 /* automatically change output type based on link */
-/* comp channel matte */
+/* Comp channel matte. */
+
#define CMP_NODE_CHANNEL_MATTE_CS_RGB 1
#define CMP_NODE_CHANNEL_MATTE_CS_HSV 2
#define CMP_NODE_CHANNEL_MATTE_CS_YUV 3
@@ -1661,7 +1662,7 @@ typedef struct NodeFunctionCompare {
#define SHD_VECT_TRANSFORM_SPACE_OBJECT 1
#define SHD_VECT_TRANSFORM_SPACE_CAMERA 2
-/* attribute */
+/** #NodeShaderAttribute.type */
enum {
SHD_ATTRIBUTE_GEOMETRY = 0,
SHD_ATTRIBUTE_OBJECT = 1,
@@ -1795,7 +1796,7 @@ enum {
#define SHD_AO_INSIDE 1
#define SHD_AO_LOCAL 2
-/* Mapping node vector types. */
+/** Mapping node vector types. */
enum {
NODE_MAPPING_TYPE_POINT = 0,
NODE_MAPPING_TYPE_TEXTURE = 1,
@@ -1803,7 +1804,7 @@ enum {
NODE_MAPPING_TYPE_NORMAL = 3,
};
-/* Rotation node vector types. */
+/** Rotation node vector types. */
enum {
NODE_VECTOR_ROTATE_TYPE_AXIS = 0,
NODE_VECTOR_ROTATE_TYPE_AXIS_X = 1,
@@ -1815,7 +1816,7 @@ enum {
/* math node clamp */
#define SHD_MATH_CLAMP 1
-/* Math node operations. */
+/** Math node operations. */
typedef enum NodeMathOperation {
NODE_MATH_ADD = 0,
NODE_MATH_SUBTRACT = 1,
@@ -1859,7 +1860,7 @@ typedef enum NodeMathOperation {
NODE_MATH_SMOOTH_MAX = 39,
} NodeMathOperation;
-/* Vector Math node operations. */
+/** Vector Math node operations. */
typedef enum NodeVectorMathOperation {
NODE_VECTOR_MATH_ADD = 0,
NODE_VECTOR_MATH_SUBTRACT = 1,
@@ -1893,14 +1894,14 @@ typedef enum NodeVectorMathOperation {
NODE_VECTOR_MATH_MULTIPLY_ADD = 26,
} NodeVectorMathOperation;
-/* Boolean math node operations. */
+/** Boolean math node operations. */
enum {
NODE_BOOLEAN_MATH_AND = 0,
NODE_BOOLEAN_MATH_OR = 1,
NODE_BOOLEAN_MATH_NOT = 2,
};
-/* Float compare node operations. */
+/** Float compare node operations. */
typedef enum NodeCompareMode {
NODE_COMPARE_MODE_ELEMENT = 0,
NODE_COMPARE_MODE_LENGTH = 1,
@@ -1921,7 +1922,7 @@ typedef enum NodeCompareOperation {
} NodeCompareOperation;
-/* Float to Int node operations. */
+/** Float to Int node operations. */
typedef enum FloatToIntRoundingMode {
FN_NODE_FLOAT_TO_INT_ROUND = 0,
FN_NODE_FLOAT_TO_INT_FLOOR = 1,
@@ -1929,13 +1930,13 @@ typedef enum FloatToIntRoundingMode {
FN_NODE_FLOAT_TO_INT_TRUNCATE = 3,
} FloatToIntRoundingMode;
-/* Clamp node types. */
+/** Clamp node types. */
enum {
NODE_CLAMP_MINMAX = 0,
NODE_CLAMP_RANGE = 1,
};
-/* Map range node types. */
+/** Map range node types. */
enum {
NODE_MAP_RANGE_LINEAR = 0,
NODE_MAP_RANGE_STEPPED = 1,
@@ -1947,7 +1948,8 @@ enum {
#define SHD_MIXRGB_USE_ALPHA 1
#define SHD_MIXRGB_CLAMP 2
-/* subsurface */
+/* Subsurface. */
+
enum {
#ifdef DNA_DEPRECATED_ALLOW
SHD_SUBSURFACE_COMPATIBLE = 0, /* Deprecated */
@@ -1978,25 +1980,29 @@ enum {
/* viewer and composite output. */
#define CMP_NODE_OUTPUT_IGNORE_ALPHA 1
-/* Plane track deform node */
+/* Plane track deform node. */
+
enum {
CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR = 1,
};
-/* Stabilization node */
+/* Stabilization node. */
+
enum {
CMP_NODEFLAG_STABILIZE_INVERSE = 1,
};
/* Set Alpha Node. */
-/* `NodeSetAlpha.mode` */
+
+/** #NodeSetAlpha.mode */
typedef enum CMPNodeSetAlphaMode {
CMP_NODE_SETALPHA_MODE_APPLY = 0,
CMP_NODE_SETALPHA_MODE_REPLACE_ALPHA = 1,
} CMPNodeSetAlphaMode;
/* Denoise Node. */
-/* `NodeDenoise.prefilter` */
+
+/** #NodeDenoise.prefilter */
typedef enum CMPNodeDenoisePrefilter {
CMP_NODE_DENOISE_PREFILTER_FAST = 0,
CMP_NODE_DENOISE_PREFILTER_NONE = 1,
diff --git a/source/blender/makesdna/DNA_object_force_types.h b/source/blender/makesdna/DNA_object_force_types.h
index 0aa4a171511..7d0d4c0d460 100644
--- a/source/blender/makesdna/DNA_object_force_types.h
+++ b/source/blender/makesdna/DNA_object_force_types.h
@@ -32,7 +32,7 @@ extern "C" {
struct BodySpring;
-/* pd->forcefield: Effector Fields types */
+/** #PartDeflect.forcefield: Effector Fields types. */
typedef enum ePFieldType {
/** (this is used for general effector weight). */
PFIELD_NULL = 0,
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 57c8ef200ae..c9345b6a950 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -57,7 +57,7 @@ struct SculptSession;
struct SoftBody;
struct bGPdata;
-/* Vertex Groups - Name Info */
+/** Vertex Groups - Name Info */
typedef struct bDeformGroup {
struct bDeformGroup *next, *prev;
/** MAX_VGROUP_NAME. */
@@ -66,7 +66,7 @@ typedef struct bDeformGroup {
char flag, _pad0[7];
} bDeformGroup;
-/* Face Maps. */
+/** Face Maps. */
typedef struct bFaceMap {
struct bFaceMap *next, *prev;
/** MAX_VGROUP_NAME. */
@@ -107,7 +107,7 @@ typedef struct BoundBox {
char _pad0[4];
} BoundBox;
-/* boundbox flag */
+/** #BoundBox.flag */
enum {
BOUNDBOX_DISABLED = (1 << 0),
BOUNDBOX_DIRTY = (1 << 1),
@@ -115,7 +115,7 @@ enum {
struct CustomData_MeshMasks;
-/* Not saved in file! */
+/** Not saved in file! */
typedef struct Object_Runtime {
/**
* The custom data layer mask that was last used
@@ -246,7 +246,7 @@ typedef struct Object {
/** String describing subobject info, MAX_ID_NAME-2. */
char parsubstr[64];
struct Object *parent, *track;
- /* if ob->proxy (or proxy_group), this object is proxy for object ob->proxy */
+ /* If `ob->proxy` (or proxy_group), this object is proxy for object `ob->proxy`. */
/* proxy_from is set in target back to the proxy. */
struct Object *proxy, *proxy_group, *proxy_from;
/** Old animation system, deprecated for 2.5. */
@@ -322,8 +322,7 @@ typedef struct Object {
* Inverse matrix of 'obmat' for any other use than rendering!
*
* \note this isn't assured to be valid as with 'obmat',
- * before using this value you should do...
- * invert_m4_m4(ob->imat, ob->obmat);
+ * before using this value you should do: `invert_m4_m4(ob->imat, ob->obmat)`
*/
float imat[4][4];
@@ -436,7 +435,7 @@ typedef struct Object {
Object_Runtime runtime;
} Object;
-/* Warning, this is not used anymore because hooks are now modifiers */
+/** DEPRECATED: this is not used anymore because hooks are now modifiers. */
typedef struct ObHook {
struct ObHook *next, *prev;
@@ -466,7 +465,7 @@ typedef struct ObHook {
/* used many places, should be specialized. */
#define SELECT 1
-/* type */
+/** #Object.type */
enum {
OB_EMPTY = 0,
OB_MESH = 1,
@@ -544,7 +543,7 @@ enum {
case ID_PT: \
case ID_VO
-/* partype: first 4 bits: type */
+/** #Object.partype: first 4 bits: type. */
enum {
PARTYPE = (1 << 4) - 1,
PAROBJECT = 0,
@@ -555,7 +554,7 @@ enum {
};
-/* (short) transflag */
+/** #Object.transflag (short) */
enum {
OB_TRANSFORM_ADJUST_ROOT_PARENT_FOR_VIEW_LOCK = 1 << 0,
OB_TRANSFLAG_UNUSED_1 = 1 << 1, /* cleared */
@@ -577,7 +576,7 @@ enum {
OB_DUPLI = OB_DUPLIVERTS | OB_DUPLICOLLECTION | OB_DUPLIFACES | OB_DUPLIPARTS,
};
-/* (short) trackflag / upflag */
+/** #Object.trackflag / #Object.upflag (short) */
enum {
OB_POSX = 0,
OB_POSY = 1,
@@ -587,7 +586,7 @@ enum {
OB_NEGZ = 5,
};
-/* dtx: flags (short) */
+/** #Object.dtx draw type extra flags (short) */
enum {
OB_DRAWBOUNDOX = 1 << 0,
OB_AXIS = 1 << 1,
@@ -606,7 +605,7 @@ enum {
OB_USE_GPENCIL_LIGHTS = 1 << 10,
};
-/* empty_drawtype: no flags */
+/** #Object.empty_drawtype: no flags */
enum {
OB_ARROWS = 1,
OB_PLAINAXES = 2,
@@ -618,7 +617,10 @@ enum {
OB_EMPTY_IMAGE = 8,
};
-/* gpencil add types */
+/**
+ * Grease-pencil add types.
+ * TODO: doesn't need to be DNA, local to `OBJECT_OT_gpencil_add`.
+ */
enum {
GP_EMPTY = 0,
GP_STROKE = 1,
@@ -628,7 +630,7 @@ enum {
GP_LRT_COLLECTION = 5,
};
-/* boundtype */
+/** #Object.boundtype */
enum {
OB_BOUND_BOX = 0,
OB_BOUND_SPHERE = 1,
@@ -642,7 +644,7 @@ enum {
/* **************** BASE ********************* */
-/* base->flag_legacy */
+/** #Base.flag_legacy */
enum {
BA_WAS_SEL = (1 << 1),
/* NOTE: BA_HAS_RECALC_DATA can be re-used later if freed in readfile.c. */
@@ -671,7 +673,7 @@ enum {
# define OB_FLAG_UNUSED_12 (1 << 12) /* cleared */
#endif
-/* ob->visibility_flag */
+/** #Object.visibility_flag */
enum {
OB_HIDE_VIEWPORT = 1 << 0,
OB_HIDE_SELECT = 1 << 1,
@@ -686,7 +688,7 @@ enum {
OB_SHADOW_CATCHER = 1 << 10
};
-/* ob->shapeflag */
+/** #Object.shapeflag */
enum {
OB_SHAPE_LOCK = 1 << 0,
#ifdef DNA_DEPRECATED_ALLOW
@@ -695,7 +697,7 @@ enum {
OB_SHAPE_EDIT_MODE = 1 << 2,
};
-/* ob->nlaflag */
+/** #Object.nlaflag */
enum {
OB_ADS_UNUSED_1 = 1 << 0, /* cleared */
OB_ADS_UNUSED_2 = 1 << 1, /* cleared */
@@ -711,7 +713,7 @@ enum {
/* OB_ADS_SHOWPARTS = 1 << 14, */ /* UNUSED */
};
-/* ob->protectflag */
+/** #Object.protectflag */
enum {
OB_LOCK_LOCX = 1 << 0,
OB_LOCK_LOCY = 1 << 1,
@@ -729,13 +731,13 @@ enum {
OB_LOCK_ROT4D = 1 << 10,
};
-/* ob->duplicator_visibility_flag */
+/** #Object.duplicator_visibility_flag */
enum {
OB_DUPLI_FLAG_VIEWPORT = 1 << 0,
OB_DUPLI_FLAG_RENDER = 1 << 1,
};
-/* ob->empty_image_depth */
+/** #Object.empty_image_depth */
#define OB_EMPTY_IMAGE_DEPTH_DEFAULT 0
#define OB_EMPTY_IMAGE_DEPTH_FRONT 1
#define OB_EMPTY_IMAGE_DEPTH_BACK 2
diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h
index a51c532dfb3..5add664f624 100644
--- a/source/blender/makesdna/DNA_particle_types.h
+++ b/source/blender/makesdna/DNA_particle_types.h
@@ -72,7 +72,7 @@ typedef struct ParticleSpring {
unsigned int particle_index[2], delete_flag;
} ParticleSpring;
-/* Child particles are created around or between parent particles */
+/** Child particles are created around or between parent particles. */
typedef struct ChildParticle {
/** Face index on the final derived mesh. */
int num;
@@ -364,8 +364,7 @@ typedef struct ParticleSystem {
int flag, totpart, totunexist, totchild, totcached, totchildcache;
/* NOTE: Recalc is one of ID_RECALC_PSYS_ALL flags.
*
- * TODO(sergey): Use part->id.recalc instead of this duplicated flag
- * somehow. */
+ * TODO(sergey): Use #ParticleSettings.id.recalc instead of this duplicated flag somehow. */
int recalc;
short target_psys, totkeyed, bakespace;
char _pad1[6];
@@ -438,9 +437,11 @@ typedef enum eParticleDrawFlag {
PART_DRAW_HAIR_GRID = (1 << 18),
} eParticleDrawFlag;
-/* part->type
+/**
+ * #ParticleSettings.type
* Hair is always baked static in object/geometry space.
- * Other types (normal particles) are in global space and not static baked. */
+ * Other types (normal particles) are in global space and not static baked.
+ */
enum {
PART_EMITTER = 0,
/* REACTOR type currently unused */
@@ -458,7 +459,7 @@ enum {
PART_FLUID_SPRAYFOAMBUBBLE = 12,
};
-/* Mirroring Mantaflow particle types from particle.h (Mantaflow header). */
+/** Mirroring Mantaflow particle types from particle.h (Mantaflow header). */
enum {
/* PARTICLE_TYPE_NONE = (0 << 0), */ /* UNUSED */
/* PARTICLE_TYPE_NEW = (1 << 0), */ /* UNUSED */
@@ -470,7 +471,7 @@ enum {
/* PARTICLE_TYPE_INVALID = (1 << 30), */ /* UNUSED */
};
-/* part->flag */
+/** #ParticleSettings.flag */
#define PART_REACT_STA_END 1
#define PART_REACT_MULTIPLE 2
@@ -514,26 +515,26 @@ enum {
#define PART_SELF_EFFECT (1 << 22)
-/* part->from */
+/** #ParticleSettings.from */
#define PART_FROM_VERT 0
#define PART_FROM_FACE 1
#define PART_FROM_VOLUME 2
/* #define PART_FROM_PARTICLE 3 deprecated! */
#define PART_FROM_CHILD 4
-/* part->distr */
+/** #ParticleSettings.distr */
#define PART_DISTR_JIT 0
#define PART_DISTR_RAND 1
#define PART_DISTR_GRID 2
-/* part->phystype */
+/** #ParticleSettings.phystype */
#define PART_PHYS_NO 0
#define PART_PHYS_NEWTON 1
#define PART_PHYS_KEYED 2
#define PART_PHYS_BOIDS 3
#define PART_PHYS_FLUID 4
-/* part->kink */
+/** #ParticleSettings.kink */
typedef enum eParticleKink {
PART_KINK_NO = 0,
PART_KINK_CURL = 1,
@@ -543,7 +544,7 @@ typedef enum eParticleKink {
PART_KINK_SPIRAL = 5,
} eParticleKink;
-/* part->child_flag */
+/** #ParticleSettings.child_flag */
typedef enum eParticleChildFlag {
PART_CHILD_USE_CLUMP_NOISE = (1 << 0),
PART_CHILD_USE_CLUMP_CURVE = (1 << 1),
@@ -551,22 +552,22 @@ typedef enum eParticleChildFlag {
PART_CHILD_USE_TWIST_CURVE = (1 << 3),
} eParticleChildFlag;
-/* part->shape_flag */
+/** #ParticleSettings.shape_flag */
typedef enum eParticleShapeFlag {
PART_SHAPE_CLOSE_TIP = (1 << 0),
} eParticleShapeFlag;
-/* part->draw_col */
+/* #ParticleSettings.draw_col */
#define PART_DRAW_COL_NONE 0
#define PART_DRAW_COL_MAT 1
#define PART_DRAW_COL_VEL 2
#define PART_DRAW_COL_ACC 3
-/* part->time_flag */
+/* #ParticleSettings.time_flag */
#define PART_TIME_AUTOSF 1 /* Automatic subframes */
-/* part->draw_as */
-/* part->ren_as */
+/* #ParticleSettings.draw_as */
+/* #ParticleSettings.ren_as */
#define PART_DRAW_NOT 0
#define PART_DRAW_DOT 1
#define PART_DRAW_HALO 1
@@ -580,13 +581,13 @@ typedef enum eParticleShapeFlag {
#define PART_DRAW_BB 9 /* deprecated */
#define PART_DRAW_REND 10
-/* part->integrator */
+/* #ParticleSettings.integrator */
#define PART_INT_EULER 0
#define PART_INT_MIDPOINT 1
#define PART_INT_RK4 2
#define PART_INT_VERLET 3
-/* part->rotmode */
+/* #ParticleSettings.rotmode */
#define PART_ROT_NOR 1
#define PART_ROT_VEL 2
#define PART_ROT_GLOB_X 3
@@ -597,7 +598,7 @@ typedef enum eParticleShapeFlag {
#define PART_ROT_OB_Z 8
#define PART_ROT_NOR_TAN 9
-/* part->avemode */
+/* #ParticleSettings.avemode */
#define PART_AVE_VELOCITY 1
#define PART_AVE_RAND 2
#define PART_AVE_HORIZONTAL 3
@@ -606,12 +607,12 @@ typedef enum eParticleShapeFlag {
#define PART_AVE_GLOBAL_Y 6
#define PART_AVE_GLOBAL_Z 7
-/* part->reactevent */
+/* #ParticleSettings.reactevent */
#define PART_EVENT_DEATH 0
#define PART_EVENT_COLLIDE 1
#define PART_EVENT_NEAR 2
-/* part->childtype */
+/* #ParticleSettings.childtype */
#define PART_CHILD_PARTICLES 1
#define PART_CHILD_FACES 2
@@ -675,7 +676,7 @@ typedef enum eParticleShapeFlag {
#define PTARGET_MODE_FRIEND 1
#define PTARGET_MODE_ENEMY 2
-/* mapto */
+/** #MTex.mapto */
typedef enum eParticleTextureInfluence {
/* init */
PAMAP_TIME = (1 << 0), /* emission time */
diff --git a/source/blender/makesdna/DNA_pointcloud_types.h b/source/blender/makesdna/DNA_pointcloud_types.h
index 26f1db3324b..53fda29a33a 100644
--- a/source/blender/makesdna/DNA_pointcloud_types.h
+++ b/source/blender/makesdna/DNA_pointcloud_types.h
@@ -54,7 +54,7 @@ typedef struct PointCloud {
void *batch_cache;
} PointCloud;
-/* PointCloud.flag */
+/** #PointCloud.flag */
enum {
PT_DS_EXPAND = (1 << 0),
};
diff --git a/source/blender/makesdna/DNA_rigidbody_types.h b/source/blender/makesdna/DNA_rigidbody_types.h
index aa11e74e89d..f653905e169 100644
--- a/source/blender/makesdna/DNA_rigidbody_types.h
+++ b/source/blender/makesdna/DNA_rigidbody_types.h
@@ -38,7 +38,7 @@ struct EffectorWeights;
/* ******************************** */
/* RigidBody World */
-/* Container for data shared by original and evaluated copies of RigidBodyWorld */
+/** Container for data shared by original and evaluated copies of #RigidBodyWorld. */
typedef struct RigidBodyWorld_Shared {
/* cache */
struct PointCache *pointcache;
@@ -90,7 +90,7 @@ typedef struct RigidBodyWorld {
float time_scale;
} RigidBodyWorld;
-/* Flags for RigidBodyWorld */
+/** RigidBodyWorld.flag */
typedef enum eRigidBodyWorld_Flag {
/* should sim world be skipped when evaluating (user setting) */
RBW_FLAG_MUTED = (1 << 0),
@@ -170,7 +170,7 @@ typedef struct RigidBodyOb {
struct RigidBodyOb_Shared *shared;
} RigidBodyOb;
-/* Participation types for RigidBodyOb */
+/** #RigidBodyOb.type */
typedef enum eRigidBodyOb_Type {
/* active geometry participant in simulation. is directly controlled by sim */
RBO_TYPE_ACTIVE = 0,
@@ -178,7 +178,7 @@ typedef enum eRigidBodyOb_Type {
RBO_TYPE_PASSIVE = 1,
} eRigidBodyOb_Type;
-/* Flags for RigidBodyOb */
+/** #RigidBodyOb.flag */
typedef enum eRigidBodyOb_Flag {
/* rigidbody is kinematic (controlled by the animation system) */
RBO_FLAG_KINEMATIC = (1 << 0),
@@ -198,7 +198,7 @@ typedef enum eRigidBodyOb_Flag {
RBO_FLAG_USE_DEFORM = (1 << 7),
} eRigidBodyOb_Flag;
-/* RigidBody Collision Shape */
+/** Rigid Body Collision Shape. */
typedef enum eRigidBody_Shape {
/** Simple box (i.e. bounding box). */
RB_SHAPE_BOX = 0,
@@ -304,7 +304,7 @@ typedef struct RigidBodyCon {
void *physics_constraint;
} RigidBodyCon;
-/* Participation types for RigidBodyOb */
+/** Participation types for #RigidBodyOb.type */
typedef enum eRigidBodyCon_Type {
/** lets bodies rotate around a specified point */
RBC_TYPE_POINT = 0,
@@ -333,13 +333,13 @@ typedef enum eRigidBodyCon_Type {
RBC_TYPE_MOTOR = 11,
} eRigidBodyCon_Type;
-/* Spring implementation type for RigidBodyOb */
+/** Spring implementation type for RigidBodyOb. */
typedef enum eRigidBodyCon_SpringType {
RBC_SPRING_TYPE1 = 0, /* btGeneric6DofSpringConstraint */
RBC_SPRING_TYPE2 = 1, /* btGeneric6DofSpring2Constraint */
} eRigidBodyCon_SpringType;
-/* Flags for RigidBodyCon */
+/** #RigidBodyCon.flag */
typedef enum eRigidBodyCon_Flag {
/* constraint influences rigid body motion */
RBC_FLAG_ENABLED = (1 << 0),
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index c66ac3a6211..4607a47a9a8 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -195,7 +195,7 @@ typedef struct AudioData {
/* *************************************************************** */
/* Render Layers */
-/* Render Layer */
+/** Render Layer. */
typedef struct SceneRenderLayer {
struct SceneRenderLayer *next, *prev;
@@ -323,7 +323,7 @@ typedef enum eScenePassType {
#define RE_PASSNAME_BLOOM "BloomCol"
#define RE_PASSNAME_VOLUME_LIGHT "VolumeDir"
-/* View - MultiView */
+/** View - MultiView. */
typedef struct SceneRenderView {
struct SceneRenderView *next, *prev;
@@ -785,12 +785,12 @@ typedef struct RenderData {
struct CurveMapping mblur_shutter_curve;
} RenderData;
-/* RenderData.quality_flag */
+/** #RenderData.quality_flag */
typedef enum eQualityOption {
SCE_PERF_HQ_NORMALS = (1 << 0),
} eQualityOption;
-/* RenderData.hair_type */
+/** #RenderData.hair_type */
typedef enum eHairType {
SCE_HAIR_SHAPE_STRAND = 0,
SCE_HAIR_SHAPE_STRIP = 1,
@@ -799,7 +799,7 @@ typedef enum eHairType {
/* *************************************************************** */
/* Render Conversion/Simplification Settings */
-/* control render convert and shading engine */
+/** Control render convert and shading engine. */
typedef struct RenderProfile {
struct RenderProfile *next, *prev;
char name[32];
@@ -829,7 +829,7 @@ typedef struct RenderProfile {
#define STEREO_RIGHT_SUFFIX "_R"
#define STEREO_LEFT_SUFFIX "_L"
-/* View3D.stereo3d_camera / View3D.multiview_eye / ImageUser.multiview_eye */
+/** #View3D.stereo3d_camera / #View3D.multiview_eye / #ImageUser.multiview_eye */
typedef enum eStereoViews {
STEREO_LEFT_ID = 0,
STEREO_RIGHT_ID = 1,
@@ -861,12 +861,12 @@ typedef struct Paint_Runtime {
char _pad[2];
} Paint_Runtime;
-/* We might want to store other things here. */
+/** We might want to store other things here. */
typedef struct PaintToolSlot {
struct Brush *brush;
} PaintToolSlot;
-/* Paint Tool Base */
+/** Paint Tool Base. */
typedef struct Paint {
struct Brush *brush;
@@ -903,7 +903,7 @@ typedef struct Paint {
/* ------------------------------------------- */
/* Image Paint */
-/* Texture/Image Editor */
+/** Texture/Image Editor. */
typedef struct ImagePaintSettings {
Paint paint;
@@ -934,7 +934,7 @@ typedef struct ImagePaintSettings {
/* ------------------------------------------- */
/* Particle Edit */
-/* Settings for a Particle Editing Brush */
+/** Settings for a Particle Editing Brush. */
typedef struct ParticleBrushData {
/** Common setting. */
short size;
@@ -944,7 +944,7 @@ typedef struct ParticleBrushData {
float strength;
} ParticleBrushData;
-/* Particle Edit Mode Settings */
+/** Particle Edit Mode Settings. */
typedef struct ParticleEditSettings {
short flag;
short totrekey;
@@ -971,7 +971,7 @@ typedef struct ParticleEditSettings {
/* ------------------------------------------- */
/* Sculpt */
-/* Sculpt */
+/** Sculpt. */
typedef struct Sculpt {
Paint paint;
@@ -1006,7 +1006,7 @@ typedef struct UvSculpt {
Paint paint;
} UvSculpt;
-/* grease pencil drawing brushes */
+/** Grease pencil drawing brushes. */
typedef struct GpPaint {
Paint paint;
int flag;
@@ -1020,21 +1020,21 @@ enum {
GPPAINT_FLAG_USE_VERTEXCOLOR = 1,
};
-/* Grease pencil vertex paint. */
+/** Grease pencil vertex paint. */
typedef struct GpVertexPaint {
Paint paint;
int flag;
char _pad[4];
} GpVertexPaint;
-/* Grease pencil sculpt paint. */
+/** Grease pencil sculpt paint. */
typedef struct GpSculptPaint {
Paint paint;
int flag;
char _pad[4];
} GpSculptPaint;
-/* Grease pencil weight paint. */
+/** Grease pencil weight paint. */
typedef struct GpWeightPaint {
Paint paint;
int flag;
@@ -1044,7 +1044,7 @@ typedef struct GpWeightPaint {
/* ------------------------------------------- */
/* Vertex Paint */
-/* Vertex Paint */
+/** Vertex Paint. */
typedef struct VPaint {
Paint paint;
char flag;
@@ -1062,7 +1062,7 @@ enum {
/* ------------------------------------------- */
/* GPencil Stroke Sculpting */
-/* GP_Sculpt_Settings.lock_axis */
+/** #GP_Sculpt_Settings.lock_axis */
typedef enum eGP_Lockaxis_Types {
GP_LOCKAXIS_VIEW = 0,
GP_LOCKAXIS_X = 1,
@@ -1071,7 +1071,7 @@ typedef enum eGP_Lockaxis_Types {
GP_LOCKAXIS_CURSOR = 4,
} eGP_Lockaxis_Types;
-/* Settings for a GPencil Speed Guide */
+/** Settings for a GPencil Speed Guide. */
typedef struct GP_Sculpt_Guide {
char use_guide;
char use_snapping;
@@ -1085,7 +1085,7 @@ typedef struct GP_Sculpt_Guide {
struct Object *reference_object;
} GP_Sculpt_Guide;
-/* GPencil Stroke Sculpting Settings */
+/** GPencil Stroke Sculpting Settings. */
typedef struct GP_Sculpt_Settings {
/** Runtime. */
void *paintcursor;
@@ -1134,7 +1134,7 @@ typedef enum eGP_vertex_SelectMaskFlag {
GP_VERTEX_MASK_SELECTMODE_SEGMENT = (1 << 2),
} eGP_Vertex_SelectMaskFlag;
-/* Settings for GP Interpolation Operators */
+/** Settings for GP Interpolation Operators. */
typedef struct GP_Interpolate_Settings {
/** Custom interpolation curve (for use with GP_IPO_CURVEMAP). */
struct CurveMapping *custom_ipo;
@@ -1255,7 +1255,7 @@ typedef struct UnifiedPaintSettings {
struct ColorSpace *colorspace;
} UnifiedPaintSettings;
-/* UnifiedPaintSettings.flag */
+/** #UnifiedPaintSettings.flag */
typedef enum {
UNIFIED_PAINT_SIZE = (1 << 0),
UNIFIED_PAINT_ALPHA = (1 << 1),
@@ -1313,7 +1313,7 @@ enum {
/* *************************************************************** */
/* Stats */
-/* Stats for Meshes */
+/** Stats for Meshes. */
typedef struct MeshStatVis {
char type;
char _pad1[2];
@@ -1570,8 +1570,8 @@ typedef struct PhysicsSettings {
char _pad0[4];
} PhysicsSettings;
-/* ------------------------------------------- */
-/* Safe Area options used in Camera View & Sequencer
+/**
+ * Safe Area options used in Camera View & Sequencer.
*/
typedef struct DisplaySafeAreas {
/* each value represents the (x,y) margins as a multiplier.
@@ -1587,8 +1587,9 @@ typedef struct DisplaySafeAreas {
float action_center[2];
} DisplaySafeAreas;
-/* ------------------------------------------- */
-/* Scene Display - used for store scene specific display settings for the 3d view */
+/**
+ * Scene Display - used for store scene specific display settings for the 3d view.
+ */
typedef struct SceneDisplay {
/** Light direction for shadows/highlight. */
float light_direction[3];
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index a4c254d6e5a..1a1d7cba7af 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -244,7 +244,7 @@ typedef struct PanelCategoryDyn {
rcti rect;
} PanelCategoryDyn;
-/* region stack of active tabs */
+/** Region stack of active tabs. */
typedef struct PanelCategoryStack {
struct PanelCategoryStack *next, *prev;
char idname[64];
@@ -654,8 +654,10 @@ enum {
#define UILST_FLT_SORT_MASK (((unsigned int)(UILST_FLT_SORT_REVERSE | UILST_FLT_SORT_LOCK)) - 1)
-/* regiontype, first two are the default set */
-/* Do NOT change order, append on end. Types are hardcoded needed */
+/**
+ * regiontype, first two are the default set.
+ * \warning Do NOT change order, append on end. Types are hard-coded needed.
+ */
typedef enum eRegion_Type {
RGN_TYPE_WINDOW = 0,
RGN_TYPE_HEADER = 1,
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index e1bba60396a..5fe67a34dae 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -47,6 +47,10 @@ struct SequenceLookup;
struct VFont;
struct bSound;
+/* -------------------------------------------------------------------- */
+/** \name Sequence & Editing Structs
+ * \{ */
+
/* strlens; 256= FILE_MAXFILE, 768= FILE_MAXDIR */
typedef struct StripAnim {
@@ -311,7 +315,12 @@ typedef struct Editing {
void *_pad1;
} Editing;
-/* ************* Effect Variable Structs ********* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Effect Variable Structs
+ * \{ */
+
typedef struct WipeVars {
float edgeWidth, angle;
short forward, wipetype;
@@ -360,7 +369,7 @@ typedef struct SpeedControlVars {
float speed_fader_frame_number;
} SpeedControlVars;
-/* SpeedControlVars.speed_control_type */
+/** #SpeedControlVars.speed_control_type */
enum {
SEQ_SPEED_STRETCH = 0,
SEQ_SPEED_MULTIPLY = 1,
@@ -387,7 +396,7 @@ typedef struct TextVars {
char _pad[5];
} TextVars;
-/* TextVars.flag */
+/** #TextVars.flag */
enum {
SEQ_TEXT_SHADOW = (1 << 0),
SEQ_TEXT_BOX = (1 << 1),
@@ -395,14 +404,14 @@ enum {
SEQ_TEXT_ITALIC = (1 << 3),
};
-/* TextVars.align */
+/** #TextVars.align */
enum {
SEQ_TEXT_ALIGN_X_LEFT = 0,
SEQ_TEXT_ALIGN_X_CENTER = 1,
SEQ_TEXT_ALIGN_X_RIGHT = 2,
};
-/* TextVars.align_y */
+/** #TextVars.align_y */
enum {
SEQ_TEXT_ALIGN_Y_TOP = 0,
SEQ_TEXT_ALIGN_Y_CENTER = 1,
@@ -418,7 +427,11 @@ typedef struct ColorMixVars {
float factor;
} ColorMixVars;
-/* ***************** Sequence modifiers ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sequence Modifiers
+ * \{ */
typedef struct SequenceModifierData {
struct SequenceModifierData *next, *prev;
@@ -489,7 +502,11 @@ enum {
SEQ_TONEMAP_RD_PHOTORECEPTOR = 1,
};
-/* ***************** Scopes ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Scopes
+ * \{ */
typedef struct SequencerScopes {
struct ImBuf *reference_ibuf;
@@ -522,10 +539,15 @@ typedef struct SequencerScopes {
#define SEQ_SPEED_UNUSED_3 (1 << 2) /* cleared */
#define SEQ_SPEED_USE_INTERPOLATION (1 << 3)
-/* ***************** SEQUENCE ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Flags & Types
+ * \{ */
+
#define SEQ_NAME_MAXSTR 64
-/* seq->flag */
+/** #Sequence.flag */
enum {
/* SELECT */
SEQ_LEFTSEL = (1 << 1),
@@ -568,7 +590,7 @@ enum {
SEQ_INVALID_EFFECT = (1u << 31),
};
-/* StripProxy->storage */
+/** #StripProxy.storage */
enum {
SEQ_STORAGE_PROXY_CUSTOM_FILE = (1 << 1), /* store proxy in custom directory */
SEQ_STORAGE_PROXY_CUSTOM_DIR = (1 << 2), /* store proxy in custom file */
@@ -601,18 +623,22 @@ enum {
#define SEQ_PROXY_TC_RECORD_RUN_NO_GAPS 8
#define SEQ_PROXY_TC_ALL 15
-/* SeqProxy->build_flags */
+/** SeqProxy.build_flags */
enum {
SEQ_PROXY_SKIP_EXISTING = 1,
};
-/* seq->alpha_mode */
+/** #Sequence.alpha_mode */
enum {
SEQ_ALPHA_STRAIGHT = 0,
SEQ_ALPHA_PREMUL = 1,
};
-/* seq->type WATCH IT: SEQ_TYPE_EFFECT BIT is used to determine if this is an effect strip!!! */
+/**
+ * #Sequence.type
+ *
+ * \warning #SEQ_TYPE_EFFECT BIT is used to determine if this is an effect strip!
+ */
enum {
SEQ_TYPE_IMAGE = 0,
SEQ_TYPE_META = 1,
@@ -681,7 +707,7 @@ enum {
/* modifiers */
-/* SequenceModifierData->type */
+/** #SequenceModifierData.type */
enum {
seqModifierType_ColorBalance = 1,
seqModifierType_Curves = 2,
@@ -694,7 +720,7 @@ enum {
NUM_SEQUENCE_MODIFIER_TYPES,
};
-/* SequenceModifierData->flag */
+/** #SequenceModifierData.flag */
enum {
SEQUENCE_MODIFIER_MUTE = (1 << 0),
SEQUENCE_MODIFIER_EXPANDED = (1 << 1),
@@ -712,13 +738,14 @@ enum {
SEQUENCE_MASK_TIME_ABSOLUTE = 1,
};
-/* Sequence->cache_flag
- * SEQ_CACHE_STORE_RAW
- * SEQ_CACHE_STORE_PREPROCESSED
- * SEQ_CACHE_STORE_COMPOSITE
- * FINAL_OUT is ignored
+/**
+ * #Sequence.cache_flag
+ * - #SEQ_CACHE_STORE_RAW
+ * - #SEQ_CACHE_STORE_PREPROCESSED
+ * - #SEQ_CACHE_STORE_COMPOSITE
+ * - #FINAL_OUT is ignored
*
- * Editing->cache_flag
+ * #Editing.cache_flag
* all entries
*/
enum {
@@ -745,7 +772,7 @@ enum {
SEQ_CACHE_STORE_THUMBNAIL = (1 << 12),
};
-/* Sequence->color_tag. */
+/** #Sequence.color_tag. */
typedef enum SequenceColorTag {
SEQUENCE_COLOR_NONE = -1,
SEQUENCE_COLOR_01,
diff --git a/source/blender/makesdna/DNA_shader_fx_types.h b/source/blender/makesdna/DNA_shader_fx_types.h
index 01e3b3a5230..be787c1760f 100644
--- a/source/blender/makesdna/DNA_shader_fx_types.h
+++ b/source/blender/makesdna/DNA_shader_fx_types.h
@@ -77,7 +77,7 @@ typedef struct ShaderFxData {
char *error;
} ShaderFxData;
-/* Runtime temp data */
+/** Runtime temp data. */
typedef struct ShaderFxData_Runtime {
float loc[3];
char _pad[4];
diff --git a/source/blender/makesdna/DNA_simulation_types.h b/source/blender/makesdna/DNA_simulation_types.h
index a700c9fe2f8..b14301ed32d 100644
--- a/source/blender/makesdna/DNA_simulation_types.h
+++ b/source/blender/makesdna/DNA_simulation_types.h
@@ -38,7 +38,7 @@ typedef struct Simulation {
char _pad[4];
} Simulation;
-/* Simulation.flag */
+/** #Simulation.flag */
enum {
SIM_DS_EXPAND = (1 << 0),
};
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index a7a19be5b3e..7837409cece 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -61,16 +61,16 @@ struct bNodeTree;
struct wmOperator;
struct wmTimer;
-/* Defined in `buttons_intern.h`. */
+/** Defined in `buttons_intern.h`. */
typedef struct SpaceProperties_Runtime SpaceProperties_Runtime;
-/* Defined in `node_intern.hh`. */
+/** Defined in `node_intern.hh`. */
typedef struct SpaceNode_Runtime SpaceNode_Runtime;
-/* Defined in `file_intern.h`. */
+/** Defined in `file_intern.h`. */
typedef struct SpaceFile_Runtime SpaceFile_Runtime;
-/* Defined in `spreadsheet_intern.hh`. */
+/** Defined in `spreadsheet_intern.hh`. */
typedef struct SpaceSpreadsheet_Runtime SpaceSpreadsheet_Runtime;
/* -------------------------------------------------------------------- */
@@ -91,7 +91,7 @@ typedef struct SpaceLink {
char _pad0[6];
} SpaceLink;
-/* SpaceLink.link_flag */
+/** #SpaceLink.link_flag */
enum {
/**
* The space is not a regular one opened through the editor menu (for example) but spawned by an
@@ -113,7 +113,7 @@ enum {
/** \name Space Info
* \{ */
-/* Info Header */
+/** Info Header. */
typedef struct SpaceInfo {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -127,7 +127,7 @@ typedef struct SpaceInfo {
char _pad[7];
} SpaceInfo;
-/* SpaceInfo.rpt_mask */
+/** #SpaceInfo.rpt_mask */
typedef enum eSpaceInfo_RptMask {
INFO_RPT_DEBUG = (1 << 0),
INFO_RPT_INFO = (1 << 1),
@@ -142,7 +142,7 @@ typedef enum eSpaceInfo_RptMask {
/** \name Properties Editor
* \{ */
-/* Properties Editor */
+/** Properties Editor. */
typedef struct SpaceProperties {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -210,7 +210,7 @@ typedef struct SpaceProperties {
// #define BUTS_EFFECTS 14
#endif /* DNA_DEPRECATED_ALLOW */
-/* SpaceProperties.mainb new */
+/** #SpaceProperties.mainb new */
typedef enum eSpaceButtons_Context {
BCONTEXT_RENDER = 0,
BCONTEXT_SCENE = 1,
@@ -235,7 +235,7 @@ typedef enum eSpaceButtons_Context {
BCONTEXT_TOT,
} eSpaceButtons_Context;
-/* SpaceProperties.flag */
+/** #SpaceProperties.flag */
typedef enum eSpaceButtons_Flag {
/* SB_PRV_OSA = (1 << 0), */ /* UNUSED */
SB_PIN_CONTEXT = (1 << 1),
@@ -246,7 +246,7 @@ typedef enum eSpaceButtons_Flag {
SB_SHADING_CONTEXT = (1 << 4),
} eSpaceButtons_Flag;
-/* SpaceProperties.outliner_sync */
+/** #SpaceProperties.outliner_sync */
typedef enum eSpaceButtons_OutlinerSync {
PROPERTIES_SYNC_AUTO = 0,
PROPERTIES_SYNC_NEVER = 1,
@@ -259,10 +259,10 @@ typedef enum eSpaceButtons_OutlinerSync {
/** \name Outliner
* \{ */
-/* Defined in `outliner_intern.h`. */
+/** Defined in `outliner_intern.h`. */
typedef struct SpaceOutliner_Runtime SpaceOutliner_Runtime;
-/* Outliner */
+/** Outliner */
typedef struct SpaceOutliner {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -303,7 +303,7 @@ typedef struct SpaceOutliner {
SpaceOutliner_Runtime *runtime;
} SpaceOutliner;
-/* SpaceOutliner.flag */
+/** #SpaceOutliner.flag */
typedef enum eSpaceOutliner_Flag {
/* SO_TESTBLOCKS = (1 << 0), */ /* UNUSED */
/* SO_NEWSELECTED = (1 << 1), */ /* UNUSED */
@@ -314,7 +314,7 @@ typedef enum eSpaceOutliner_Flag {
SO_MODE_COLUMN = (1 << 6),
} eSpaceOutliner_Flag;
-/* SpaceOutliner.filter */
+/** #SpaceOutliner.filter */
typedef enum eSpaceOutliner_Filter {
SO_FILTER_SEARCH = (1 << 0), /* Run-time flag. */
SO_FILTER_CLEARED_1 = (1 << 1),
@@ -356,7 +356,7 @@ typedef enum eSpaceOutliner_Filter {
(SO_FILTER_NO_OB_CONTENT | SO_FILTER_NO_CHILDREN | SO_FILTER_OB_TYPE | SO_FILTER_OB_STATE | \
SO_FILTER_NO_COLLECTION | SO_FILTER_NO_VIEW_LAYERS | SO_FILTER_NO_LIB_OVERRIDE)
-/* SpaceOutliner.filter_state */
+/** #SpaceOutliner.filter_state */
typedef enum eSpaceOutliner_StateFilter {
SO_FILTER_OB_ALL = 0,
SO_FILTER_OB_VISIBLE = 1,
@@ -366,7 +366,7 @@ typedef enum eSpaceOutliner_StateFilter {
SO_FILTER_OB_SELECTABLE = 5,
} eSpaceOutliner_StateFilter;
-/* SpaceOutliner.show_restrict_flags */
+/** #SpaceOutliner.show_restrict_flags */
typedef enum eSpaceOutliner_ShowRestrictFlag {
SO_RESTRICT_ENABLE = (1 << 0),
SO_RESTRICT_SELECT = (1 << 1),
@@ -377,7 +377,7 @@ typedef enum eSpaceOutliner_ShowRestrictFlag {
SO_RESTRICT_INDIRECT_ONLY = (1 << 6),
} eSpaceOutliner_Restrict;
-/* SpaceOutliner.outlinevis */
+/** #SpaceOutliner.outlinevis */
typedef enum eSpaceOutliner_Mode {
SO_SCENES = 0,
/* SO_CUR_SCENE = 1, */ /* deprecated! */
@@ -398,7 +398,7 @@ typedef enum eSpaceOutliner_Mode {
SO_OVERRIDES_LIBRARY = 16,
} eSpaceOutliner_Mode;
-/* SpaceOutliner.storeflag */
+/** #SpaceOutliner.storeflag */
typedef enum eSpaceOutliner_StoreFlag {
/* cleanup tree */
SO_TREESTORE_CLEANUP = (1 << 0),
@@ -408,7 +408,7 @@ typedef enum eSpaceOutliner_StoreFlag {
SO_TREESTORE_REBUILD = (1 << 2),
} eSpaceOutliner_StoreFlag;
-/* outliner search flags (SpaceOutliner.search_flags) */
+/** Outliner search flags (#SpaceOutliner.search_flags) */
typedef enum eSpaceOutliner_Search_Flags {
SO_FIND_CASE_SENSITIVE = (1 << 0),
SO_FIND_COMPLETE = (1 << 1),
@@ -429,7 +429,7 @@ typedef struct SpaceGraph_Runtime {
ListBase ghost_curves;
} SpaceGraph_Runtime;
-/* 'Graph' Editor (formerly known as the IPO Editor) */
+/** 'Graph' Editor (formerly known as the IPO Editor). */
typedef struct SpaceGraph {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -467,7 +467,7 @@ typedef struct SpaceGraph {
SpaceGraph_Runtime runtime;
} SpaceGraph;
-/* SpaceGraph.flag (Graph Editor Settings) */
+/** #SpaceGraph.flag (Graph Editor Settings) */
typedef enum eGraphEdit_Flag {
/* OLD DEPRECATED SETTING */
/* SIPO_LOCK_VIEW = (1 << 0), */
@@ -504,7 +504,7 @@ typedef enum eGraphEdit_Flag {
SIPO_NO_DRAW_EXTRAPOLATION = (1 << 17),
} eGraphEdit_Flag;
-/* SpaceGraph.mode (Graph Editor Mode) */
+/** #SpaceGraph.mode (Graph Editor Mode) */
typedef enum eGraphEdit_Mode {
/* all animation curves (from all over Blender) */
SIPO_MODE_ANIMATION = 0,
@@ -532,7 +532,7 @@ typedef enum eGraphEdit_Runtime_Flag {
/** \name NLA Editor
* \{ */
-/* NLA Editor */
+/** NLA Editor */
typedef struct SpaceNla {
struct SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -552,7 +552,7 @@ typedef struct SpaceNla {
View2D v2d DNA_DEPRECATED;
} SpaceNla;
-/* SpaceNla.flag */
+/** #SpaceNla.flag */
typedef enum eSpaceNla_Flag {
SNLA_FLAG_UNUSED_0 = (1 << 0),
SNLA_FLAG_UNUSED_1 = (1 << 1),
@@ -581,7 +581,7 @@ typedef struct SequencerPreviewOverlay {
char _pad0[4];
} SequencerPreviewOverlay;
-/* SequencerPreviewOverlay.flag */
+/** #SequencerPreviewOverlay.flag */
typedef enum eSpaceSeq_SequencerPreviewOverlay_Flag {
SEQ_PREVIEW_SHOW_2D_CURSOR = (1 << 1),
SEQ_PREVIEW_SHOW_OUTLINE_SELECTED = (1 << 2),
@@ -596,7 +596,7 @@ typedef struct SequencerTimelineOverlay {
char _pad0[4];
} SequencerTimelineOverlay;
-/* SequencerTimelineOverlay.flag */
+/** #SequencerTimelineOverlay.flag */
typedef enum eSpaceSeq_SequencerTimelineOverlay_Flag {
SEQ_TIMELINE_SHOW_STRIP_OFFSETS = (1 << 1),
SEQ_TIMELINE_SHOW_THUMBNAILS = (1 << 2),
@@ -617,7 +617,7 @@ typedef struct SpaceSeqRuntime {
struct GHash *last_displayed_thumbnails;
} SpaceSeqRuntime;
-/* Sequencer */
+/** Sequencer. */
typedef struct SpaceSeq {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -667,7 +667,7 @@ typedef struct SpaceSeq {
SpaceSeqRuntime runtime;
} SpaceSeq;
-/* SpaceSeq.mainb */
+/** #SpaceSeq.mainb */
typedef enum eSpaceSeq_RegionType {
SEQ_DRAW_IMG_IMBUF = 1,
SEQ_DRAW_IMG_WAVEFORM = 2,
@@ -675,14 +675,14 @@ typedef enum eSpaceSeq_RegionType {
SEQ_DRAW_IMG_HISTOGRAM = 4,
} eSpaceSeq_RegionType;
-/* SpaceSeq.draw_flag */
+/** #SpaceSeq.draw_flag */
typedef enum eSpaceSeq_DrawFlag {
SEQ_DRAW_BACKDROP = (1 << 0),
SEQ_DRAW_UNUSED_1 = (1 << 1),
SEQ_DRAW_TRANSFORM_PREVIEW = (1 << 2),
} eSpaceSeq_DrawFlag;
-/* SpaceSeq.flag */
+/** #SpaceSeq.flag */
typedef enum eSpaceSeq_Flag {
SEQ_DRAWFRAMES = (1 << 0),
SEQ_MARKER_TRANS = (1 << 1),
@@ -703,14 +703,14 @@ typedef enum eSpaceSeq_Flag {
SEQ_SHOW_GRID = (1 << 18),
} eSpaceSeq_Flag;
-/* SpaceSeq.view */
+/** #SpaceSeq.view */
typedef enum eSpaceSeq_Displays {
SEQ_VIEW_SEQUENCE = 1,
SEQ_VIEW_PREVIEW = 2,
SEQ_VIEW_SEQUENCE_PREVIEW = 3,
} eSpaceSeq_Dispays;
-/* SpaceSeq.render_size */
+/** #SpaceSeq.render_size */
typedef enum eSpaceSeq_Proxy_RenderSize {
SEQ_RENDER_SIZE_NONE = -1,
SEQ_RENDER_SIZE_SCENE = 0,
@@ -740,7 +740,7 @@ enum {
SEQ_GIZMO_HIDE_TOOL = (1 << 3),
};
-/* SpaceSeq.mainb */
+/** #SpaceSeq.mainb */
typedef enum eSpaceSeq_OverlayFrameType {
SEQ_OVERLAY_FRAME_TYPE_RECT = 0,
SEQ_OVERLAY_FRAME_TYPE_REFERENCE = 1,
@@ -753,7 +753,7 @@ typedef enum eSpaceSeq_OverlayFrameType {
/** \name File Selector
* \{ */
-/* Config and Input for File Selector */
+/** Config and Input for File Selector. */
typedef struct FileSelectParams {
/** Title, also used for the text of the execute button. */
char title[96];
@@ -857,7 +857,7 @@ typedef struct FileFolderHistory {
ListBase folders_next;
} FileFolderHistory;
-/* File Browser */
+/** File Browser. */
typedef struct SpaceFile {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -921,7 +921,7 @@ typedef struct SpaceFile {
SpaceFile_Runtime *runtime;
} SpaceFile;
-/* SpaceFile.browse_mode (File Space Browsing Mode) */
+/** #SpaceFile.browse_mode (File Space Browsing Mode). */
typedef enum eFileBrowse_Mode {
/* Regular Blender File Browser */
FILE_BROWSE_MODE_FILES = 0,
@@ -929,7 +929,7 @@ typedef enum eFileBrowse_Mode {
FILE_BROWSE_MODE_ASSETS = 1,
} eFileBrowse_Mode;
-/* FileSelectParams.display */
+/** #FileSelectParams.display */
enum eFileDisplayType {
/** Internal (not exposed to users): Keep whatever display type was used during the last File
* Browser use, or the default if no such record is found. Use this unless there's a good reason
@@ -943,7 +943,7 @@ enum eFileDisplayType {
FILE_IMGDISPLAY = 3,
};
-/* FileSelectParams.sort */
+/** #FileSelectParams.sort */
enum eFileSortType {
/** Internal (not exposed to users): Sort by whatever was sorted by during the last File Browser
* use, or the default if no such record is found. Use this unless there's a good reason to set a
@@ -958,14 +958,14 @@ enum eFileSortType {
FILE_SORT_SIZE = 4,
};
-/* SpaceFile.tags */
+/** #SpaceFile.tags */
enum eFileTags {
/** Tag the space as having to update files representing or containing main data. Must be set
* after file read and undo/redo. */
FILE_TAG_REBUILD_MAIN_FILES = (1 << 0),
};
-/* FileSelectParams.details_flags */
+/** #FileSelectParams.details_flags */
enum eFileDetails {
FILE_DETAILS_SIZE = (1 << 0),
FILE_DETAILS_DATETIME = (1 << 1),
@@ -986,7 +986,7 @@ enum eFileDetails {
*/
#define FILE_SELECT_MAX_RECURSIONS (FILE_MAX_LIBEXTRA / 2)
-/* filesel types */
+/** Filesel types. */
typedef enum eFileSelectType {
FILE_LOADLIB = 1,
FILE_MAIN = 2,
@@ -1000,14 +1000,14 @@ typedef enum eFileSelectType {
FILE_SPECIAL = 9,
} eFileSelectType;
-/* filesel op property -> action */
+/** filesel op property -> action. */
typedef enum eFileSel_Action {
FILE_OPENFILE = 0,
FILE_SAVE = 1,
} eFileSel_Action;
-/* sfile->params->flag */
/**
+ * #FileSelectParams.flag / `sfile->params->flag`.
* \note short flag, also used as 16 lower bits of flags in link/append code
* (WM and BLO code area, see #eBLOLibLinkFlags in BLO_readfile.h).
*/
@@ -1037,8 +1037,10 @@ typedef enum eFileSel_Params_AssetCatalogVisibility {
FILE_SHOW_ASSETS_WITHOUT_CATALOG,
} eFileSel_Params_AssetCatalogVisibility;
-/* sfile->params->rename_flag */
-/* NOTE: short flag. Defined as bitflags, but currently only used as exclusive status markers... */
+/**
+ * #FileSelectParams.rename_flag / `sfile->params->rename_flag`.
+ * \note short flag. Defined as bit-flags, but currently only used as exclusive status markers.
+ */
typedef enum eFileSel_Params_RenameFlag {
/** Used when we only have the name of the entry we want to rename,
* but not yet access to its matching file entry. */
@@ -1084,7 +1086,7 @@ typedef enum eFileSel_File_Types {
FILE_TYPE_BLENDERLIB = (1u << 31),
} eFileSel_File_Types;
-/* Selection Flags in filesel: struct direntry, unsigned char selflag */
+/** Selection Flags in filesel: struct direntry, unsigned char selflag. */
typedef enum eDirEntry_SelectFlag {
/* FILE_SEL_ACTIVE = (1 << 1), */ /* UNUSED */
FILE_SEL_HIGHLIGHTED = (1 << 2),
@@ -1156,7 +1158,7 @@ typedef struct FileDirEntryArr {
char root[1024];
} FileDirEntryArr;
-/* FileDirEntry.flags */
+/** #FileDirEntry.flags */
enum {
/* The preview for this entry could not be generated. */
FILE_ENTRY_INVALID_PREVIEW = 1 << 0,
@@ -1243,7 +1245,7 @@ typedef struct SpaceImage {
SpaceImageOverlay overlay;
} SpaceImage;
-/* SpaceImage.dt_uv */
+/** #SpaceImage.dt_uv */
typedef enum eSpaceImage_UVDT {
SI_UVDT_OUTLINE = 0,
SI_UVDT_DASH = 1,
@@ -1251,20 +1253,20 @@ typedef enum eSpaceImage_UVDT {
SI_UVDT_WHITE = 3,
} eSpaceImage_UVDT;
-/* SpaceImage.dt_uvstretch */
+/** #SpaceImage.dt_uvstretch */
typedef enum eSpaceImage_UVDT_Stretch {
SI_UVDT_STRETCH_ANGLE = 0,
SI_UVDT_STRETCH_AREA = 1,
} eSpaceImage_UVDT_Stretch;
-/* SpaceImage.pixel_snap_mode */
+/** #SpaceImage.pixel_snap_mode */
typedef enum eSpaceImage_PixelSnapMode {
SI_PIXEL_SNAP_DISABLED = 0,
SI_PIXEL_SNAP_CENTER = 1,
SI_PIXEL_SNAP_CORNER = 2,
} eSpaceImage_Snap_Mode;
-/* SpaceImage.mode */
+/** #SpaceImage.mode */
typedef enum eSpaceImage_Mode {
SI_MODE_VIEW = 0,
SI_MODE_PAINT = 1,
@@ -1281,7 +1283,7 @@ typedef enum eSpaceImage_Sticky {
SI_STICKY_VERTEX = 2,
} eSpaceImage_Sticky;
-/* SpaceImage.flag */
+/** #SpaceImage.flag */
typedef enum eSpaceImage_Flag {
SI_FLAG_UNUSED_0 = (1 << 0), /* cleared */
SI_FLAG_UNUSED_1 = (1 << 1), /* cleared */
@@ -1375,7 +1377,7 @@ typedef struct SpaceText_Runtime {
} SpaceText_Runtime;
-/* Text Editor */
+/** Text Editor. */
typedef struct SpaceText {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -1425,7 +1427,7 @@ typedef struct SpaceText {
SpaceText_Runtime runtime;
} SpaceText;
-/* SpaceText flags (moved from DNA_text_types.h) */
+/** SpaceText flags (moved from DNA_text_types.h). */
typedef enum eSpaceText_Flags {
/* scrollable */
ST_SCROLL_SELECT = (1 << 0),
@@ -1449,7 +1451,7 @@ typedef enum eSpaceText_Flags {
/** \name Script View (Obsolete)
* \{ */
-/* Script Runtime Data - Obsolete (pre 2.5) */
+/** Script Runtime Data - Obsolete (pre 2.5). */
typedef struct Script {
ID id;
@@ -1474,7 +1476,7 @@ typedef struct Script {
_script->py_globaldict = NULL; \
_script->flags = 0
-/* Script View - Obsolete (pre 2.5) */
+/** Script View - Obsolete (pre 2.5). */
typedef struct SpaceScript {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -1584,7 +1586,7 @@ typedef struct SpaceNode {
SpaceNode_Runtime *runtime;
} SpaceNode;
-/* SpaceNode.flag */
+/** #SpaceNode.flag */
typedef enum eSpaceNode_Flag {
SNODE_BACKDRAW = (1 << 1),
SNODE_SHOW_GPENCIL = (1 << 2),
@@ -1602,7 +1604,7 @@ typedef enum eSpaceNode_Flag {
SNODE_SKIP_INSOFFSET = (1 << 13),
} eSpaceNode_Flag;
-/* SpaceNode.texfrom */
+/** #SpaceNode.texfrom */
typedef enum eSpaceNode_TexFrom {
/* SNODE_TEX_OBJECT = 0, */
SNODE_TEX_WORLD = 1,
@@ -1610,14 +1612,14 @@ typedef enum eSpaceNode_TexFrom {
SNODE_TEX_LINESTYLE = 3,
} eSpaceNode_TexFrom;
-/* SpaceNode.shaderfrom */
+/** #SpaceNode.shaderfrom */
typedef enum eSpaceNode_ShaderFrom {
SNODE_SHADER_OBJECT = 0,
SNODE_SHADER_WORLD = 1,
SNODE_SHADER_LINESTYLE = 2,
} eSpaceNode_ShaderFrom;
-/* SpaceNode.insert_ofs_dir */
+/** #SpaceNode.insert_ofs_dir */
enum {
SNODE_INSERTOFS_DIR_RIGHT = 0,
SNODE_INSERTOFS_DIR_LEFT = 1,
@@ -1629,7 +1631,7 @@ enum {
/** \name Console
* \{ */
-/* Console content */
+/** Console content. */
typedef struct ConsoleLine {
struct ConsoleLine *next, *prev;
@@ -1645,7 +1647,7 @@ typedef struct ConsoleLine {
int type;
} ConsoleLine;
-/* ConsoleLine.type */
+/** #ConsoleLine.type */
typedef enum eConsoleLine_Type {
CONSOLE_LINE_OUTPUT = 0,
CONSOLE_LINE_INPUT = 1,
@@ -1653,7 +1655,7 @@ typedef enum eConsoleLine_Type {
CONSOLE_LINE_ERROR = 3,
} eConsoleLine_Type;
-/* Console View */
+/** Console View. */
typedef struct SpaceConsole {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -1707,7 +1709,7 @@ typedef struct SpaceUserPref {
/** \name Motion Tracking
* \{ */
-/* Clip Editor */
+/** Clip Editor. */
typedef struct SpaceClip {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -1770,7 +1772,7 @@ typedef struct SpaceClip {
MaskSpaceInfo mask_info;
} SpaceClip;
-/* SpaceClip.flag */
+/** #SpaceClip.flag */
typedef enum eSpaceClip_Flag {
SC_SHOW_MARKER_PATTERN = (1 << 0),
SC_SHOW_MARKER_SEARCH = (1 << 1),
@@ -1797,7 +1799,7 @@ typedef enum eSpaceClip_Flag {
SC_SHOW_METADATA = (1 << 22),
} eSpaceClip_Flag;
-/* SpaceClip.mode */
+/** #SpaceClip.mode */
typedef enum eSpaceClip_Mode {
SC_MODE_TRACKING = 0,
// SC_MODE_RECONSTRUCTION = 1, /* DEPRECATED */
@@ -1805,14 +1807,14 @@ typedef enum eSpaceClip_Mode {
SC_MODE_MASKEDIT = 3,
} eSpaceClip_Mode;
-/* SpaceClip.view */
+/** #SpaceClip.view */
typedef enum eSpaceClip_View {
SC_VIEW_CLIP = 0,
SC_VIEW_GRAPH = 1,
SC_VIEW_DOPESHEET = 2,
} eSpaceClip_View;
-/* SpaceClip.gpencil_src */
+/** #SpaceClip.gpencil_src */
typedef enum eSpaceClip_GPencil_Source {
SC_GPENCIL_SRC_CLIP = 0,
SC_GPENCIL_SRC_TRACK = 1,
@@ -2030,8 +2032,10 @@ typedef enum eSpreadsheetColumnValueType {
/** \name Space Defines (eSpace_Type)
* \{ */
-/* space types, moved from DNA_screen_types.h */
-/* Do NOT change order, append on end. types are hardcoded needed */
+/**
+ * Space types: #SpaceLink.spacetype & #ScrArea.spacetype.
+ * \note Do NOT change order, append on end. types are hardcoded needed.
+ */
typedef enum eSpace_Type {
SPACE_EMPTY = 0,
SPACE_VIEW3D = 1,
diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h
index 2c3cd8eab77..cd19825d29f 100644
--- a/source/blender/makesdna/DNA_texture_types.h
+++ b/source/blender/makesdna/DNA_texture_types.h
@@ -98,8 +98,10 @@ typedef struct CBData {
int cur;
} CBData;
-/* 32 = MAXCOLORBAND */
-/* note that this has to remain a single struct, for UserDef */
+/**
+ * 32 = #MAXCOLORBAND
+ * \note that this has to remain a single struct, for UserDef.
+ */
typedef struct ColorBand {
short tot, cur;
char ipotype, ipotype_hue;
@@ -454,14 +456,14 @@ typedef struct ColorMapping {
/* **************** ColorBand ********************* */
-/* colormode */
+/** color-mode. */
enum {
COLBAND_BLEND_RGB = 0,
COLBAND_BLEND_HSV = 1,
COLBAND_BLEND_HSL = 2,
};
-/* interpolation */
+/** Interpolation. */
enum {
COLBAND_INTERP_LINEAR = 0,
COLBAND_INTERP_EASE = 1,
@@ -470,7 +472,7 @@ enum {
COLBAND_INTERP_CONSTANT = 4,
};
-/* color interpolation */
+/** Color interpolation. */
enum {
COLBAND_HUE_NEAR = 0,
COLBAND_HUE_FAR = 1,
@@ -509,7 +511,7 @@ enum {
/* #define TEX_PD_NOISE_AGE 2 */ /* Deprecated */
/* #define TEX_PD_NOISE_TIME 3 */ /* Deprecated */
-/* color_source */
+/** color_source. */
enum {
TEX_PD_COLOR_CONSTANT = 0,
/* color_source: particles */
diff --git a/source/blender/makesdna/DNA_tracking_types.h b/source/blender/makesdna/DNA_tracking_types.h
index 0e313183300..815fab59876 100644
--- a/source/blender/makesdna/DNA_tracking_types.h
+++ b/source/blender/makesdna/DNA_tracking_types.h
@@ -462,7 +462,7 @@ typedef struct MovieTracking {
MovieTrackingDopesheet dopesheet;
} MovieTracking;
-/* MovieTrackingCamera->distortion_model */
+/** #MovieTrackingCamera.distortion_model */
enum {
TRACKING_DISTORTION_MODEL_POLYNOMIAL = 0,
TRACKING_DISTORTION_MODEL_DIVISION = 1,
@@ -470,13 +470,13 @@ enum {
TRACKING_DISTORTION_MODEL_BROWN = 3,
};
-/* MovieTrackingCamera->units */
+/** #MovieTrackingCamera.units */
enum {
CAMERA_UNITS_PX = 0,
CAMERA_UNITS_MM = 1,
};
-/* MovieTrackingMarker->flag */
+/** #MovieTrackingMarker.flag */
enum {
MARKER_DISABLED = (1 << 0),
MARKER_TRACKED = (1 << 1),
@@ -485,7 +485,7 @@ enum {
MARKER_GRAPH_SEL = (MARKER_GRAPH_SEL_X | MARKER_GRAPH_SEL_Y),
};
-/* MovieTrackingTrack->flag */
+/** #MovieTrackingTrack.flag */
enum {
TRACK_HAS_BUNDLE = (1 << 1),
TRACK_DISABLE_RED = (1 << 2),
@@ -501,7 +501,7 @@ enum {
TRACK_USE_2D_STAB_ROT = (1 << 12),
};
-/* MovieTrackingTrack->motion_model */
+/** #MovieTrackingTrack.motion_model */
enum {
TRACK_MOTION_MODEL_TRANSLATION = 0,
TRACK_MOTION_MODEL_TRANSLATION_ROTATION = 1,
@@ -511,27 +511,27 @@ enum {
TRACK_MOTION_MODEL_HOMOGRAPHY = 5,
};
-/* MovieTrackingTrack->algorithm_flag */
+/** #MovieTrackingTrack.algorithm_flag */
enum {
TRACK_ALGORITHM_FLAG_USE_BRUTE = (1 << 0),
TRACK_ALGORITHM_FLAG_USE_NORMALIZATION = (1 << 2),
TRACK_ALGORITHM_FLAG_USE_MASK = (1 << 3),
};
-/* MovieTrackingTrack->pattern_match */
+/** #MovieTrackingTrack.pattern_match */
typedef enum eTrackFrameMatch {
TRACK_MATCH_KEYFRAME = 0,
TRACK_MATCH_PREVIOS_FRAME = 1,
} eTrackFrameMatch;
-/* MovieTrackingSettings->motion_flag */
+/** #MovieTrackingSettings.motion_flag */
enum {
TRACKING_MOTION_TRIPOD = (1 << 0),
TRACKING_MOTION_MODAL = (TRACKING_MOTION_TRIPOD),
};
-/* MovieTrackingSettings->speed */
+/** #MovieTrackingSettings.speed */
enum {
TRACKING_SPEED_FASTEST = 0,
TRACKING_SPEED_REALTIME = 1,
@@ -540,13 +540,13 @@ enum {
TRACKING_SPEED_DOUBLE = 5,
};
-/* MovieTrackingSettings->reconstruction_flag */
+/** #MovieTrackingSettings.reconstruction_flag */
enum {
/* TRACKING_USE_FALLBACK_RECONSTRUCTION = (1 << 0), */ /* DEPRECATED */
TRACKING_USE_KEYFRAME_SELECTION = (1 << 1),
};
-/* MovieTrackingSettings->refine_camera_intrinsics */
+/** #MovieTrackingSettings.refine_camera_intrinsics */
enum {
REFINE_NO_INTRINSICS = (0),
@@ -556,7 +556,7 @@ enum {
REFINE_TANGENTIAL_DISTORTION = (1 << 3),
};
-/* MovieTrackingStabilization->flag */
+/** #MovieTrackingStabilization.flag */
enum {
TRACKING_2D_STABILIZATION = (1 << 0),
TRACKING_AUTOSCALE = (1 << 1),
@@ -565,19 +565,19 @@ enum {
TRACKING_SHOW_STAB_TRACKS = (1 << 5),
};
-/* MovieTrackingStabilization->filter */
+/** #MovieTrackingStabilization.filter */
enum {
TRACKING_FILTER_NEAREST = 0,
TRACKING_FILTER_BILINEAR = 1,
TRACKING_FILTER_BICUBIC = 2,
};
-/* MovieTrackingReconstruction->flag */
+/** #MovieTrackingReconstruction.flag */
enum {
TRACKING_RECONSTRUCTED = (1 << 0),
};
-/* MovieTrackingObject->flag */
+/** #MovieTrackingObject.flag */
enum {
TRACKING_OBJECT_CAMERA = (1 << 0),
};
@@ -588,7 +588,7 @@ enum {
TRACKING_CLEAN_DELETE_SEGMENT = 2,
};
-/* MovieTrackingDopesheet->sort_method */
+/** #MovieTrackingDopesheet.sort_method */
enum {
TRACKING_DOPE_SORT_NAME = 0,
TRACKING_DOPE_SORT_LONGEST = 1,
@@ -598,27 +598,27 @@ enum {
TRACKING_DOPE_SORT_END = 5,
};
-/* MovieTrackingDopesheet->flag */
+/** #MovieTrackingDopesheet.flag */
enum {
TRACKING_DOPE_SORT_INVERSE = (1 << 0),
TRACKING_DOPE_SELECTED_ONLY = (1 << 1),
TRACKING_DOPE_SHOW_HIDDEN = (1 << 2),
};
-/* MovieTrackingDopesheetCoverageSegment->trackness */
+/** #MovieTrackingDopesheetCoverageSegment.trackness */
enum {
TRACKING_COVERAGE_BAD = 0,
TRACKING_COVERAGE_ACCEPTABLE = 1,
TRACKING_COVERAGE_OK = 2,
};
-/* MovieTrackingPlaneMarker->flag */
+/** #MovieTrackingPlaneMarker.flag */
enum {
PLANE_MARKER_DISABLED = (1 << 0),
PLANE_MARKER_TRACKED = (1 << 1),
};
-/* MovieTrackingPlaneTrack->flag */
+/** #MovieTrackingPlaneTrack.flag */
enum {
PLANE_TRACK_HIDDEN = (1 << 1),
PLANE_TRACK_LOCKED = (1 << 2),
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index c8fdac19b61..c99651f0717 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -30,7 +30,8 @@
extern "C" {
#endif
-/* themes; defines in BIF_resource.h */
+/* Themes; defines in `BIF_resource.h`. */
+
struct ColorBand;
/* ************************ style definitions ******************** */
@@ -50,8 +51,10 @@ typedef enum eUIFont_ID {
/* UIFONT_CUSTOM2 = 3, */ /* UNUSED */
} eUIFont_ID;
-/* default fonts to load/initialize */
-/* first font is the default (index 0), others optional */
+/**
+ * Default fonts to load/initialize.
+ * First font is the default (index 0), others optional.
+ */
typedef struct uiFont {
struct uiFont *next, *prev;
/** 1024 = FILE_MAX. */
@@ -445,7 +448,7 @@ typedef enum eBackgroundGradientTypes {
TH_BACKGROUND_GRADIENT_RADIAL = 2,
} eBackgroundGradientTypes;
-/* set of colors for use as a custom color set for Objects/Bones wire drawing */
+/** Set of colors for use as a custom color set for Objects/Bones wire drawing. */
typedef struct ThemeWireColor {
unsigned char solid[4];
unsigned char select[4];
@@ -959,7 +962,7 @@ typedef struct UserDef {
UserDef_Runtime runtime;
} UserDef;
-/* from blenkernel blender.c */
+/** From blenkernel `blender.c`. */
extern UserDef U;
/* ***************** USERDEF ****************** */
diff --git a/source/blender/makesdna/DNA_view2d_types.h b/source/blender/makesdna/DNA_view2d_types.h
index f8166305fd9..6c03422963d 100644
--- a/source/blender/makesdna/DNA_view2d_types.h
+++ b/source/blender/makesdna/DNA_view2d_types.h
@@ -31,7 +31,7 @@ extern "C" {
/* ---------------------------------- */
-/* View 2D data - stored per region */
+/** View 2D data - stored per region. */
typedef struct View2D {
/** Tot - area that data can be drawn in; cur - region of tot that is visible in viewport. */
rctf tot, cur;
@@ -83,7 +83,7 @@ typedef struct View2D {
/* ---------------------------------- */
-/* view zooming restrictions, per axis (v2d->keepzoom) */
+/** View zooming restrictions, per axis (#View2D.keepzoom) */
enum {
/* zoom is clamped to lie within limits set by minzoom and maxzoom */
V2D_LIMITZOOM = (1 << 0),
@@ -97,7 +97,7 @@ enum {
V2D_LOCKZOOM_Y = (1 << 9),
};
-/* view panning restrictions, per axis (v2d->keepofs) */
+/** View panning restrictions, per axis (#View2D.keepofs). */
enum {
/* panning on x-axis is not allowed */
V2D_LOCKOFS_X = (1 << 1),
@@ -109,7 +109,7 @@ enum {
V2D_KEEPOFS_Y = (1 << 4),
};
-/* view extent restrictions (v2d->keeptot) */
+/** View extent restrictions (#View2D.keeptot). */
enum {
/** 'cur' view can be out of extents of 'tot' */
V2D_KEEPTOT_FREE = 0,
@@ -120,7 +120,7 @@ enum {
V2D_KEEPTOT_STRICT = 2,
};
-/* general refresh settings (v2d->flag) */
+/** General refresh settings (#View2D.flag). */
enum {
/* global view2d horizontal locking (for showing same time interval) */
/* TODO: this flag may be set in old files but is not accessible currently,
@@ -138,7 +138,7 @@ enum {
V2D_IS_INIT = (1 << 10),
};
-/* scroller flags for View2D (v2d->scroll) */
+/** Scroller flags for View2D (#View2D.scroll). */
enum {
/* left scrollbar */
V2D_SCROLL_LEFT = (1 << 0),
@@ -162,13 +162,15 @@ enum {
V2D_SCROLL_HORIZONTAL_FULLR = (1 << 10),
};
-/* scroll_ui, activate flag for drawing */
+/** scroll_ui, activate flag for drawing. */
enum {
V2D_SCROLL_H_ACTIVE = (1 << 0),
V2D_SCROLL_V_ACTIVE = (1 << 1),
};
-/* alignment flags for totrect, flags use 'shading-out' convention (v2d->align) */
+/**
+ * Alignment flags for `totrect`, flags use 'shading-out' convention (#View2D.align).
+ */
enum {
/* all quadrants free */
V2D_ALIGN_FREE = 0,
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 3fd2f1208dd..5f4353b6f3a 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -245,7 +245,7 @@ typedef struct View3DOverlay {
char _pad[4];
} View3DOverlay;
-/* View3DOverlay->handle_display */
+/** #View3DOverlay.handle_display */
typedef enum eHandleDisplay {
/* Display only selected points. */
CURVE_HANDLE_SELECTED = 0,
diff --git a/source/blender/makesdna/DNA_volume_types.h b/source/blender/makesdna/DNA_volume_types.h
index 1344f295ea9..df5a122faaf 100644
--- a/source/blender/makesdna/DNA_volume_types.h
+++ b/source/blender/makesdna/DNA_volume_types.h
@@ -30,13 +30,13 @@ struct PackedFile;
struct VolumeGridVector;
typedef struct Volume_Runtime {
- /* OpenVDB Grids */
+ /** OpenVDB Grids. */
struct VolumeGridVector *grids;
- /* Current frame in sequence for evaluated volume */
+ /** Current frame in sequence for evaluated volume. */
int frame;
- /* Default simplify level for volume grids loaded from files. */
+ /** Default simplify level for volume grids loaded from files. */
int default_simplify_level;
} Volume_Runtime;
@@ -96,12 +96,12 @@ typedef struct Volume {
Volume_Runtime runtime;
} Volume;
-/* Volume.flag */
+/** #Volume.flag */
enum {
VO_DS_EXPAND = (1 << 0),
};
-/* Volume.sequence_mode */
+/** #Volume.sequence_mode */
typedef enum VolumeSequenceMode {
VOLUME_SEQUENCE_CLIP = 0,
VOLUME_SEQUENCE_EXTEND = 1,
@@ -109,7 +109,7 @@ typedef enum VolumeSequenceMode {
VOLUME_SEQUENCE_PING_PONG = 3,
} VolumeSequenceMode;
-/* VolumeDisplay.wireframe_type */
+/** #VolumeDisplay.wireframe_type */
typedef enum VolumeWireframeType {
VOLUME_WIREFRAME_NONE = 0,
VOLUME_WIREFRAME_BOUNDS = 1,
@@ -117,32 +117,32 @@ typedef enum VolumeWireframeType {
VOLUME_WIREFRAME_POINTS = 3,
} VolumeWireframeType;
-/* VolumeDisplay.wireframe_detail */
+/** #VolumeDisplay.wireframe_detail */
typedef enum VolumeWireframeDetail {
VOLUME_WIREFRAME_COARSE = 0,
VOLUME_WIREFRAME_FINE = 1,
} VolumeWireframeDetail;
-/* VolumeRender.space */
+/** #VolumeRender.space */
typedef enum VolumeRenderSpace {
VOLUME_SPACE_OBJECT = 0,
VOLUME_SPACE_WORLD = 1,
} VolumeRenderSpace;
-/* VolumeDisplay.interpolation_method */
+/** #VolumeDisplay.interpolation_method */
typedef enum VolumeDisplayInterpMethod {
VOLUME_DISPLAY_INTERP_LINEAR = 0,
VOLUME_DISPLAY_INTERP_CUBIC = 1,
VOLUME_DISPLAY_INTERP_CLOSEST = 2,
} VolumeDisplayInterpMethod;
-/* VolumeDisplay.axis_slice_method */
+/** #VolumeDisplay.axis_slice_method */
typedef enum AxisAlignedSlicingMethod {
VOLUME_AXIS_SLICE_FULL = 0,
VOLUME_AXIS_SLICE_SINGLE = 1,
} AxisAlignedSlicingMethod;
-/* VolumeDisplay.slice_axis */
+/** #VolumeDisplay.slice_axis */
typedef enum SliceAxis {
VOLUME_SLICE_AXIS_AUTO = 0,
VOLUME_SLICE_AXIS_X = 1,
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index 841edaf8724..d0e4184d2a5 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -33,7 +33,8 @@
extern "C" {
#endif
-/* defined here: */
+/* Defined here: */
+
struct wmWindow;
struct wmWindowManager;
@@ -45,7 +46,8 @@ struct wmMsgBus;
struct wmOperator;
struct wmOperatorType;
-/* forwards */
+/* Forward declarations: */
+
struct PointerRNA;
struct Report;
struct ReportList;
@@ -58,7 +60,7 @@ struct wmTimer;
#define OP_MAX_TYPENAME 64
#define KMAP_MAX_NAME 64
-/* keep in sync with 'rna_enum_wm_report_items' in wm_rna.c */
+/** Keep in sync with 'rna_enum_wm_report_items' in `wm_rna.c`. */
typedef enum eReportType {
RPT_DEBUG = (1 << 0),
RPT_INFO = (1 << 1),
@@ -100,7 +102,9 @@ typedef struct Report {
const char *message;
} Report;
-/* saved in the wm, don't remove */
+/**
+ * \note Saved in the wm, don't remove.
+ */
typedef struct ReportList {
ListBase list;
/** eReportType. */
@@ -133,7 +137,7 @@ typedef struct wmXrData {
/* reports need to be before wmWindowManager */
-/* windowmanager is saved, tag WMAN */
+/** Window-manager is saved, tag WMAN. */
typedef struct wmWindowManager {
ID id;
@@ -204,13 +208,13 @@ typedef struct wmWindowManager {
//#endif
} wmWindowManager;
-/* wmWindowManager.initialized */
+/** #wmWindowManager.initialized */
enum {
WM_WINDOW_IS_INIT = (1 << 0),
WM_KEYCONFIG_IS_INIT = (1 << 1),
};
-/* wmWindowManager.outliner_sync_select_dirty */
+/** #wmWindowManager.outliner_sync_select_dirty */
enum {
WM_OUTLINER_SYNC_SELECT_FROM_OBJECT = (1 << 0),
WM_OUTLINER_SYNC_SELECT_FROM_EDIT_BONE = (1 << 1),
@@ -231,7 +235,9 @@ enum {
# endif
#endif
-/* the saveable part, rest of data is local in ghostwinlay */
+/**
+ * The saveable part, the rest of the data is local in GHOST.
+ */
typedef struct wmWindow {
struct wmWindow *next, *prev;
@@ -352,7 +358,9 @@ typedef struct wmOperatorTypeMacro {
struct PointerRNA *ptr;
} wmOperatorTypeMacro;
-/* Partial copy of the event, for matching by event handler. */
+/**
+ * Partial copy of the event, for matching by event handler.
+ */
typedef struct wmKeyMapItem {
struct wmKeyMapItem *next, *prev;
@@ -436,7 +444,9 @@ enum {
KMI_TYPE_NDOF = 5,
};
-/* stored in WM, the actively used keymaps */
+/**
+ * Stored in WM, the actively used key-maps.
+ */
typedef struct wmKeyMap {
struct wmKeyMap *next, *prev;
diff --git a/source/blender/makesdna/DNA_workspace_types.h b/source/blender/makesdna/DNA_workspace_types.h
index a0856588a58..95530c7b0f7 100644
--- a/source/blender/makesdna/DNA_workspace_types.h
+++ b/source/blender/makesdna/DNA_workspace_types.h
@@ -60,7 +60,9 @@ typedef struct bToolRef_Runtime {
int flag;
} bToolRef_Runtime;
-/* Stored per mode. */
+/**
+ * \note Stored per mode.
+ */
typedef struct bToolRef {
struct bToolRef *next, *prev;
char idname[64];
diff --git a/source/blender/makesdna/intern/dna_utils.h b/source/blender/makesdna/intern/dna_utils.h
index b89c45a7a43..7ba71fb970b 100644
--- a/source/blender/makesdna/intern/dna_utils.h
+++ b/source/blender/makesdna/intern/dna_utils.h
@@ -60,7 +60,9 @@ char *DNA_elem_id_rename(struct MemArena *mem_arena,
const int elem_src_full_len,
const uint elem_src_full_offset_len);
-/* When requesting version info, support both directions. */
+/**
+ * When requesting version info, support both directions.
+ */
enum eDNA_RenameDir {
DNA_RENAME_STATIC_FROM_ALIAS = -1,
DNA_RENAME_ALIAS_FROM_STATIC = 1,
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index 5c12fc3a227..091b457cc83 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -321,7 +321,7 @@ static void rna_ColorRamp_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *
CMP_NODE_VALTORGB,
TEX_NODE_VALTORGB,
GEO_NODE_LEGACY_ATTRIBUTE_COLOR_RAMP)) {
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
}
break;
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index a38bbd3d6d2..d3175c445a9 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -388,6 +388,7 @@ void rna_DriverVariable_name_set(PointerRNA *ptr, const char *value)
BLI_strncpy_utf8(data->name, value, 64);
driver_variable_name_validate(data);
+ driver_variable_unique_name(data);
}
/* ----------- */
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index 2f42e521b52..0d86572357f 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -168,7 +168,7 @@ static void rna_ImageUser_update(Main *bmain, Scene *scene, PointerRNA *ptr)
if (id) {
if (GS(id->name) == ID_NT) {
/* Special update for nodetrees to find parent datablock. */
- ED_node_tag_update_nodetree(bmain, (bNodeTree *)id, NULL);
+ ED_node_tree_propagate_change(NULL, bmain, NULL);
}
else {
/* Update material or texture for render preview. */
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index df0271d81d5..e8f9a0b423b 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -42,6 +42,7 @@
#include "BKE_geometry_set.h"
#include "BKE_image.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_texture.h"
#include "RNA_access.h"
@@ -1219,7 +1220,7 @@ static void rna_NodeTree_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *p
WM_main_add_notifier(NC_NODE | NA_EDITED, NULL);
WM_main_add_notifier(NC_SCENE | ND_NODES, &ntree->id);
- ED_node_tag_update_nodetree(bmain, ntree, NULL);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
static bNode *rna_NodeTree_node_new(bNodeTree *ntree,
@@ -1269,8 +1270,7 @@ static bNode *rna_NodeTree_node_new(bNodeTree *ntree,
}
Main *bmain = CTX_data_main(C);
- ntreeUpdateTree(bmain, ntree);
- nodeUpdate(ntree, node);
+ ED_node_tree_propagate_change(C, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
if (node->type == GEO_NODE_INPUT_SCENE_TIME) {
@@ -1300,7 +1300,7 @@ static void rna_NodeTree_node_remove(bNodeTree *ntree,
RNA_POINTER_INVALIDATE(node_ptr);
- ntreeUpdateTree(bmain, ntree); /* update group node socket links */
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1320,8 +1320,7 @@ static void rna_NodeTree_node_clear(bNodeTree *ntree, Main *bmain, ReportList *r
node = next_node;
}
- ntreeUpdateTree(bmain, ntree);
-
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1400,13 +1399,7 @@ static bNodeLink *rna_NodeTree_link_new(bNodeTree *ntree,
fromsock->flag &= ~SOCK_HIDDEN;
tosock->flag &= ~SOCK_HIDDEN;
- if (tonode) {
- nodeUpdate(ntree, tonode);
- }
-
- ntreeUpdateTree(bmain, ntree);
-
- ED_node_tag_update_nodetree(bmain, ntree, ret->tonode);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
return ret;
@@ -1431,7 +1424,7 @@ static void rna_NodeTree_link_remove(bNodeTree *ntree,
nodeRemLink(ntree, link);
RNA_POINTER_INVALIDATE(link_ptr);
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1450,8 +1443,7 @@ static void rna_NodeTree_link_clear(bNodeTree *ntree, Main *bmain, ReportList *r
link = next_link;
}
- ntreeUpdateTree(bmain, ntree);
-
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1508,7 +1500,7 @@ static bNodeSocket *rna_NodeTree_inputs_new(
bNodeSocket *sock = ntreeAddSocketInterface(ntree, SOCK_IN, type, name);
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
return sock;
@@ -1523,7 +1515,7 @@ static bNodeSocket *rna_NodeTree_outputs_new(
bNodeSocket *sock = ntreeAddSocketInterface(ntree, SOCK_OUT, type, name);
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
return sock;
@@ -1544,8 +1536,7 @@ static void rna_NodeTree_socket_remove(bNodeTree *ntree,
else {
ntreeRemoveSocketInterface(ntree, sock);
- ntreeUpdateTree(bmain, ntree);
- DEG_id_tag_update(&ntree->id, 0);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
}
@@ -1560,7 +1551,7 @@ static void rna_NodeTree_inputs_clear(bNodeTree *ntree, Main *bmain, ReportList
ntreeRemoveSocketInterface(ntree, socket);
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1574,7 +1565,7 @@ static void rna_NodeTree_outputs_clear(bNodeTree *ntree, Main *bmain, ReportList
ntreeRemoveSocketInterface(ntree, socket);
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1603,9 +1594,9 @@ static void rna_NodeTree_inputs_move(bNodeTree *ntree, Main *bmain, int from_ind
}
}
- ntree->update |= NTREE_UPDATE_GROUP_IN;
+ BKE_ntree_update_tag_interface(ntree);
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1634,9 +1625,9 @@ static void rna_NodeTree_outputs_move(bNodeTree *ntree, Main *bmain, int from_in
}
}
- ntree->update |= NTREE_UPDATE_GROUP_OUT;
+ BKE_ntree_update_tag_interface(ntree);
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1644,10 +1635,8 @@ static void rna_NodeTree_interface_update(bNodeTree *ntree, bContext *C)
{
Main *bmain = CTX_data_main(C);
- ntree->update |= NTREE_UPDATE_GROUP;
- ntreeUpdateTree(bmain, ntree);
-
- ED_node_tag_update_nodetree(bmain, ntree, NULL);
+ BKE_ntree_update_tag_interface(ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
/* ******** NodeLink ******** */
@@ -2617,7 +2606,8 @@ static void rna_Node_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNode *node = (bNode *)ptr->data;
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ BKE_ntree_update_tag_node_property(ntree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
static void rna_Node_update_relations(Main *bmain, Scene *scene, PointerRNA *ptr)
@@ -2626,9 +2616,10 @@ static void rna_Node_update_relations(Main *bmain, Scene *scene, PointerRNA *ptr
DEG_relations_tag_update(bmain);
}
-static void rna_Node_socket_value_update(ID *id, bNode *node, bContext *C)
+static void rna_Node_socket_value_update(ID *id, bNode *UNUSED(node), bContext *C)
{
- ED_node_tag_update_nodetree(CTX_data_main(C), (bNodeTree *)id, node);
+ BKE_ntree_update_tag_all((bNodeTree *)id);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), (bNodeTree *)id);
}
static void rna_Node_select_set(PointerRNA *ptr, bool value)
@@ -2682,7 +2673,7 @@ static bNodeSocket *rna_Node_inputs_new(ID *id,
BKE_report(reports, RPT_ERROR, "Unable to create socket");
}
else {
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -2716,7 +2707,7 @@ static bNodeSocket *rna_Node_outputs_new(ID *id,
BKE_report(reports, RPT_ERROR, "Unable to create socket");
}
else {
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -2734,7 +2725,7 @@ static void rna_Node_socket_remove(
else {
nodeRemoveSocket(ntree, node, sock);
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
}
@@ -2749,7 +2740,7 @@ static void rna_Node_inputs_clear(ID *id, bNode *node, Main *bmain)
nodeRemoveSocket(ntree, node, sock);
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -2763,7 +2754,7 @@ static void rna_Node_outputs_clear(ID *id, bNode *node, Main *bmain)
nodeRemoveSocket(ntree, node, sock);
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -2795,7 +2786,7 @@ static void rna_Node_inputs_move(ID *id, bNode *node, Main *bmain, int from_inde
}
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -2827,7 +2818,7 @@ static void rna_Node_outputs_move(ID *id, bNode *node, Main *bmain, int from_ind
}
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -3055,10 +3046,9 @@ static void rna_NodeSocket_update(Main *bmain, Scene *UNUSED(scene), PointerRNA
{
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNodeSocket *sock = (bNodeSocket *)ptr->data;
- bNode *node;
- if (nodeFindNode(ntree, sock, &node, NULL)) {
- ED_node_tag_update_nodetree(bmain, ntree, node);
- }
+
+ BKE_ntree_update_tag_socket_property(ntree, sock);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
static bool rna_NodeSocket_is_output_get(PointerRNA *ptr)
@@ -3351,10 +3341,8 @@ static void rna_NodeSocketInterface_update(Main *bmain, Scene *UNUSED(scene), Po
return;
}
- ntree->update |= NTREE_UPDATE_GROUP;
- ntreeUpdateTree(bmain, ntree);
-
- ED_node_tag_update_nodetree(bmain, ntree, NULL);
+ BKE_ntree_update_tag_interface(ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
/* ******** Standard Node Socket Base Types ******** */
@@ -3452,28 +3440,14 @@ static void rna_NodeSocketStandard_vector_range(
/* using a context update function here, to avoid searching the node if possible */
static void rna_NodeSocketStandard_value_update(struct bContext *C, PointerRNA *ptr)
{
- bNode *node;
-
/* default update */
rna_NodeSocket_update(CTX_data_main(C), CTX_data_scene(C), ptr);
-
- /* try to use node from context, faster */
- node = CTX_data_pointer_get(C, "node").data;
- if (!node) {
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNodeSocket *sock = ptr->data;
-
- /* fall back to searching node in the tree */
- nodeFindNode(ntree, sock, &node, NULL);
- }
}
static void rna_NodeSocketStandard_value_and_relation_update(struct bContext *C, PointerRNA *ptr)
{
rna_NodeSocketStandard_value_update(C, ptr);
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
Main *bmain = CTX_data_main(C);
- ntreeUpdateTree(bmain, ntree);
DEG_relations_tag_update(bmain);
}
@@ -3567,12 +3541,11 @@ static bool rna_NodeInternal_poll_instance(bNode *node, bNodeTree *ntree)
}
}
-static void rna_NodeInternal_update(ID *id, bNode *node)
+static void rna_NodeInternal_update(ID *id, bNode *node, Main *bmain)
{
bNodeTree *ntree = (bNodeTree *)id;
- if (node->typeinfo->updatefunc) {
- node->typeinfo->updatefunc(ntree, node);
- }
+ BKE_ntree_update_tag_node_property(ntree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
static void rna_NodeInternal_draw_buttons(ID *id,
@@ -3721,7 +3694,8 @@ static void rna_Node_tex_image_update(Main *bmain, Scene *UNUSED(scene), Pointer
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNode *node = (bNode *)ptr->data;
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ BKE_ntree_update_tag_node_property(ntree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_IMAGE, NULL);
}
@@ -3730,11 +3704,8 @@ static void rna_NodeGroup_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNode *node = (bNode *)ptr->data;
- if (node->id) {
- ntreeUpdateTree(bmain, (bNodeTree *)node->id);
- }
-
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ BKE_ntree_update_tag_node_property(ntree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
DEG_relations_tag_update(bmain);
}
@@ -4142,13 +4113,12 @@ static const EnumPropertyItem *rna_Node_channel_itemf(bContext *UNUSED(C),
return item;
}
-static void rna_Image_Node_update_id(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_Image_Node_update_id(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNode *node = (bNode *)ptr->data;
node->update |= NODE_UPDATE_ID;
- nodeUpdate(ntree, node); /* to update image node sockets */
+ rna_Node_update(bmain, scene, ptr);
}
static void rna_NodeOutputFile_slots_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
@@ -4395,7 +4365,7 @@ static bNodeSocket *rna_NodeOutputFile_slots_new(
sock = ntreeCompositOutputFileAddSocket(ntree, node, name, im_format);
- ntreeUpdateTree(CTX_data_main(C), ntree);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
return sock;
@@ -4504,42 +4474,27 @@ static void rna_ShaderNodeScript_update(Main *bmain, Scene *scene, PointerRNA *p
RE_engine_free(engine);
}
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ BKE_ntree_update_tag_node_property(ntree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
static void rna_ShaderNode_socket_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNode *node = (bNode *)ptr->data;
-
- nodeUpdate(ntree, node);
rna_Node_update(bmain, scene, ptr);
}
static void rna_Node_socket_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNode *node = (bNode *)ptr->data;
-
- nodeUpdate(ntree, node);
rna_Node_update(bmain, scene, ptr);
}
static void rna_GeometryNode_socket_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNode *node = (bNode *)ptr->data;
-
- nodeUpdate(ntree, node);
rna_Node_update(bmain, scene, ptr);
}
static void rna_CompositorNodeScale_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNode *node = (bNode *)ptr->data;
-
- nodeUpdate(ntree, node);
rna_Node_update(bmain, scene, ptr);
}
@@ -12386,7 +12341,7 @@ static void rna_def_internal_node(BlenderRNA *brna)
func = RNA_def_function(srna, "update", "rna_NodeInternal_update");
RNA_def_function_ui_description(
func, "Update on node graph topology changes (adding or removing nodes and links)");
- RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_ALLOW_WRITE);
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_ALLOW_WRITE);
/* draw buttons */
func = RNA_def_function(srna, "draw_buttons", "rna_NodeInternal_draw_buttons");
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index d05f2a13c4b..5f1d9c5a5ce 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -5583,7 +5583,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
{FFMPEG_MPEG2, "MPEG2", 0, "MPEG-2", ""},
{FFMPEG_MPEG4, "MPEG4", 0, "MPEG-4", ""},
{FFMPEG_AVI, "AVI", 0, "AVI", ""},
- {FFMPEG_MOV, "QUICKTIME", 0, "Quicktime", ""},
+ {FFMPEG_MOV, "QUICKTIME", 0, "QuickTime", ""},
{FFMPEG_DV, "DV", 0, "DV", ""},
{FFMPEG_OGG, "OGG", 0, "Ogg", ""},
{FFMPEG_MKV, "MKV", 0, "Matroska", ""},
diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c
index 5a74cfa9964..f66fb2653b5 100644
--- a/source/blender/makesrna/intern/rna_texture.c
+++ b/source/blender/makesrna/intern/rna_texture.c
@@ -199,7 +199,7 @@ static void rna_Texture_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *pt
}
else if (GS(id->name) == ID_NT) {
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- ED_node_tag_update_nodetree(bmain, ntree, NULL);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
}
diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c
index c81588aa8b5..03f4acdae79 100644
--- a/source/blender/makesrna/intern/rna_tracking.c
+++ b/source/blender/makesrna/intern/rna_tracking.c
@@ -24,6 +24,7 @@
#include "MEM_guardedalloc.h"
#include "BKE_movieclip.h"
+#include "BKE_node_tree_update.h"
#include "BKE_tracking.h"
#include "RNA_access.h"
@@ -415,11 +416,12 @@ static void rna_tracking_stabRotTracks_active_index_range(
*max = max_ii(0, clip->tracking.stabilization.tot_rot_track - 1);
}
-static void rna_tracking_flushUpdate(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
+static void rna_tracking_flushUpdate(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
MovieClip *clip = (MovieClip *)ptr->owner_id;
- nodeUpdateID(scene->nodetree, &clip->id);
+ BKE_ntree_update_tag_id_changed(bmain, &clip->id);
+ BKE_ntree_update_main(bmain, NULL);
WM_main_add_notifier(NC_SCENE | ND_NODES, NULL);
WM_main_add_notifier(NC_SCENE, NULL);
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index dd1252ffebf..929cf94615b 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -2889,7 +2889,7 @@ static void rna_def_userdef_theme_space_node(BlenderRNA *brna)
prop = RNA_def_property(srna, "group_node", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "syntaxc");
- RNA_def_property_array(prop, 4);
+ RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Group Node", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index a3ef26f619f..88ac06b25eb 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -114,7 +114,7 @@ set(SRC
intern/MOD_weightvgedit.c
intern/MOD_weightvgmix.c
intern/MOD_weightvgproximity.c
- intern/MOD_weld.c
+ intern/MOD_weld.cc
intern/MOD_wireframe.c
MOD_modifiertypes.h
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index ec6cbeb43bf..cee5d0be65d 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -60,6 +60,7 @@
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
+#include "BKE_node_tree_update.h"
#include "BKE_object.h"
#include "BKE_pointcloud.h"
#include "BKE_screen.h"
@@ -237,7 +238,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
DEG_add_modifier_to_transform_relation(ctx->node, "Nodes Modifier");
if (nmd->node_group != nullptr) {
- DEG_add_node_tree_relation(ctx->node, nmd->node_group, "Nodes Modifier");
+ DEG_add_node_tree_output_relation(ctx->node, nmd->node_group, "Nodes Modifier");
Set<ID *> used_ids;
find_used_ids_from_settings(nmd->settings, used_ids);
@@ -725,7 +726,7 @@ void MOD_nodes_init(Main *bmain, NodesModifierData *nmd)
group_input_node,
(bNodeSocket *)group_input_node->outputs.first);
- ntreeUpdateTree(bmain, ntree);
+ BKE_ntree_update_main_tree(bmain, ntree, nullptr);
}
static void initialize_group_input(NodesModifierData &nmd,
@@ -1294,7 +1295,7 @@ static void add_attribute_search_button(const bContext &C,
return;
}
- AttributeSearchData *data = OBJECT_GUARDED_NEW(AttributeSearchData);
+ AttributeSearchData *data = MEM_new<AttributeSearchData>(__func__);
data->object_session_uid = object->id.session_uuid;
STRNCPY(data->modifier_name, nmd.modifier.name);
STRNCPY(data->socket_identifier, socket.identifier);
diff --git a/source/blender/modifiers/intern/MOD_weld.c b/source/blender/modifiers/intern/MOD_weld.cc
index f842bef3298..7a7af4e61aa 100644
--- a/source/blender/modifiers/intern/MOD_weld.c
+++ b/source/blender/modifiers/intern/MOD_weld.cc
@@ -35,10 +35,13 @@
#include "BLI_utildefines.h"
-#include "BLI_alloca.h"
+#include "BLI_array.hh"
#include "BLI_bitmap.h"
+#include "BLI_index_range.hh"
#include "BLI_kdtree.h"
#include "BLI_math.h"
+#include "BLI_span.hh"
+#include "BLI_vector.hh"
#include "BLT_translation.h"
@@ -69,127 +72,133 @@
#include "MOD_modifiertypes.h"
#include "MOD_ui_common.h"
+using blender::Array;
+using blender::IndexRange;
+using blender::MutableSpan;
+using blender::Span;
+using blender::Vector;
+
/* Indicates when the element was not computed. */
-#define OUT_OF_CONTEXT (uint)(-1)
+#define OUT_OF_CONTEXT (int)(-1)
/* Indicates if the edge or face will be collapsed. */
-#define ELEM_COLLAPSED (uint)(-2)
+#define ELEM_COLLAPSED (int)(-2)
/* indicates whether an edge or vertex in groups_map will be merged. */
-#define ELEM_MERGED (uint)(-2)
+#define ELEM_MERGED (int)(-2)
/* Used to indicate a range in an array specifying a group. */
struct WeldGroup {
- uint len;
- uint ofs;
+ int len;
+ int ofs;
};
/* Edge groups that will be merged. Final vertices are also indicated. */
struct WeldGroupEdge {
struct WeldGroup group;
- uint v1;
- uint v2;
+ int v1;
+ int v2;
};
-typedef struct WeldVert {
+struct WeldVert {
/* Indexes relative to the original Mesh. */
- uint vert_dest;
- uint vert_orig;
-} WeldVert;
+ int vert_dest;
+ int vert_orig;
+};
-typedef struct WeldEdge {
+struct WeldEdge {
union {
- uint flag;
+ int flag;
struct {
/* Indexes relative to the original Mesh. */
- uint edge_dest;
- uint edge_orig;
- uint vert_a;
- uint vert_b;
+ int edge_dest;
+ int edge_orig;
+ int vert_a;
+ int vert_b;
};
};
-} WeldEdge;
+};
-typedef struct WeldLoop {
+struct WeldLoop {
union {
- uint flag;
+ int flag;
struct {
/* Indexes relative to the original Mesh. */
- uint vert;
- uint edge;
- uint loop_orig;
- uint loop_skip_to;
+ int vert;
+ int edge;
+ int loop_orig;
+ int loop_skip_to;
};
};
-} WeldLoop;
+};
-typedef struct WeldPoly {
+struct WeldPoly {
union {
- uint flag;
+ int flag;
struct {
/* Indexes relative to the original Mesh. */
- uint poly_dst;
- uint poly_orig;
- uint loop_start;
- uint loop_end;
+ int poly_dst;
+ int poly_orig;
+ int loop_start;
+ int loop_end;
/* Final Polygon Size. */
- uint len;
+ int len;
/* Group of loops that will be affected. */
struct WeldGroup loops;
};
};
-} WeldPoly;
+};
-typedef struct WeldMesh {
+struct WeldMesh {
/* Group of vertices to be merged. */
- struct WeldGroup *vert_groups;
- uint *vert_groups_buffer;
+ Array<WeldGroup> vert_groups;
+ Array<int> vert_groups_buffer;
/* Group of edges to be merged. */
- struct WeldGroupEdge *edge_groups;
- uint *edge_groups_buffer;
+ Array<WeldGroupEdge> edge_groups;
+ Array<int> edge_groups_buffer;
/* From the original index of the vertex, this indicates which group it is or is going to be
* merged. */
- uint *edge_groups_map;
+ Array<int> edge_groups_map;
/* References all polygons and loops that will be affected. */
- WeldLoop *wloop;
- WeldPoly *wpoly;
+ Vector<WeldLoop> wloop;
+ Vector<WeldPoly> wpoly;
WeldPoly *wpoly_new;
- uint wloop_len;
- uint wpoly_len;
- uint wpoly_new_len;
+ int wloop_len;
+ int wpoly_len;
+ int wpoly_new_len;
/* From the actual index of the element in the mesh, it indicates what is the index of the Weld
* element above. */
- uint *loop_map;
- uint *poly_map;
+ Array<int> loop_map;
+ Array<int> poly_map;
- uint vert_kill_len;
- uint edge_kill_len;
- uint loop_kill_len;
- uint poly_kill_len; /* Including the new polygons. */
+ int vert_kill_len;
+ int edge_kill_len;
+ int loop_kill_len;
+ int poly_kill_len; /* Including the new polygons. */
/* Size of the affected polygon with more sides. */
- uint max_poly_len;
-} WeldMesh;
-
-typedef struct WeldLoopOfPolyIter {
- uint loop_start;
- uint loop_end;
- const WeldLoop *wloop;
- const MLoop *mloop;
- const uint *loop_map;
+ int max_poly_len;
+};
+
+struct WeldLoopOfPolyIter {
+ int loop_start;
+ int loop_end;
+ Span<WeldLoop> wloop;
+ Span<MLoop> mloop;
+ Span<int> loop_map;
/* Weld group. */
- uint *group;
+ int *group;
- uint l_curr;
- uint l_next;
+ int l_curr;
+ int l_next;
/* Return */
- uint group_len;
- uint v;
- uint e;
+ int group_len;
+ int v;
+ int e;
char type;
-} WeldLoopOfPolyIter;
+};
/* -------------------------------------------------------------------- */
/** \name Debug Utils
@@ -197,22 +206,20 @@ typedef struct WeldLoopOfPolyIter {
#ifdef USE_WELD_DEBUG
static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter,
- const WeldPoly *wp,
- const WeldLoop *wloop,
- const MLoop *mloop,
- const uint *loop_map,
- uint *group_buffer);
+ const WeldPoly &wp,
+ Span<WeldLoop> wloop,
+ Span<MLoop> mloop,
+ Span<int> loop_map,
+ int *group_buffer);
static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter);
-static void weld_assert_edge_kill_len(const WeldEdge *wedge,
- const uint wedge_len,
- const uint supposed_kill_len)
+static void weld_assert_edge_kill_len(Span<WeldEdge> wedge, const int supposed_kill_len)
{
- uint kills = 0;
+ int kills = 0;
const WeldEdge *we = &wedge[0];
- for (uint i = wedge_len; i--; we++) {
- uint edge_dest = we->edge_dest;
+ for (int i = wedge.size(); i--; we++) {
+ int edge_dest = we->edge_dest;
/* Magically includes collapsed edges. */
if (edge_dest != OUT_OF_CONTEXT) {
kills++;
@@ -221,28 +228,25 @@ static void weld_assert_edge_kill_len(const WeldEdge *wedge,
BLI_assert(kills == supposed_kill_len);
}
-static void weld_assert_poly_and_loop_kill_len(const WeldPoly *wpoly,
- const WeldPoly *wpoly_new,
- const uint wpoly_new_len,
- const WeldLoop *wloop,
- const MLoop *mloop,
- const uint *loop_map,
- const uint *poly_map,
- const MPoly *mpoly,
- const uint mpoly_len,
- const uint mloop_len,
- const uint supposed_poly_kill_len,
- const uint supposed_loop_kill_len)
+static void weld_assert_poly_and_loop_kill_len(Span<WeldPoly> wpoly,
+ Span<WeldPoly> wpoly_new,
+ Span<WeldLoop> wloop,
+ Span<MLoop> mloop,
+ Span<int> loop_map,
+ Span<int> poly_map,
+ Span<MPoly> mpoly,
+ const int supposed_poly_kill_len,
+ const int supposed_loop_kill_len)
{
- uint poly_kills = 0;
- uint loop_kills = mloop_len;
+ int poly_kills = 0;
+ int loop_kills = mloop.size();
const MPoly *mp = &mpoly[0];
- for (uint i = 0; i < mpoly_len; i++, mp++) {
- uint poly_ctx = poly_map[i];
+ for (int i = 0; i < mpoly.size(); i++, mp++) {
+ int poly_ctx = poly_map[i];
if (poly_ctx != OUT_OF_CONTEXT) {
const WeldPoly *wp = &wpoly[poly_ctx];
WeldLoopOfPolyIter iter;
- if (!weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) {
+ if (!weld_iter_loop_of_poly_begin(&iter, *wp, wloop, mloop, loop_map, nullptr)) {
poly_kills++;
continue;
}
@@ -251,11 +255,11 @@ static void weld_assert_poly_and_loop_kill_len(const WeldPoly *wpoly,
poly_kills++;
continue;
}
- uint remain = wp->len;
- uint l = wp->loop_start;
+ int remain = wp->len;
+ int l = wp->loop_start;
while (remain) {
- uint l_next = l + 1;
- uint loop_ctx = loop_map[l];
+ int l_next = l + 1;
+ int loop_ctx = loop_map[l];
if (loop_ctx != OUT_OF_CONTEXT) {
const WeldLoop *wl = &wloop[loop_ctx];
if (wl->loop_skip_to != OUT_OF_CONTEXT) {
@@ -279,17 +283,17 @@ static void weld_assert_poly_and_loop_kill_len(const WeldPoly *wpoly,
}
}
- const WeldPoly *wp = &wpoly_new[0];
- for (uint i = wpoly_new_len; i--; wp++) {
+ const WeldPoly *wp = wpoly_new.data();
+ for (int i = wpoly_new.size(); i--; wp++) {
if (wp->poly_dst != OUT_OF_CONTEXT) {
poly_kills++;
continue;
}
- uint remain = wp->len;
- uint l = wp->loop_start;
+ int remain = wp->len;
+ int l = wp->loop_start;
while (remain) {
- uint l_next = l + 1;
- uint loop_ctx = loop_map[l];
+ int l_next = l + 1;
+ int loop_ctx = loop_map[l];
if (loop_ctx != OUT_OF_CONTEXT) {
const WeldLoop *wl = &wloop[loop_ctx];
if (wl->loop_skip_to != OUT_OF_CONTEXT) {
@@ -312,46 +316,46 @@ static void weld_assert_poly_and_loop_kill_len(const WeldPoly *wpoly,
BLI_assert(loop_kills == supposed_loop_kill_len);
}
-static void weld_assert_poly_no_vert_repetition(const WeldPoly *wp,
- const WeldLoop *wloop,
- const MLoop *mloop,
- const uint *loop_map)
+static void weld_assert_poly_no_vert_repetition(const WeldPoly &wp,
+ Span<WeldLoop> wloop,
+ Span<MLoop> mloop,
+ Span<int> loop_map)
{
- const uint len = wp->len;
- uint *verts = BLI_array_alloca(verts, len);
+ const int len = wp.len;
+ Array<int, 64> verts(len);
WeldLoopOfPolyIter iter;
- if (!weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) {
+ if (!weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, nullptr)) {
return;
}
else {
- uint i = 0;
+ int i = 0;
while (weld_iter_loop_of_poly_next(&iter)) {
verts[i++] = iter.v;
}
}
- for (uint i = 0; i < len; i++) {
- uint va = verts[i];
- for (uint j = i + 1; j < len; j++) {
- uint vb = verts[j];
+ for (int i = 0; i < len; i++) {
+ int va = verts[i];
+ for (int j = i + 1; j < len; j++) {
+ int vb = verts[j];
BLI_assert(va != vb);
}
}
}
-static void weld_assert_poly_len(const WeldPoly *wp, const WeldLoop *wloop)
+static void weld_assert_poly_len(const WeldPoly *wp, const Span<WeldLoop> wloop)
{
if (wp->flag == ELEM_COLLAPSED) {
return;
}
- uint len = wp->len;
+ int len = wp->len;
const WeldLoop *wl = &wloop[wp->loops.ofs];
BLI_assert(wp->loop_start <= wl->loop_orig);
- uint end_wloop = wp->loops.ofs + wp->loops.len;
+ int end_wloop = wp->loops.ofs + wp->loops.len;
const WeldLoop *wl_end = &wloop[end_wloop - 1];
- uint min_len = 0;
+ int min_len = 0;
for (; wl <= wl_end; wl++) {
BLI_assert(wl->loop_skip_to == OUT_OF_CONTEXT); /* Not for this case. */
if (wl->flag != ELEM_COLLAPSED) {
@@ -360,7 +364,7 @@ static void weld_assert_poly_len(const WeldPoly *wp, const WeldLoop *wloop)
}
BLI_assert(len >= min_len);
- uint max_len = wp->loop_end - wp->loop_start + 1;
+ int max_len = wp->loop_end - wp->loop_start + 1;
BLI_assert(len <= max_len);
}
@@ -372,92 +376,70 @@ static void weld_assert_poly_len(const WeldPoly *wp, const WeldLoop *wloop)
/** \name Weld Vert API
* \{ */
-static void weld_vert_ctx_alloc_and_setup(const uint mvert_len,
- uint *r_vert_dest_map,
- WeldVert **r_wvert,
- uint *r_wvert_len)
+static Vector<WeldVert> weld_vert_ctx_alloc_and_setup(Span<int> vert_dest_map)
{
- /* Vert Context. */
- uint wvert_len = 0;
-
- WeldVert *wvert, *wv;
- wvert = MEM_mallocN(sizeof(*wvert) * mvert_len, __func__);
- wv = &wvert[0];
-
- uint *v_dest_iter = &r_vert_dest_map[0];
- for (uint i = 0; i < mvert_len; i++, v_dest_iter++) {
- if (*v_dest_iter != OUT_OF_CONTEXT) {
- wv->vert_dest = *v_dest_iter;
- wv->vert_orig = i;
- wv++;
- wvert_len++;
+ Vector<WeldVert> wvert;
+ wvert.reserve(vert_dest_map.size());
+
+ for (const int i : vert_dest_map.index_range()) {
+ if (vert_dest_map[i] != OUT_OF_CONTEXT) {
+ wvert.append({vert_dest_map[i], i});
}
}
-
- *r_wvert = MEM_reallocN(wvert, sizeof(*wvert) * wvert_len);
- *r_wvert_len = wvert_len;
+ return wvert;
}
-static void weld_vert_groups_setup(const uint mvert_len,
- const uint wvert_len,
- const WeldVert *wvert,
- const uint *vert_dest_map,
- uint *r_vert_groups_map,
- uint **r_vert_groups_buffer,
- struct WeldGroup **r_vert_groups)
+static void weld_vert_groups_setup(Span<WeldVert> wvert,
+ Span<int> vert_dest_map,
+ MutableSpan<int> r_vert_groups_map,
+ Array<int> &r_vert_groups_buffer,
+ Array<WeldGroup> &r_vert_groups)
{
/* Get weld vert groups. */
- uint wgroups_len = 0;
- const uint *vert_dest_iter = &vert_dest_map[0];
- uint *group_map_iter = &r_vert_groups_map[0];
- for (uint i = 0; i < mvert_len; i++, group_map_iter++, vert_dest_iter++) {
- uint vert_dest = *vert_dest_iter;
+ int wgroups_len = 0;
+ for (const int i : vert_dest_map.index_range()) {
+ const int vert_dest = vert_dest_map[i];
if (vert_dest != OUT_OF_CONTEXT) {
if (vert_dest != i) {
- *group_map_iter = ELEM_MERGED;
+ r_vert_groups_map[i] = ELEM_MERGED;
}
else {
- *group_map_iter = wgroups_len;
+ r_vert_groups_map[i] = wgroups_len;
wgroups_len++;
}
}
else {
- *group_map_iter = OUT_OF_CONTEXT;
+ r_vert_groups_map[i] = OUT_OF_CONTEXT;
}
}
- struct WeldGroup *wgroups = MEM_callocN(sizeof(*wgroups) * wgroups_len, __func__);
+ r_vert_groups.reinitialize(wgroups_len);
+ r_vert_groups.fill({0, 0});
+ MutableSpan<WeldGroup> wgroups = r_vert_groups;
- const WeldVert *wv = &wvert[0];
- for (uint i = wvert_len; i--; wv++) {
- uint group_index = r_vert_groups_map[wv->vert_dest];
+ for (const WeldVert &wv : wvert) {
+ int group_index = r_vert_groups_map[wv.vert_dest];
wgroups[group_index].len++;
}
- uint ofs = 0;
- struct WeldGroup *wg_iter = &wgroups[0];
- for (uint i = wgroups_len; i--; wg_iter++) {
- wg_iter->ofs = ofs;
- ofs += wg_iter->len;
+ int ofs = 0;
+ for (WeldGroup &wg : wgroups) {
+ wg.ofs = ofs;
+ ofs += wg.len;
}
- BLI_assert(ofs == wvert_len);
+ BLI_assert(ofs == wvert.size());
- uint *groups_buffer = MEM_mallocN(sizeof(*groups_buffer) * ofs, __func__);
- wv = &wvert[0];
- for (uint i = wvert_len; i--; wv++) {
- uint group_index = r_vert_groups_map[wv->vert_dest];
- groups_buffer[wgroups[group_index].ofs++] = wv->vert_orig;
+ r_vert_groups_buffer.reinitialize(ofs);
+ for (const WeldVert &wv : wvert) {
+ int group_index = r_vert_groups_map[wv.vert_dest];
+ r_vert_groups_buffer[wgroups[group_index].ofs++] = wv.vert_orig;
}
- wg_iter = &wgroups[0];
- for (uint i = wgroups_len; i--; wg_iter++) {
- wg_iter->ofs -= wg_iter->len;
+ for (WeldGroup &wg : wgroups) {
+ wg.ofs -= wg.len;
}
-
- *r_vert_groups = wgroups;
- *r_vert_groups_buffer = groups_buffer;
}
/** \} */
@@ -466,31 +448,24 @@ static void weld_vert_groups_setup(const uint mvert_len,
/** \name Weld Edge API
* \{ */
-static void weld_edge_ctx_setup(const uint mvert_len,
- const uint wedge_len,
- struct WeldGroup *r_vlinks,
- uint *r_edge_dest_map,
- WeldEdge *r_wedge,
- uint *r_edge_kiil_len)
+static void weld_edge_ctx_setup(MutableSpan<WeldGroup> r_vlinks,
+ MutableSpan<int> r_edge_dest_map,
+ MutableSpan<WeldEdge> r_wedge,
+ int *r_edge_kiil_len)
{
- WeldEdge *we;
-
/* Setup Edge Overlap. */
- uint edge_kill_len = 0;
+ int edge_kill_len = 0;
- struct WeldGroup *vl_iter, *v_links;
- v_links = r_vlinks;
- vl_iter = &v_links[0];
+ MutableSpan<WeldGroup> v_links = r_vlinks;
- we = &r_wedge[0];
- for (uint i = wedge_len; i--; we++) {
- uint dst_vert_a = we->vert_a;
- uint dst_vert_b = we->vert_b;
+ for (WeldEdge &we : r_wedge) {
+ int dst_vert_a = we.vert_a;
+ int dst_vert_b = we.vert_b;
if (dst_vert_a == dst_vert_b) {
- BLI_assert(we->edge_dest == OUT_OF_CONTEXT);
- r_edge_dest_map[we->edge_orig] = ELEM_COLLAPSED;
- we->flag = ELEM_COLLAPSED;
+ BLI_assert(we.edge_dest == OUT_OF_CONTEXT);
+ r_edge_dest_map[we.edge_orig] = ELEM_COLLAPSED;
+ we.flag = ELEM_COLLAPSED;
edge_kill_len++;
continue;
}
@@ -499,62 +474,60 @@ static void weld_edge_ctx_setup(const uint mvert_len,
v_links[dst_vert_b].len++;
}
- uint link_len = 0;
- vl_iter = &v_links[0];
- for (uint i = mvert_len; i--; vl_iter++) {
- vl_iter->ofs = link_len;
- link_len += vl_iter->len;
+ int link_len = 0;
+ for (WeldGroup &vl : r_vlinks) {
+ vl.ofs = link_len;
+ link_len += vl.len;
}
- if (link_len) {
- uint *link_edge_buffer = MEM_mallocN(sizeof(*link_edge_buffer) * link_len, __func__);
+ if (link_len > 0) {
+ Array<int> link_edge_buffer(link_len);
- we = &r_wedge[0];
- for (uint i = 0; i < wedge_len; i++, we++) {
- if (we->flag == ELEM_COLLAPSED) {
+ for (const int i : r_wedge.index_range()) {
+ const WeldEdge &we = r_wedge[i];
+ if (we.flag == ELEM_COLLAPSED) {
continue;
}
- uint dst_vert_a = we->vert_a;
- uint dst_vert_b = we->vert_b;
+ int dst_vert_a = we.vert_a;
+ int dst_vert_b = we.vert_b;
link_edge_buffer[v_links[dst_vert_a].ofs++] = i;
link_edge_buffer[v_links[dst_vert_b].ofs++] = i;
}
- vl_iter = &v_links[0];
- for (uint i = mvert_len; i--; vl_iter++) {
+ for (WeldGroup &vl : r_vlinks) {
/* Fix offset */
- vl_iter->ofs -= vl_iter->len;
+ vl.ofs -= vl.len;
}
- we = &r_wedge[0];
- for (uint i = 0; i < wedge_len; i++, we++) {
- if (we->edge_dest != OUT_OF_CONTEXT) {
+ for (const int i : r_wedge.index_range()) {
+ const WeldEdge &we = r_wedge[i];
+ if (we.edge_dest != OUT_OF_CONTEXT) {
/* No need to retest edges.
* (Already includes collapsed edges). */
continue;
}
- uint dst_vert_a = we->vert_a;
- uint dst_vert_b = we->vert_b;
+ int dst_vert_a = we.vert_a;
+ int dst_vert_b = we.vert_b;
struct WeldGroup *link_a = &v_links[dst_vert_a];
struct WeldGroup *link_b = &v_links[dst_vert_b];
- uint edges_len_a = link_a->len;
- uint edges_len_b = link_b->len;
+ int edges_len_a = link_a->len;
+ int edges_len_b = link_b->len;
if (edges_len_a <= 1 || edges_len_b <= 1) {
continue;
}
- uint *edges_ctx_a = &link_edge_buffer[link_a->ofs];
- uint *edges_ctx_b = &link_edge_buffer[link_b->ofs];
- uint edge_orig = we->edge_orig;
+ int *edges_ctx_a = &link_edge_buffer[link_a->ofs];
+ int *edges_ctx_b = &link_edge_buffer[link_b->ofs];
+ int edge_orig = we.edge_orig;
for (; edges_len_a--; edges_ctx_a++) {
- uint e_ctx_a = *edges_ctx_a;
+ int e_ctx_a = *edges_ctx_a;
if (e_ctx_a == i) {
continue;
}
@@ -565,7 +538,7 @@ static void weld_edge_ctx_setup(const uint mvert_len,
if (edges_len_b == 0) {
break;
}
- uint e_ctx_b = *edges_ctx_b;
+ int e_ctx_b = *edges_ctx_b;
if (e_ctx_a == e_ctx_b) {
WeldEdge *we_b = &r_wedge[e_ctx_b];
BLI_assert(ELEM(we_b->vert_a, dst_vert_a, dst_vert_b));
@@ -580,138 +553,118 @@ static void weld_edge_ctx_setup(const uint mvert_len,
}
#ifdef USE_WELD_DEBUG
- weld_assert_edge_kill_len(r_wedge, wedge_len, edge_kill_len);
+ weld_assert_edge_kill_len(r_wedge, edge_kill_len);
#endif
-
- MEM_freeN(link_edge_buffer);
}
*r_edge_kiil_len = edge_kill_len;
}
-static void weld_edge_ctx_alloc(const MEdge *medge,
- const uint medge_len,
- const uint *vert_dest_map,
- uint *r_edge_dest_map,
- uint **r_edge_ctx_map,
- WeldEdge **r_wedge,
- uint *r_wedge_len)
+static Vector<WeldEdge> weld_edge_ctx_alloc(Span<MEdge> medge,
+ Span<int> vert_dest_map,
+ MutableSpan<int> r_edge_dest_map,
+ MutableSpan<int> r_edge_ctx_map)
{
/* Edge Context. */
- uint *edge_map = MEM_mallocN(sizeof(*edge_map) * medge_len, __func__);
- uint wedge_len = 0;
-
- WeldEdge *wedge, *we;
- wedge = MEM_mallocN(sizeof(*wedge) * medge_len, __func__);
- we = &wedge[0];
-
- const MEdge *me = &medge[0];
- uint *e_dest_iter = &r_edge_dest_map[0];
- uint *iter = &edge_map[0];
- for (uint i = 0; i < medge_len; i++, me++, iter++, e_dest_iter++) {
- uint v1 = me->v1;
- uint v2 = me->v2;
- uint v_dest_1 = vert_dest_map[v1];
- uint v_dest_2 = vert_dest_map[v2];
+ int wedge_len = 0;
+
+ Vector<WeldEdge> wedge;
+ wedge.reserve(medge.size());
+
+ for (const int i : medge.index_range()) {
+ int v1 = medge[i].v1;
+ int v2 = medge[i].v2;
+ int v_dest_1 = vert_dest_map[v1];
+ int v_dest_2 = vert_dest_map[v2];
if ((v_dest_1 != OUT_OF_CONTEXT) || (v_dest_2 != OUT_OF_CONTEXT)) {
- we->vert_a = (v_dest_1 != OUT_OF_CONTEXT) ? v_dest_1 : v1;
- we->vert_b = (v_dest_2 != OUT_OF_CONTEXT) ? v_dest_2 : v2;
- we->edge_dest = OUT_OF_CONTEXT;
- we->edge_orig = i;
- we++;
- *e_dest_iter = i;
- *iter = wedge_len++;
+ WeldEdge we{};
+ we.vert_a = (v_dest_1 != OUT_OF_CONTEXT) ? v_dest_1 : v1;
+ we.vert_b = (v_dest_2 != OUT_OF_CONTEXT) ? v_dest_2 : v2;
+ we.edge_dest = OUT_OF_CONTEXT;
+ we.edge_orig = i;
+ wedge.append(we);
+ r_edge_dest_map[i] = i;
+ r_edge_ctx_map[i] = wedge_len++;
}
else {
- *e_dest_iter = OUT_OF_CONTEXT;
- *iter = OUT_OF_CONTEXT;
+ r_edge_dest_map[i] = OUT_OF_CONTEXT;
+ r_edge_ctx_map[i] = OUT_OF_CONTEXT;
}
}
- *r_wedge = MEM_reallocN(wedge, sizeof(*wedge) * wedge_len);
- *r_wedge_len = wedge_len;
- *r_edge_ctx_map = edge_map;
+ return wedge;
}
-static void weld_edge_groups_setup(const uint medge_len,
- const uint edge_kill_len,
- const uint wedge_len,
- WeldEdge *wedge,
- const uint *wedge_map,
- uint *r_edge_groups_map,
- uint **r_edge_groups_buffer,
- struct WeldGroupEdge **r_edge_groups)
+static void weld_edge_groups_setup(const int medge_len,
+ const int edge_kill_len,
+ MutableSpan<WeldEdge> wedge,
+ Span<int> wedge_map,
+ MutableSpan<int> r_edge_groups_map,
+ Array<int> &r_edge_groups_buffer,
+ Array<WeldGroupEdge> &r_edge_groups)
{
-
/* Get weld edge groups. */
- struct WeldGroupEdge *wegroups, *wegrp_iter;
+ struct WeldGroupEdge *wegrp_iter;
- uint wgroups_len = wedge_len - edge_kill_len;
- wegroups = MEM_callocN(sizeof(*wegroups) * wgroups_len, __func__);
- wegrp_iter = &wegroups[0];
+ int wgroups_len = wedge.size() - edge_kill_len;
+ r_edge_groups.reinitialize(wgroups_len);
+ r_edge_groups.fill({0});
+ MutableSpan<WeldGroupEdge> wegroups = r_edge_groups;
+ wegrp_iter = &r_edge_groups[0];
wgroups_len = 0;
- const uint *edge_ctx_iter = &wedge_map[0];
- uint *group_map_iter = &r_edge_groups_map[0];
- for (uint i = medge_len; i--; edge_ctx_iter++, group_map_iter++) {
- uint edge_ctx = *edge_ctx_iter;
+ for (const int i : IndexRange(medge_len)) {
+ int edge_ctx = wedge_map[i];
if (edge_ctx != OUT_OF_CONTEXT) {
WeldEdge *we = &wedge[edge_ctx];
- uint edge_dest = we->edge_dest;
+ int edge_dest = we->edge_dest;
if (edge_dest != OUT_OF_CONTEXT) {
BLI_assert(edge_dest != we->edge_orig);
- *group_map_iter = ELEM_MERGED;
+ r_edge_groups_map[i] = ELEM_MERGED;
}
else {
we->edge_dest = we->edge_orig;
wegrp_iter->v1 = we->vert_a;
wegrp_iter->v2 = we->vert_b;
- *group_map_iter = wgroups_len;
+ r_edge_groups_map[i] = wgroups_len;
wgroups_len++;
wegrp_iter++;
}
}
else {
- *group_map_iter = OUT_OF_CONTEXT;
+ r_edge_groups_map[i] = OUT_OF_CONTEXT;
}
}
- BLI_assert(wgroups_len == wedge_len - edge_kill_len);
+ BLI_assert(wgroups_len == wedge.size() - edge_kill_len);
- WeldEdge *we = &wedge[0];
- for (uint i = wedge_len; i--; we++) {
- if (we->flag == ELEM_COLLAPSED) {
+ for (const WeldEdge &we : wedge) {
+ if (we.flag == ELEM_COLLAPSED) {
continue;
}
- uint group_index = r_edge_groups_map[we->edge_dest];
+ int group_index = r_edge_groups_map[we.edge_dest];
wegroups[group_index].group.len++;
}
- uint ofs = 0;
- wegrp_iter = &wegroups[0];
- for (uint i = wgroups_len; i--; wegrp_iter++) {
- wegrp_iter->group.ofs = ofs;
- ofs += wegrp_iter->group.len;
+ int ofs = 0;
+ for (WeldGroupEdge &wegrp : wegroups) {
+ wegrp.group.ofs = ofs;
+ ofs += wegrp.group.len;
}
- uint *groups_buffer = MEM_mallocN(sizeof(*groups_buffer) * ofs, __func__);
- we = &wedge[0];
- for (uint i = wedge_len; i--; we++) {
- if (we->flag == ELEM_COLLAPSED) {
+ r_edge_groups_buffer.reinitialize(ofs);
+ for (const WeldEdge &we : wedge) {
+ if (we.flag == ELEM_COLLAPSED) {
continue;
}
- uint group_index = r_edge_groups_map[we->edge_dest];
- groups_buffer[wegroups[group_index].group.ofs++] = we->edge_orig;
+ int group_index = r_edge_groups_map[we.edge_dest];
+ r_edge_groups_buffer[wegroups[group_index].group.ofs++] = we.edge_orig;
}
- wegrp_iter = &wegroups[0];
- for (uint i = wgroups_len; i--; wegrp_iter++) {
- wegrp_iter->group.ofs -= wegrp_iter->group.len;
+ for (WeldGroupEdge &wegrp : wegroups) {
+ wegrp.group.ofs -= wegrp.group.len;
}
-
- *r_edge_groups_buffer = groups_buffer;
- *r_edge_groups = wegroups;
}
/** \} */
@@ -721,31 +674,31 @@ static void weld_edge_groups_setup(const uint medge_len,
* \{ */
static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter,
- const WeldPoly *wp,
- const WeldLoop *wloop,
- const MLoop *mloop,
- const uint *loop_map,
- uint *group_buffer)
+ const WeldPoly &wp,
+ Span<WeldLoop> wloop,
+ Span<MLoop> mloop,
+ Span<int> loop_map,
+ int *group_buffer)
{
- if (wp->flag == ELEM_COLLAPSED) {
+ if (wp.flag == ELEM_COLLAPSED) {
return false;
}
- iter->loop_start = wp->loop_start;
- iter->loop_end = wp->loop_end;
+ iter->loop_start = wp.loop_start;
+ iter->loop_end = wp.loop_end;
iter->wloop = wloop;
iter->mloop = mloop;
iter->loop_map = loop_map;
iter->group = group_buffer;
- uint group_len = 0;
+ int group_len = 0;
if (group_buffer) {
/* First loop group needs more attention. */
- uint loop_start, loop_end, l;
+ int loop_start, loop_end, l;
loop_start = iter->loop_start;
loop_end = l = iter->loop_end;
while (l >= loop_start) {
- const uint loop_ctx = loop_map[l];
+ const int loop_ctx = loop_map[l];
if (loop_ctx != OUT_OF_CONTEXT) {
const WeldLoop *wl = &wloop[loop_ctx];
if (wl->flag == ELEM_COLLAPSED) {
@@ -774,10 +727,10 @@ static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter,
static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter)
{
- uint loop_end = iter->loop_end;
- const WeldLoop *wloop = iter->wloop;
- const uint *loop_map = iter->loop_map;
- uint l = iter->l_curr = iter->l_next;
+ int loop_end = iter->loop_end;
+ Span<WeldLoop> wloop = iter->wloop;
+ Span<int> loop_map = iter->loop_map;
+ int l = iter->l_curr = iter->l_next;
if (l == iter->loop_start) {
/* `grupo_len` is already calculated in the first loop */
}
@@ -785,8 +738,8 @@ static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter)
iter->group_len = 0;
}
while (l <= loop_end) {
- uint l_next = l + 1;
- const uint loop_ctx = loop_map[l];
+ int l_next = l + 1;
+ const int loop_ctx = loop_map[l];
if (loop_ctx != OUT_OF_CONTEXT) {
const WeldLoop *wl = &wloop[loop_ctx];
if (wl->loop_skip_to != OUT_OF_CONTEXT) {
@@ -809,7 +762,7 @@ static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter)
else {
const MLoop *ml = &iter->mloop[l];
#ifdef USE_WELD_DEBUG
- BLI_assert(iter->v != ml->v);
+ BLI_assert((uint)iter->v != ml->v);
#endif
iter->v = ml->v;
iter->e = ml->e;
@@ -825,129 +778,119 @@ static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter)
return false;
}
-static void weld_poly_loop_ctx_alloc(const MPoly *mpoly,
- const uint mpoly_len,
- const MLoop *mloop,
- const uint mloop_len,
- const uint *vert_dest_map,
- const uint *edge_dest_map,
+static void weld_poly_loop_ctx_alloc(Span<MPoly> mpoly,
+ Span<MLoop> mloop,
+ Span<int> vert_dest_map,
+ Span<int> edge_dest_map,
WeldMesh *r_weld_mesh)
{
/* Loop/Poly Context. */
- uint *loop_map = MEM_mallocN(sizeof(*loop_map) * mloop_len, __func__);
- uint *poly_map = MEM_mallocN(sizeof(*poly_map) * mpoly_len, __func__);
- uint wloop_len = 0;
- uint wpoly_len = 0;
- uint max_ctx_poly_len = 4;
+ Array<int> loop_map(mloop.size());
+ Array<int> poly_map(mpoly.size());
+ int wloop_len = 0;
+ int wpoly_len = 0;
+ int max_ctx_poly_len = 4;
- WeldLoop *wloop, *wl;
- wloop = MEM_mallocN(sizeof(*wloop) * mloop_len, __func__);
- wl = &wloop[0];
+ Vector<WeldLoop> wloop;
+ wloop.reserve(mloop.size());
- WeldPoly *wpoly, *wp;
- wpoly = MEM_mallocN(sizeof(*wpoly) * mpoly_len, __func__);
- wp = &wpoly[0];
+ Vector<WeldPoly> wpoly;
+ wpoly.reserve(mpoly.size());
- uint maybe_new_poly = 0;
+ int maybe_new_poly = 0;
- const MPoly *mp = &mpoly[0];
- uint *iter = &poly_map[0];
- uint *loop_map_iter = &loop_map[0];
- for (uint i = 0; i < mpoly_len; i++, mp++, iter++) {
- const uint loopstart = mp->loopstart;
- const uint totloop = mp->totloop;
-
- uint vert_ctx_len = 0;
-
- uint l = loopstart;
- uint prev_wloop_len = wloop_len;
- const MLoop *ml = &mloop[l];
- for (uint j = totloop; j--; l++, ml++, loop_map_iter++) {
- uint v = ml->v;
- uint e = ml->e;
- uint v_dest = vert_dest_map[v];
- uint e_dest = edge_dest_map[e];
+ for (const int i : mpoly.index_range()) {
+ const MPoly &mp = mpoly[i];
+ const int loopstart = mp.loopstart;
+ const int totloop = mp.totloop;
+
+ int vert_ctx_len = 0;
+
+ int prev_wloop_len = wloop_len;
+ for (const int i_loop : mloop.index_range().slice(loopstart, totloop)) {
+ int v = mloop[i_loop].v;
+ int e = mloop[i_loop].e;
+ int v_dest = vert_dest_map[v];
+ int e_dest = edge_dest_map[e];
bool is_vert_ctx = v_dest != OUT_OF_CONTEXT;
bool is_edge_ctx = e_dest != OUT_OF_CONTEXT;
if (is_vert_ctx) {
vert_ctx_len++;
}
if (is_vert_ctx || is_edge_ctx) {
- wl->vert = is_vert_ctx ? v_dest : v;
- wl->edge = is_edge_ctx ? e_dest : e;
- wl->loop_orig = l;
- wl->loop_skip_to = OUT_OF_CONTEXT;
- wl++;
-
- *loop_map_iter = wloop_len++;
+ WeldLoop wl{};
+ wl.vert = is_vert_ctx ? v_dest : v;
+ wl.edge = is_edge_ctx ? e_dest : e;
+ wl.loop_orig = i_loop;
+ wl.loop_skip_to = OUT_OF_CONTEXT;
+ wloop.append(wl);
+
+ loop_map[i_loop] = wloop_len++;
}
else {
- *loop_map_iter = OUT_OF_CONTEXT;
+ loop_map[i_loop] = OUT_OF_CONTEXT;
}
}
if (wloop_len != prev_wloop_len) {
- uint loops_len = wloop_len - prev_wloop_len;
-
- wp->poly_dst = OUT_OF_CONTEXT;
- wp->poly_orig = i;
- wp->loops.len = loops_len;
- wp->loops.ofs = prev_wloop_len;
- wp->loop_start = loopstart;
- wp->loop_end = loopstart + totloop - 1;
- wp->len = totloop;
- wp++;
-
- *iter = wpoly_len++;
+ int loops_len = wloop_len - prev_wloop_len;
+ WeldPoly wp{};
+ wp.poly_dst = OUT_OF_CONTEXT;
+ wp.poly_orig = i;
+ wp.loops.len = loops_len;
+ wp.loops.ofs = prev_wloop_len;
+ wp.loop_start = loopstart;
+ wp.loop_end = loopstart + totloop - 1;
+ wp.len = totloop;
+ wpoly.append(wp);
+
+ poly_map[i] = wpoly_len++;
if (totloop > 5 && vert_ctx_len > 1) {
- uint max_new = (totloop / 3) - 1;
+ int max_new = (totloop / 3) - 1;
vert_ctx_len /= 2;
maybe_new_poly += MIN2(max_new, vert_ctx_len);
CLAMP_MIN(max_ctx_poly_len, totloop);
}
}
else {
- *iter = OUT_OF_CONTEXT;
+ poly_map[i] = OUT_OF_CONTEXT;
}
}
- if (mpoly_len < (wpoly_len + maybe_new_poly)) {
- WeldPoly *wpoly_tmp = wpoly;
- wpoly = MEM_mallocN(sizeof(*wpoly) * ((size_t)wpoly_len + maybe_new_poly), __func__);
- memcpy(wpoly, wpoly_tmp, sizeof(*wpoly) * wpoly_len);
- MEM_freeN(wpoly_tmp);
+ if (mpoly.size() < (wpoly_len + maybe_new_poly)) {
+ wpoly.resize(wpoly_len + maybe_new_poly);
}
- WeldPoly *poly_new = &wpoly[wpoly_len];
+ WeldPoly *poly_new = wpoly.data() + wpoly_len;
- r_weld_mesh->wloop = MEM_reallocN(wloop, sizeof(*wloop) * wloop_len);
- r_weld_mesh->wpoly = wpoly;
+ r_weld_mesh->wloop = std::move(wloop);
+ r_weld_mesh->wpoly = std::move(wpoly);
r_weld_mesh->wpoly_new = poly_new;
r_weld_mesh->wloop_len = wloop_len;
r_weld_mesh->wpoly_len = wpoly_len;
r_weld_mesh->wpoly_new_len = 0;
- r_weld_mesh->loop_map = loop_map;
- r_weld_mesh->poly_map = poly_map;
+ r_weld_mesh->loop_map = std::move(loop_map);
+ r_weld_mesh->poly_map = std::move(poly_map);
r_weld_mesh->max_poly_len = max_ctx_poly_len;
}
-static void weld_poly_split_recursive(const uint *vert_dest_map,
+static void weld_poly_split_recursive(Span<int> vert_dest_map,
#ifdef USE_WELD_DEBUG
- const MLoop *mloop,
+ const Span<MLoop> mloop,
#endif
- uint ctx_verts_len,
+ int ctx_verts_len,
WeldPoly *r_wp,
WeldMesh *r_weld_mesh,
- uint *r_poly_kill,
- uint *r_loop_kill)
+ int *r_poly_kill,
+ int *r_loop_kill)
{
- uint poly_len = r_wp->len;
+ int poly_len = r_wp->len;
if (poly_len > 3 && ctx_verts_len > 1) {
- const uint ctx_loops_len = r_wp->loops.len;
- const uint ctx_loops_ofs = r_wp->loops.ofs;
- WeldLoop *wloop = r_weld_mesh->wloop;
+ const int ctx_loops_len = r_wp->loops.len;
+ const int ctx_loops_ofs = r_wp->loops.ofs;
+ MutableSpan<WeldLoop> wloop = r_weld_mesh->wloop;
WeldPoly *wpoly_new = r_weld_mesh->wpoly_new;
- uint loop_kill = 0;
+ int loop_kill = 0;
WeldLoop *poly_loops = &wloop[ctx_loops_ofs];
WeldLoop *wla = &poly_loops[0];
@@ -955,19 +898,19 @@ static void weld_poly_split_recursive(const uint *vert_dest_map,
while (wla_prev->flag == ELEM_COLLAPSED) {
wla_prev--;
}
- const uint la_len = ctx_loops_len - 1;
- for (uint la = 0; la < la_len; la++, wla++) {
+ const int la_len = ctx_loops_len - 1;
+ for (int la = 0; la < la_len; la++, wla++) {
wa_continue:
if (wla->flag == ELEM_COLLAPSED) {
continue;
}
- uint vert_a = wla->vert;
+ int vert_a = wla->vert;
/* Only test vertices that will be merged. */
if (vert_dest_map[vert_a] != OUT_OF_CONTEXT) {
- uint lb = la + 1;
+ int lb = la + 1;
WeldLoop *wlb = wla + 1;
WeldLoop *wlb_prev = wla;
- uint killed_ab = 0;
+ int killed_ab = 0;
ctx_verts_len = 1;
for (; lb < ctx_loops_len; lb++, wlb++) {
BLI_assert(wlb->loop_skip_to == OUT_OF_CONTEXT);
@@ -975,13 +918,13 @@ static void weld_poly_split_recursive(const uint *vert_dest_map,
killed_ab++;
continue;
}
- uint vert_b = wlb->vert;
+ int vert_b = wlb->vert;
if (vert_dest_map[vert_b] != OUT_OF_CONTEXT) {
ctx_verts_len++;
}
if (vert_a == vert_b) {
- const uint dist_a = wlb->loop_orig - wla->loop_orig - killed_ab;
- const uint dist_b = poly_len - dist_a;
+ const int dist_a = wlb->loop_orig - wla->loop_orig - killed_ab;
+ const int dist_b = poly_len - dist_a;
BLI_assert(dist_a != 0 && dist_b != 0);
if (dist_a == 1 || dist_b == 1) {
@@ -989,7 +932,7 @@ static void weld_poly_split_recursive(const uint *vert_dest_map,
BLI_assert((wla->flag == ELEM_COLLAPSED) || (wlb->flag == ELEM_COLLAPSED));
}
else {
- WeldLoop *wl_tmp = NULL;
+ WeldLoop *wl_tmp = nullptr;
if (dist_a == 2) {
wl_tmp = wlb_prev;
BLI_assert(wla->flag != ELEM_COLLAPSED);
@@ -1000,7 +943,7 @@ static void weld_poly_split_recursive(const uint *vert_dest_map,
poly_len -= 2;
}
if (dist_b == 2) {
- if (wl_tmp != NULL) {
+ if (wl_tmp != nullptr) {
r_wp->flag = ELEM_COLLAPSED;
*r_poly_kill += 1;
}
@@ -1014,9 +957,9 @@ static void weld_poly_split_recursive(const uint *vert_dest_map,
loop_kill += 2;
poly_len -= 2;
}
- if (wl_tmp == NULL) {
- const uint new_loops_len = lb - la;
- const uint new_loops_ofs = ctx_loops_ofs + la;
+ if (wl_tmp == nullptr) {
+ const int new_loops_len = lb - la;
+ const int new_loops_ofs = ctx_loops_ofs + la;
WeldPoly *new_wp = &wpoly_new[r_weld_mesh->wpoly_new_len++];
new_wp->poly_dst = OUT_OF_CONTEXT;
@@ -1065,56 +1008,53 @@ static void weld_poly_split_recursive(const uint *vert_dest_map,
*r_loop_kill += loop_kill;
#ifdef USE_WELD_DEBUG
- weld_assert_poly_no_vert_repetition(r_wp, wloop, mloop, r_weld_mesh->loop_map);
+ weld_assert_poly_no_vert_repetition(*r_wp, wloop, mloop, r_weld_mesh->loop_map);
#endif
}
}
-static void weld_poly_loop_ctx_setup(const MLoop *mloop,
+static void weld_poly_loop_ctx_setup(Span<MLoop> mloop,
#ifdef USE_WELD_DEBUG
- const MPoly *mpoly,
- const uint mpoly_len,
- const uint mloop_len,
+ Span<MPoly> mpoly,
#endif
- const uint mvert_len,
- const uint *vert_dest_map,
- const uint remain_edge_ctx_len,
- struct WeldGroup *r_vlinks,
+ const int mvert_len,
+ Span<int> vert_dest_map,
+ const int remain_edge_ctx_len,
+ MutableSpan<WeldGroup> r_vlinks,
WeldMesh *r_weld_mesh)
{
- uint poly_kill_len, loop_kill_len, wpoly_len, wpoly_new_len;
+ int poly_kill_len, loop_kill_len, wpoly_len, wpoly_new_len;
- WeldPoly *wpoly_new, *wpoly, *wp;
- WeldLoop *wloop, *wl;
+ WeldPoly *wpoly_new;
+ WeldLoop *wl;
- wpoly = r_weld_mesh->wpoly;
- wloop = r_weld_mesh->wloop;
+ MutableSpan<WeldPoly> wpoly = r_weld_mesh->wpoly;
+ MutableSpan<WeldLoop> wloop = r_weld_mesh->wloop;
wpoly_new = r_weld_mesh->wpoly_new;
wpoly_len = r_weld_mesh->wpoly_len;
wpoly_new_len = 0;
poly_kill_len = 0;
loop_kill_len = 0;
- const uint *loop_map = r_weld_mesh->loop_map;
+ Span<int> loop_map = r_weld_mesh->loop_map;
if (remain_edge_ctx_len) {
/* Setup Poly/Loop. */
- wp = &wpoly[0];
- for (uint i = wpoly_len; i--; wp++) {
- const uint ctx_loops_len = wp->loops.len;
- const uint ctx_loops_ofs = wp->loops.ofs;
+ for (WeldPoly &wp : wpoly) {
+ const int ctx_loops_len = wp.loops.len;
+ const int ctx_loops_ofs = wp.loops.ofs;
- uint poly_len = wp->len;
- uint ctx_verts_len = 0;
+ int poly_len = wp.len;
+ int ctx_verts_len = 0;
wl = &wloop[ctx_loops_ofs];
- for (uint l = ctx_loops_len; l--; wl++) {
- const uint edge_dest = wl->edge;
+ for (int l = ctx_loops_len; l--; wl++) {
+ const int edge_dest = wl->edge;
if (edge_dest == ELEM_COLLAPSED) {
wl->flag = ELEM_COLLAPSED;
if (poly_len == 3) {
- wp->flag = ELEM_COLLAPSED;
+ wp.flag = ELEM_COLLAPSED;
poly_kill_len++;
loop_kill_len += 3;
poly_len = 0;
@@ -1124,7 +1064,7 @@ static void weld_poly_loop_ctx_setup(const MLoop *mloop,
poly_len--;
}
else {
- const uint vert_dst = wl->vert;
+ const int vert_dst = wl->vert;
if (vert_dest_map[vert_dst] != OUT_OF_CONTEXT) {
ctx_verts_len++;
}
@@ -1132,7 +1072,7 @@ static void weld_poly_loop_ctx_setup(const MLoop *mloop,
}
if (poly_len) {
- wp->len = poly_len;
+ wp.len = poly_len;
#ifdef USE_WELD_DEBUG
weld_assert_poly_len(wp, wloop);
#endif
@@ -1142,7 +1082,7 @@ static void weld_poly_loop_ctx_setup(const MLoop *mloop,
mloop,
#endif
ctx_verts_len,
- wp,
+ &wp,
r_weld_mesh,
&poly_kill_len,
&loop_kill_len);
@@ -1153,75 +1093,70 @@ static void weld_poly_loop_ctx_setup(const MLoop *mloop,
#ifdef USE_WELD_DEBUG
weld_assert_poly_and_loop_kill_len(wpoly,
- wpoly_new,
- wpoly_new_len,
+ {wpoly_new, wpoly_new_len},
wloop,
mloop,
loop_map,
r_weld_mesh->poly_map,
mpoly,
- mpoly_len,
- mloop_len,
poly_kill_len,
loop_kill_len);
#endif
/* Setup Polygon Overlap. */
- uint wpoly_and_new_len = wpoly_len + wpoly_new_len;
+ int wpoly_and_new_len = wpoly_len + wpoly_new_len;
- struct WeldGroup *vl_iter, *v_links = r_vlinks;
- memset(v_links, 0, sizeof(*v_links) * mvert_len);
+ r_vlinks.fill({0, 0});
+ MutableSpan<WeldGroup> v_links = r_vlinks;
- wp = &wpoly[0];
- for (uint i = wpoly_and_new_len; i--; wp++) {
+ for (const int i : IndexRange(wpoly_and_new_len)) {
+ const WeldPoly &wp = wpoly[i];
WeldLoopOfPolyIter iter;
- if (weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) {
+ if (weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, nullptr)) {
while (weld_iter_loop_of_poly_next(&iter)) {
v_links[iter.v].len++;
}
}
}
- uint link_len = 0;
- vl_iter = &v_links[0];
- for (uint i = mvert_len; i--; vl_iter++) {
- vl_iter->ofs = link_len;
- link_len += vl_iter->len;
+ int link_len = 0;
+ for (const int i : IndexRange(mvert_len)) {
+ v_links[i].ofs = link_len;
+ link_len += v_links[i].len;
}
if (link_len) {
- uint *link_poly_buffer = MEM_mallocN(sizeof(*link_poly_buffer) * link_len, __func__);
+ Array<int> link_poly_buffer(link_len);
- wp = &wpoly[0];
- for (uint i = 0; i < wpoly_and_new_len; i++, wp++) {
+ for (const int i : IndexRange(wpoly_and_new_len)) {
+ const WeldPoly &wp = wpoly[i];
WeldLoopOfPolyIter iter;
- if (weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) {
+ if (weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, nullptr)) {
while (weld_iter_loop_of_poly_next(&iter)) {
link_poly_buffer[v_links[iter.v].ofs++] = i;
}
}
}
- vl_iter = &v_links[0];
- for (uint i = mvert_len; i--; vl_iter++) {
+ for (WeldGroup &vl : r_vlinks) {
/* Fix offset */
- vl_iter->ofs -= vl_iter->len;
+ vl.ofs -= vl.len;
}
- uint polys_len_a, polys_len_b, *polys_ctx_a, *polys_ctx_b, p_ctx_a, p_ctx_b;
+ int polys_len_a, polys_len_b, *polys_ctx_a, *polys_ctx_b, p_ctx_a, p_ctx_b;
polys_len_b = p_ctx_b = 0; /* silence warnings */
- wp = &wpoly[0];
- for (uint i = 0; i < wpoly_and_new_len; i++, wp++) {
- if (wp->poly_dst != OUT_OF_CONTEXT) {
+ for (const int i : IndexRange(wpoly_and_new_len)) {
+ const WeldPoly &wp = wpoly[i];
+ if (wp.poly_dst != OUT_OF_CONTEXT) {
/* No need to retest poly.
* (Already includes collapsed polygons). */
continue;
}
WeldLoopOfPolyIter iter;
- weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL);
+ weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, nullptr);
weld_iter_loop_of_poly_next(&iter);
struct WeldGroup *link_a = &v_links[iter.v];
polys_len_a = link_a->len;
@@ -1229,7 +1164,7 @@ static void weld_poly_loop_ctx_setup(const MLoop *mloop,
BLI_assert(link_poly_buffer[link_a->ofs] == i);
continue;
}
- uint wp_len = wp->len;
+ int wp_len = wp.len;
polys_ctx_a = &link_poly_buffer[link_a->ofs];
for (; polys_len_a--; polys_ctx_a++) {
p_ctx_a = *polys_ctx_a;
@@ -1275,36 +1210,31 @@ static void weld_poly_loop_ctx_setup(const MLoop *mloop,
BLI_assert(p_ctx_a > i);
BLI_assert(p_ctx_a == p_ctx_b);
BLI_assert(wp_tmp->poly_dst == OUT_OF_CONTEXT);
- BLI_assert(wp_tmp != wp);
- wp_tmp->poly_dst = wp->poly_orig;
+ BLI_assert(wp_tmp != &wp);
+ wp_tmp->poly_dst = wp.poly_orig;
loop_kill_len += wp_tmp->len;
poly_kill_len++;
}
}
- MEM_freeN(link_poly_buffer);
}
}
else {
poly_kill_len = r_weld_mesh->wpoly_len;
loop_kill_len = r_weld_mesh->wloop_len;
- wp = &wpoly[0];
- for (uint i = wpoly_len; i--; wp++) {
- wp->flag = ELEM_COLLAPSED;
+ for (WeldPoly &wp : wpoly) {
+ wp.flag = ELEM_COLLAPSED;
}
}
#ifdef USE_WELD_DEBUG
weld_assert_poly_and_loop_kill_len(wpoly,
- wpoly_new,
- wpoly_new_len,
+ {wpoly_new, wpoly_new_len},
wloop,
mloop,
loop_map,
r_weld_mesh->poly_map,
mpoly,
- mpoly_len,
- mloop_len,
poly_kill_len,
loop_kill_len);
#endif
@@ -1321,87 +1251,53 @@ static void weld_poly_loop_ctx_setup(const MLoop *mloop,
* \{ */
static void weld_mesh_context_create(const Mesh *mesh,
- uint *vert_dest_map,
- const uint vert_kill_len,
+ MutableSpan<int> vert_dest_map,
+ const int vert_kill_len,
WeldMesh *r_weld_mesh)
{
- const MEdge *medge = mesh->medge;
- const MLoop *mloop = mesh->mloop;
- const MPoly *mpoly = mesh->mpoly;
- const uint mvert_len = mesh->totvert;
- const uint medge_len = mesh->totedge;
- const uint mloop_len = mesh->totloop;
- const uint mpoly_len = mesh->totpoly;
-
- uint *edge_dest_map = MEM_mallocN(sizeof(*edge_dest_map) * medge_len, __func__);
- struct WeldGroup *v_links = MEM_callocN(sizeof(*v_links) * mvert_len, __func__);
-
- WeldVert *wvert;
- uint wvert_len;
+ Span<MEdge> medge{mesh->medge, mesh->totedge};
+ Span<MPoly> mpoly{mesh->mpoly, mesh->totpoly};
+ Span<MLoop> mloop{mesh->mloop, mesh->totloop};
+ const int mvert_len = mesh->totvert;
+
+ Vector<WeldVert> wvert = weld_vert_ctx_alloc_and_setup(vert_dest_map);
r_weld_mesh->vert_kill_len = vert_kill_len;
- weld_vert_ctx_alloc_and_setup(mvert_len, vert_dest_map, &wvert, &wvert_len);
- uint *edge_ctx_map;
- WeldEdge *wedge;
- uint wedge_len;
- weld_edge_ctx_alloc(
- medge, medge_len, vert_dest_map, edge_dest_map, &edge_ctx_map, &wedge, &wedge_len);
+ Array<int> edge_dest_map(medge.size());
+ Array<int> edge_ctx_map(medge.size());
+ Vector<WeldEdge> wedge = weld_edge_ctx_alloc(medge, vert_dest_map, edge_dest_map, edge_ctx_map);
- weld_edge_ctx_setup(
- mvert_len, wedge_len, v_links, edge_dest_map, wedge, &r_weld_mesh->edge_kill_len);
+ Array<WeldGroup> v_links(mvert_len, {0, 0});
+ weld_edge_ctx_setup(v_links, edge_dest_map, wedge, &r_weld_mesh->edge_kill_len);
- weld_poly_loop_ctx_alloc(
- mpoly, mpoly_len, mloop, mloop_len, vert_dest_map, edge_dest_map, r_weld_mesh);
+ weld_poly_loop_ctx_alloc(mpoly, mloop, vert_dest_map, edge_dest_map, r_weld_mesh);
weld_poly_loop_ctx_setup(mloop,
#ifdef USE_WELD_DEBUG
mpoly,
- mpoly_len,
- mloop_len,
+
#endif
mvert_len,
vert_dest_map,
- wedge_len - r_weld_mesh->edge_kill_len,
+ wedge.size() - r_weld_mesh->edge_kill_len,
v_links,
r_weld_mesh);
- weld_vert_groups_setup(mvert_len,
- wvert_len,
- wvert,
+ weld_vert_groups_setup(wvert,
vert_dest_map,
vert_dest_map,
- &r_weld_mesh->vert_groups_buffer,
- &r_weld_mesh->vert_groups);
+ r_weld_mesh->vert_groups_buffer,
+ r_weld_mesh->vert_groups);
- weld_edge_groups_setup(medge_len,
+ weld_edge_groups_setup(medge.size(),
r_weld_mesh->edge_kill_len,
- wedge_len,
wedge,
edge_ctx_map,
edge_dest_map,
- &r_weld_mesh->edge_groups_buffer,
- &r_weld_mesh->edge_groups);
-
- r_weld_mesh->edge_groups_map = edge_dest_map;
- MEM_freeN(v_links);
- MEM_freeN(wvert);
- MEM_freeN(edge_ctx_map);
- MEM_freeN(wedge);
-}
+ r_weld_mesh->edge_groups_buffer,
+ r_weld_mesh->edge_groups);
-static void weld_mesh_context_free(WeldMesh *weld_mesh)
-{
- MEM_freeN(weld_mesh->vert_groups);
- MEM_freeN(weld_mesh->vert_groups_buffer);
-
- MEM_freeN(weld_mesh->edge_groups);
- MEM_freeN(weld_mesh->edge_groups_buffer);
- MEM_freeN(weld_mesh->edge_groups_map);
-
- MEM_freeN(weld_mesh->wloop);
- MEM_freeN(weld_mesh->wpoly);
- MEM_freeN(weld_mesh->loop_map);
- MEM_freeN(weld_mesh->poly_map);
+ r_weld_mesh->edge_groups_map = std::move(edge_dest_map);
}
/** \} */
@@ -1411,14 +1307,14 @@ static void weld_mesh_context_free(WeldMesh *weld_mesh)
* \{ */
static void customdata_weld(
- const CustomData *source, CustomData *dest, const uint *src_indices, int count, int dest_index)
+ const CustomData *source, CustomData *dest, const int *src_indices, int count, int dest_index)
{
if (count == 1) {
CustomData_copy_data(source, dest, src_indices[0], dest_index, 1);
return;
}
- CustomData_interp(source, dest, (const int *)src_indices, NULL, NULL, count, dest_index);
+ CustomData_interp(source, dest, (const int *)src_indices, nullptr, nullptr, count, dest_index);
int src_i, dest_i;
int j;
@@ -1427,8 +1323,8 @@ static void customdata_weld(
#ifdef USE_WELD_NORMALS
float no[3] = {0.0f, 0.0f, 0.0f};
#endif
- uint crease = 0;
- uint bweight = 0;
+ int crease = 0;
+ int bweight = 0;
short flag = 0;
/* interpolates a layer at a time */
@@ -1572,7 +1468,7 @@ static bool bvhtree_weld_overlap_cb(void *userdata, int index_a, int index_b, in
/** Use for #MOD_WELD_MODE_CONNECTED calculation. */
struct WeldVertexCluster {
float co[3];
- uint merged_verts;
+ int merged_verts;
};
static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
@@ -1581,28 +1477,24 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
{
Mesh *result = mesh;
- BLI_bitmap *v_mask = NULL;
+ BLI_bitmap *v_mask = nullptr;
int v_mask_act = 0;
- const MVert *mvert;
- const MLoop *mloop;
- const MPoly *mpoly, *mp;
- uint totvert, totedge, totloop, totpoly;
+ Span<MVert> mvert{mesh->mvert, mesh->totvert};
+ int totvert, totedge, totloop, totpoly;
- mvert = mesh->mvert;
totvert = mesh->totvert;
/* Vertex Group. */
const int defgrp_index = BKE_id_defgroup_name_index(&mesh->id, wmd->defgrp_name);
if (defgrp_index != -1) {
- MDeformVert *dvert, *dv;
- dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
+ MDeformVert *dvert;
+ dvert = static_cast<MDeformVert *>(CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT));
if (dvert) {
const bool invert_vgroup = (wmd->flag & MOD_WELD_INVERT_VGROUP) != 0;
- dv = &dvert[0];
v_mask = BLI_BITMAP_NEW(totvert, __func__);
- for (uint i = 0; i < totvert; i++, dv++) {
- const bool found = BKE_defvert_find_weight(dv, defgrp_index) > 0.0f;
+ for (const int i : IndexRange(totvert)) {
+ const bool found = BKE_defvert_find_weight(&dvert[i], defgrp_index) > 0.0f;
if (found != invert_vgroup) {
BLI_BITMAP_ENABLE(v_mask, i);
v_mask_act++;
@@ -1613,15 +1505,15 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
/* From the original index of the vertex.
* This indicates which vert it is or is going to be merged. */
- uint *vert_dest_map = MEM_malloc_arrayN(totvert, sizeof(*vert_dest_map), __func__);
- uint vert_kill_len = 0;
+ Array<int> vert_dest_map(totvert);
+ int vert_kill_len = 0;
if (wmd->mode == MOD_WELD_MODE_ALL)
#ifdef USE_BVHTREEKDOP
{
/* Get overlap map. */
struct BVHTreeFromMesh treedata;
BVHTree *bvhtree = bvhtree_from_mesh_verts_ex(&treedata,
- mvert,
+ mvert.data(),
totvert,
false,
v_mask,
@@ -1630,8 +1522,8 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
2,
6,
0,
- NULL,
- NULL);
+ nullptr,
+ nullptr);
if (bvhtree) {
struct WeldOverlapData data;
@@ -1649,20 +1541,20 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
free_bvhtree_from_mesh(&treedata);
if (overlap) {
- range_vn_u(vert_dest_map, totvert, 0);
+ range_vn_i(vert_dest_map.data(), totvert, 0);
const BVHTreeOverlap *overlap_iter = &overlap[0];
- for (uint i = 0; i < overlap_len; i++, overlap_iter++) {
- uint indexA = overlap_iter->indexA;
- uint indexB = overlap_iter->indexB;
+ for (int i = 0; i < overlap_len; i++, overlap_iter++) {
+ int indexA = overlap_iter->indexA;
+ int indexB = overlap_iter->indexB;
BLI_assert(indexA < indexB);
- uint va_dst = vert_dest_map[indexA];
+ int va_dst = vert_dest_map[indexA];
while (va_dst != vert_dest_map[va_dst]) {
va_dst = vert_dest_map[va_dst];
}
- uint vb_dst = vert_dest_map[indexB];
+ int vb_dst = vert_dest_map[indexB];
while (vb_dst != vert_dest_map[vb_dst]) {
vb_dst = vert_dest_map[vb_dst];
}
@@ -1670,19 +1562,19 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
continue;
}
if (va_dst > vb_dst) {
- SWAP(uint, va_dst, vb_dst);
+ SWAP(int, va_dst, vb_dst);
}
vert_kill_len++;
vert_dest_map[vb_dst] = va_dst;
}
/* Fix #r_vert_dest_map for next step. */
- for (uint i = 0; i < totvert; i++) {
+ for (int i = 0; i < totvert; i++) {
if (i == vert_dest_map[i]) {
vert_dest_map[i] = OUT_OF_CONTEXT;
}
else {
- uint v = i;
+ int v = i;
while (v != vert_dest_map[v] && vert_dest_map[v] != OUT_OF_CONTEXT) {
v = vert_dest_map[v];
}
@@ -1698,7 +1590,7 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
#else
{
KDTree_3d *tree = BLI_kdtree_3d_new(v_mask ? v_mask_act : totvert);
- for (uint i = 0; i < totvert; i++) {
+ for (const int i : IndexRange(totvert)) {
if (!v_mask || BLI_BITMAP_TEST(v_mask, i)) {
BLI_kdtree_3d_insert(tree, i, mvert[i].co);
}
@@ -1707,37 +1599,34 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
BLI_kdtree_3d_balance(tree);
vert_kill_len = BLI_kdtree_3d_calc_duplicates_fast(
- tree, wmd->merge_dist, false, (int *)vert_dest_map);
+ tree, wmd->merge_dist, false, vert_dest_map.data());
BLI_kdtree_3d_free(tree);
}
#endif
else {
BLI_assert(wmd->mode == MOD_WELD_MODE_CONNECTED);
- MEdge *medge, *me;
+ Span<MEdge> medge{mesh->medge, mesh->totedge};
- medge = mesh->medge;
totvert = mesh->totvert;
- totedge = mesh->totedge;
- struct WeldVertexCluster *vert_clusters = MEM_malloc_arrayN(
- totvert, sizeof(*vert_clusters), __func__);
- struct WeldVertexCluster *vc = &vert_clusters[0];
- for (uint i = 0; i < totvert; i++, vc++) {
- copy_v3_v3(vc->co, mvert[i].co);
- vc->merged_verts = 0;
+ Array<WeldVertexCluster> vert_clusters(totvert);
+
+ for (const int i : mvert.index_range()) {
+ WeldVertexCluster &vc = vert_clusters[i];
+ copy_v3_v3(vc.co, mvert[i].co);
+ vc.merged_verts = 0;
}
const float merge_dist_sq = square_f(wmd->merge_dist);
- range_vn_u(vert_dest_map, totvert, 0);
+ range_vn_i(vert_dest_map.data(), totvert, 0);
/* Collapse Edges that are shorter than the threshold. */
- me = &medge[0];
- for (uint i = 0; i < totedge; i++, me++) {
- uint v1 = me->v1;
- uint v2 = me->v2;
+ for (const int i : medge.index_range()) {
+ int v1 = medge[i].v1;
+ int v2 = medge[i].v2;
- if (wmd->flag & MOD_WELD_LOOSE_EDGES && (me->flag & ME_LOOSEEDGE) == 0) {
+ if (wmd->flag & MOD_WELD_LOOSE_EDGES && (medge[i].flag & ME_LOOSEEDGE) == 0) {
continue;
}
while (v1 != vert_dest_map[v1]) {
@@ -1753,10 +1642,10 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
continue;
}
if (v1 > v2) {
- SWAP(uint, v1, v2);
+ SWAP(int, v1, v2);
}
- struct WeldVertexCluster *v1_cluster = &vert_clusters[v1];
- struct WeldVertexCluster *v2_cluster = &vert_clusters[v2];
+ WeldVertexCluster *v1_cluster = &vert_clusters[v1];
+ WeldVertexCluster *v2_cluster = &vert_clusters[v2];
float edgedir[3];
sub_v3_v3v3(edgedir, v2_cluster->co, v1_cluster->co);
@@ -1772,14 +1661,12 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
}
}
- MEM_freeN(vert_clusters);
-
- for (uint i = 0; i < totvert; i++) {
+ for (const int i : IndexRange(totvert)) {
if (i == vert_dest_map[i]) {
vert_dest_map[i] = OUT_OF_CONTEXT;
}
else {
- uint v = i;
+ int v = i;
while ((v != vert_dest_map[v]) && (vert_dest_map[v] != OUT_OF_CONTEXT)) {
v = vert_dest_map[v];
}
@@ -1797,8 +1684,8 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
WeldMesh weld_mesh;
weld_mesh_context_create(mesh, vert_dest_map, vert_kill_len, &weld_mesh);
- mloop = mesh->mloop;
- mpoly = mesh->mpoly;
+ Span<MLoop> mloop{mesh->mloop, mesh->totloop};
+ Span<MPoly> mpoly{mesh->mpoly, mesh->totpoly};
totedge = mesh->totedge;
totloop = mesh->totloop;
@@ -1814,10 +1701,10 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
/* Vertices */
- uint *vert_final = vert_dest_map;
- uint *index_iter = &vert_final[0];
+ int *vert_final = vert_dest_map.data();
+ int *index_iter = &vert_final[0];
int dest_index = 0;
- for (uint i = 0; i < totvert; i++, index_iter++) {
+ for (int i = 0; i < totvert; i++, index_iter++) {
int source_index = i;
int count = 0;
while (i < totvert && *index_iter == OUT_OF_CONTEXT) {
@@ -1849,10 +1736,10 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
/* Edges */
- uint *edge_final = weld_mesh.edge_groups_map;
+ int *edge_final = weld_mesh.edge_groups_map.data();
index_iter = &edge_final[0];
dest_index = 0;
- for (uint i = 0; i < totedge; i++, index_iter++) {
+ for (int i = 0; i < totedge; i++, index_iter++) {
int source_index = i;
int count = 0;
while (i < totedge && *index_iter == OUT_OF_CONTEXT) {
@@ -1894,18 +1781,18 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
/* Polys/Loops */
- mp = &mpoly[0];
MPoly *r_mp = &result->mpoly[0];
MLoop *r_ml = &result->mloop[0];
- uint r_i = 0;
+ int r_i = 0;
int loop_cur = 0;
- uint *group_buffer = BLI_array_alloca(group_buffer, weld_mesh.max_poly_len);
- for (uint i = 0; i < totpoly; i++, mp++) {
+ Array<int, 64> group_buffer(weld_mesh.max_poly_len);
+ for (const int i : mpoly.index_range()) {
+ const MPoly &mp = mpoly[i];
int loop_start = loop_cur;
- uint poly_ctx = weld_mesh.poly_map[i];
+ int poly_ctx = weld_mesh.poly_map[i];
if (poly_ctx == OUT_OF_CONTEXT) {
- uint mp_loop_len = mp->totloop;
- CustomData_copy_data(&mesh->ldata, &result->ldata, mp->loopstart, loop_cur, mp_loop_len);
+ int mp_loop_len = mp.totloop;
+ CustomData_copy_data(&mesh->ldata, &result->ldata, mp.loopstart, loop_cur, mp_loop_len);
loop_cur += mp_loop_len;
for (; mp_loop_len--; r_ml++) {
r_ml->v = vert_final[r_ml->v];
@@ -1913,20 +1800,21 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
}
}
else {
- WeldPoly *wp = &weld_mesh.wpoly[poly_ctx];
+ const WeldPoly &wp = weld_mesh.wpoly[poly_ctx];
WeldLoopOfPolyIter iter;
if (!weld_iter_loop_of_poly_begin(
- &iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer)) {
+ &iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer.data())) {
continue;
}
- if (wp->poly_dst != OUT_OF_CONTEXT) {
+ if (wp.poly_dst != OUT_OF_CONTEXT) {
continue;
}
while (weld_iter_loop_of_poly_next(&iter)) {
- customdata_weld(&mesh->ldata, &result->ldata, group_buffer, iter.group_len, loop_cur);
- uint v = vert_final[iter.v];
- uint e = edge_final[iter.e];
+ customdata_weld(
+ &mesh->ldata, &result->ldata, group_buffer.data(), iter.group_len, loop_cur);
+ int v = vert_final[iter.v];
+ int e = edge_final[iter.e];
r_ml->v = v;
r_ml->e = e;
r_ml++;
@@ -1945,22 +1833,23 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
r_i++;
}
- WeldPoly *wp = &weld_mesh.wpoly_new[0];
- for (uint i = 0; i < weld_mesh.wpoly_new_len; i++, wp++) {
+ for (const int i : IndexRange(weld_mesh.wpoly_new_len)) {
+ const WeldPoly &wp = weld_mesh.wpoly_new[i];
int loop_start = loop_cur;
WeldLoopOfPolyIter iter;
if (!weld_iter_loop_of_poly_begin(
- &iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer)) {
+ &iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer.data())) {
continue;
}
- if (wp->poly_dst != OUT_OF_CONTEXT) {
+ if (wp.poly_dst != OUT_OF_CONTEXT) {
continue;
}
while (weld_iter_loop_of_poly_next(&iter)) {
- customdata_weld(&mesh->ldata, &result->ldata, group_buffer, iter.group_len, loop_cur);
- uint v = vert_final[iter.v];
- uint e = edge_final[iter.e];
+ customdata_weld(
+ &mesh->ldata, &result->ldata, group_buffer.data(), iter.group_len, loop_cur);
+ int v = vert_final[iter.v];
+ int e = edge_final[iter.e];
r_ml->v = v;
r_ml->e = e;
r_ml++;
@@ -1982,11 +1871,8 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
/* is this needed? */
BKE_mesh_normals_tag_dirty(result);
-
- weld_mesh_context_free(&weld_mesh);
}
- MEM_freeN(vert_dest_map);
return result;
}
@@ -2027,12 +1913,12 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayoutSetPropSep(layout, true);
- uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "mode", 0, nullptr, ICON_NONE);
uiItemR(layout, ptr, "merge_threshold", 0, IFACE_("Distance"), ICON_NONE);
if (weld_mode == MOD_WELD_MODE_CONNECTED) {
- uiItemR(layout, ptr, "loose_edges", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "loose_edges", 0, nullptr, ICON_NONE);
}
- modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL);
+ modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", nullptr);
modifier_panel_end(layout, ptr);
}
@@ -2048,34 +1934,35 @@ ModifierTypeInfo modifierType_Weld = {
/* structSize */ sizeof(WeldModifierData),
/* srna */ &RNA_WeldModifier,
/* type */ eModifierTypeType_Constructive,
- /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
- eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode |
- eModifierTypeFlag_AcceptsCVs,
+ /* flags */
+ (ModifierTypeFlag)(eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
+ eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode |
+ eModifierTypeFlag_AcceptsCVs),
/* icon */ ICON_AUTOMERGE_OFF, /* TODO: Use correct icon. */
/* copyData */ BKE_modifier_copydata_generic,
- /* deformVerts */ NULL,
- /* deformMatrices */ NULL,
- /* deformVertsEM */ NULL,
- /* deformMatricesEM */ NULL,
+ /* deformVerts */ nullptr,
+ /* deformMatrices */ nullptr,
+ /* deformVertsEM */ nullptr,
+ /* deformMatricesEM */ nullptr,
/* modifyMesh */ modifyMesh,
- /* modifyHair */ NULL,
- /* modifyGeometrySet */ NULL,
+ /* modifyHair */ nullptr,
+ /* modifyGeometrySet */ nullptr,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
- /* freeData */ NULL,
- /* isDisabled */ NULL,
- /* updateDepsgraph */ NULL,
- /* dependsOnTime */ NULL,
- /* dependsOnNormals */ NULL,
- /* foreachIDLink */ NULL,
- /* foreachTexLink */ NULL,
- /* freeRuntimeData */ NULL,
+ /* freeData */ nullptr,
+ /* isDisabled */ nullptr,
+ /* updateDepsgraph */ nullptr,
+ /* dependsOnTime */ nullptr,
+ /* dependsOnNormals */ nullptr,
+ /* foreachIDLink */ nullptr,
+ /* foreachTexLink */ nullptr,
+ /* freeRuntimeData */ nullptr,
/* panelRegister */ panelRegister,
- /* blendWrite */ NULL,
- /* blendRead */ NULL,
+ /* blendWrite */ nullptr,
+ /* blendRead */ nullptr,
};
/** \} */
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 5f61d13a3af..2e2ff874f20 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -316,4 +316,8 @@ if(WITH_OPENVDB)
add_definitions(-DWITH_OPENVDB ${OPENVDB_DEFINITIONS})
endif()
+if(WITH_OPENIMAGEDENOISE)
+ add_definitions(-DWITH_OPENIMAGEDENOISE)
+endif()
+
blender_add_lib(bf_nodes "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index a0b8e237f19..c6efe6efb62 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -87,8 +87,8 @@ 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_spline_parameter(void);
+void register_node_type_geo_curve_spline_type(void);
void register_node_type_geo_curve_subdivide(void);
void register_node_type_geo_curve_to_mesh(void);
void register_node_type_geo_curve_to_points(void);
diff --git a/source/blender/nodes/NOD_node_declaration.hh b/source/blender/nodes/NOD_node_declaration.hh
index af2130ec452..4ad1bcad885 100644
--- a/source/blender/nodes/NOD_node_declaration.hh
+++ b/source/blender/nodes/NOD_node_declaration.hh
@@ -288,10 +288,13 @@ class NodeDeclarationBuilder {
/**
* 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.
+ * Calling field status definitions on each socket is unnecessary. Must be called before adding
+ * any sockets.
*/
void is_function_node(bool value = true)
{
+ BLI_assert_msg(declaration_.inputs().is_empty() && declaration_.outputs().is_empty(),
+ "is_function_node() must be called before any socket is created");
declaration_.is_function_node_ = value;
}
@@ -476,6 +479,10 @@ inline typename DeclType::Builder &NodeDeclarationBuilder::add_socket(StringRef
socket_decl->name_ = name;
socket_decl->identifier_ = identifier.is_empty() ? name : identifier;
socket_decl->in_out_ = in_out;
+ if (declaration_.is_function_node()) {
+ socket_decl->input_field_type_ = InputSocketFieldType::IsSupported;
+ socket_decl->output_field_dependency_ = OutputFieldDependency::ForDependentField();
+ }
declarations.append(std::move(socket_decl));
Builder &socket_decl_builder_ref = *socket_decl_builder;
builders_.append(std::move(socket_decl_builder));
diff --git a/source/blender/nodes/NOD_socket_declarations.hh b/source/blender/nodes/NOD_socket_declarations.hh
index 3fb21a4263d..c0ba949e337 100644
--- a/source/blender/nodes/NOD_socket_declarations.hh
+++ b/source/blender/nodes/NOD_socket_declarations.hh
@@ -231,7 +231,7 @@ class Shader : public SocketDeclaration {
bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
- bool can_connect(const bNodeSocket &socket) const;
+ bool can_connect(const bNodeSocket &socket) const override;
};
class ShaderBuilder : public SocketDeclarationBuilder<Shader> {
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 84bc7bf0ceb..0c6e42deb27 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -323,9 +323,9 @@ DefNode(GeometryNode, GEO_NODE_LEGACY_SELECT_BY_MATERIAL, 0, "LEGACY_SELECT_BY_M
DefNode(GeometryNode, GEO_NODE_LEGACY_SUBDIVISION_SURFACE, def_geo_subdivision_surface, "LEGACY_SUBDIVISION_SURFACE", LegacySubdivisionSurface, "Subdivision Surface", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_VOLUME_TO_MESH, def_geo_volume_to_mesh, "LEGACY_VOLUME_TO_MESH", LegacyVolumeToMesh, "Volume to Mesh", "")
+DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, def_geo_attribute_domain_size, "ATTRIBUTE_DOMAIN_SIZE", AttributeDomainSize, "Domain Size", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_REMOVE, 0, "ATTRIBUTE_REMOVE", AttributeRemove, "Attribute Remove", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_STATISTIC, def_geo_attribute_statistic, "ATTRIBUTE_STATISTIC", AttributeStatistic, "Attribute Statistic", "")
-DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, def_geo_attribute_domain_size, "ATTRIBUTE_DOMAIN_SIZE", AttributeDomainSize, "Domain Size", "")
DefNode(GeometryNode, GEO_NODE_BOUNDING_BOX, 0, "BOUNDING_BOX", BoundBox, "Bounding Box", "")
DefNode(GeometryNode, GEO_NODE_CAPTURE_ATTRIBUTE, def_geo_attribute_capture, "CAPTURE_ATTRIBUTE", CaptureAttribute, "Capture Attribute", "")
DefNode(GeometryNode, GEO_NODE_COLLECTION_INFO, def_geo_collection_info, "COLLECTION_INFO", CollectionInfo, "Collection Info", "")
@@ -333,7 +333,6 @@ DefNode(GeometryNode, GEO_NODE_CONVEX_HULL, 0, "CONVEX_HULL", ConvexHull, "Conve
DefNode(GeometryNode, GEO_NODE_CURVE_ENDPOINT_SELECTION, 0, "CURVE_ENDPOINT_SELECTION", CurveEndpointSelection, "Endpoint Selection", "")
DefNode(GeometryNode, GEO_NODE_CURVE_HANDLE_TYPE_SELECTION, def_geo_curve_handle_type_selection, "CURVE_HANDLE_TYPE_SELECTION", CurveHandleTypeSelection, "Handle Type Selection", "")
DefNode(GeometryNode, GEO_NODE_CURVE_LENGTH, 0, "CURVE_LENGTH", CurveLength, "Curve Length", "")
-DefNode(GeometryNode, GEO_NODE_CURVE_SPLINE_PARAMETER, 0, "SPLINE_PARAMETER", SplineParameter, "Spline Parameter", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT, def_geo_curve_primitive_bezier_segment, "CURVE_PRIMITIVE_BEZIER_SEGMENT", CurvePrimitiveBezierSegment, "Bezier Segment", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, def_geo_curve_primitive_circle, "CURVE_PRIMITIVE_CIRCLE", CurvePrimitiveCircle, "Curve Circle", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_LINE, def_geo_curve_primitive_line, "CURVE_PRIMITIVE_LINE", CurvePrimitiveLine, "Curve Line", "")
@@ -342,6 +341,7 @@ 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_SET_HANDLES, def_geo_curve_set_handles, "CURVE_SET_HANDLES", CurveSetHandles, "Set Handle Type", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_SPLINE_PARAMETER, 0, "SPLINE_PARAMETER", SplineParameter, "Spline Parameter", "")
DefNode(GeometryNode, GEO_NODE_CURVE_SPLINE_TYPE, def_geo_curve_spline_type, "CURVE_SPLINE_TYPE", CurveSplineType, "Set Spline Type", "")
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", "")
diff --git a/source/blender/nodes/composite/node_composite_tree.cc b/source/blender/nodes/composite/node_composite_tree.cc
index 1326c9edab1..54967c82562 100644
--- a/source/blender/nodes/composite/node_composite_tree.cc
+++ b/source/blender/nodes/composite/node_composite_tree.cc
@@ -33,6 +33,7 @@
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_tracking.h"
#include "node_common.h"
@@ -186,11 +187,6 @@ static void update(bNodeTree *ntree)
ntreeSetOutput(ntree);
ntree_update_reroute_nodes(ntree);
-
- if (ntree->update & NTREE_UPDATE_NODES) {
- /* clean up preview cache, in case nodes have been removed */
- BKE_node_preview_remove_unused(ntree);
- }
}
static void composite_node_add_init(bNodeTree *UNUSED(bnodetree), bNode *bnode)
@@ -301,14 +297,15 @@ void ntreeCompositTagRender(Scene *scene)
if (sce_iter->nodetree) {
LISTBASE_FOREACH (bNode *, node, &sce_iter->nodetree->nodes) {
if (node->id == (ID *)scene || node->type == CMP_NODE_COMPOSITE) {
- nodeUpdate(sce_iter->nodetree, node);
+ BKE_ntree_update_tag_node_property(sce_iter->nodetree, node);
}
else if (node->type == CMP_NODE_TEXTURE) /* uses scene size_x/size_y */ {
- nodeUpdate(sce_iter->nodetree, node);
+ BKE_ntree_update_tag_node_property(sce_iter->nodetree, node);
}
}
}
}
+ BKE_ntree_update_main(G_MAIN, nullptr);
}
/* XXX after render animation system gets a refresh, this call allows composite to end clean */
diff --git a/source/blender/nodes/composite/nodes/node_composite_denoise.cc b/source/blender/nodes/composite/nodes/node_composite_denoise.cc
index f1e5388a7a3..17bad211dec 100644
--- a/source/blender/nodes/composite/nodes/node_composite_denoise.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_denoise.cc
@@ -23,6 +23,8 @@
* \ingroup cmpnodes
*/
+#include "BLI_system.h"
+
#include "UI_interface.h"
#include "UI_resources.h"
diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt
index f9a64381981..c24f8849532 100644
--- a/source/blender/nodes/geometry/CMakeLists.txt
+++ b/source/blender/nodes/geometry/CMakeLists.txt
@@ -105,8 +105,8 @@ set(SRC
nodes/node_geo_curve_reverse.cc
nodes/node_geo_curve_sample.cc
nodes/node_geo_curve_set_handles.cc
- nodes/node_geo_curve_spline_type.cc
nodes/node_geo_curve_spline_parameter.cc
+ nodes/node_geo_curve_spline_type.cc
nodes/node_geo_curve_subdivide.cc
nodes/node_geo_curve_to_mesh.cc
nodes/node_geo_curve_to_points.cc
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc
index 4366c6f9234..b4e1b671d15 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc
@@ -53,8 +53,8 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryAlignRotationToVector *node_storage = (NodeGeometryAlignRotationToVector *)
- MEM_callocN(sizeof(NodeGeometryAlignRotationToVector), __func__);
+ NodeGeometryAlignRotationToVector *node_storage = MEM_cnew<NodeGeometryAlignRotationToVector>(
+ __func__);
node_storage->axis = GEO_NODE_ALIGN_ROTATION_TO_VECTOR_AXIS_X;
node_storage->input_type_factor = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc
index 7435152a966..a103709d284 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc
@@ -46,8 +46,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeClamp *data = (NodeAttributeClamp *)MEM_callocN(sizeof(NodeAttributeClamp),
- __func__);
+ NodeAttributeClamp *data = MEM_cnew<NodeAttributeClamp>(__func__);
data->data_type = CD_PROP_FLOAT;
data->operation = NODE_CLAMP_MINMAX;
node->storage = data;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc
index 4efdf786e4e..fe3fb872238 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc
@@ -40,8 +40,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeAttributeColorRamp *node_storage = (NodeAttributeColorRamp *)MEM_callocN(
- sizeof(NodeAttributeColorRamp), __func__);
+ NodeAttributeColorRamp *node_storage = MEM_cnew<NodeAttributeColorRamp>(__func__);
BKE_colorband_init(&node_storage->color_ramp, true);
node->storage = node_storage;
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc
index 7ba64c8db2b..3065ea3d7a1 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc
@@ -46,8 +46,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeCombineXYZ *data = (NodeAttributeCombineXYZ *)MEM_callocN(
- sizeof(NodeAttributeCombineXYZ), __func__);
+ NodeAttributeCombineXYZ *data = MEM_cnew<NodeAttributeCombineXYZ>(__func__);
data->input_type_x = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
data->input_type_y = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc
index 8aa1adb0cf3..3a973610cc4 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc
@@ -50,8 +50,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeCompare *data = (NodeAttributeCompare *)MEM_callocN(sizeof(NodeAttributeCompare),
- __func__);
+ NodeAttributeCompare *data = MEM_cnew<NodeAttributeCompare>(__func__);
data->operation = NODE_COMPARE_GREATER_THAN;
data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
data->input_type_b = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc
index 28c133871f7..b729eec87f8 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc
@@ -39,8 +39,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeConvert *data = (NodeAttributeConvert *)MEM_callocN(sizeof(NodeAttributeConvert),
- __func__);
+ NodeAttributeConvert *data = MEM_cnew<NodeAttributeConvert>(__func__);
data->data_type = CD_AUTO_FROM_NAME;
data->domain = ATTR_DOMAIN_AUTO;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc
index 0a7b5dd8463..4bef8f658a9 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc
@@ -75,8 +75,7 @@ static void node_copy_storage(bNodeTree *UNUSED(dest_ntree),
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)MEM_callocN(sizeof(NodeAttributeCurveMap),
- __func__);
+ NodeAttributeCurveMap *data = MEM_cnew<NodeAttributeCurveMap>(__func__);
data->data_type = CD_PROP_FLOAT;
data->curve_vec = BKE_curvemapping_add(4, -1.0f, -1.0f, 1.0f, 1.0f);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc
index 8ebcf34ad0b..9bc1eaaa368 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc
@@ -51,8 +51,7 @@ static void fn_attribute_map_range_layout(uiLayout *layout, bContext *UNUSED(C),
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeAttributeMapRange *data = (NodeAttributeMapRange *)MEM_callocN(sizeof(NodeAttributeMapRange),
- __func__);
+ NodeAttributeMapRange *data = MEM_cnew<NodeAttributeMapRange>(__func__);
data->data_type = CD_PROP_FLOAT;
data->interpolation_type = NODE_MAP_RANGE_LINEAR;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc
index e0a829b4100..3deaecad26d 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc
@@ -121,7 +121,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeMath *data = (NodeAttributeMath *)MEM_callocN(sizeof(NodeAttributeMath), __func__);
+ NodeAttributeMath *data = MEM_cnew<NodeAttributeMath>(__func__);
data->operation = NODE_MATH_ADD;
data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc
index 4a110e9690a..20cc285f3a5 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc
@@ -61,8 +61,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeAttributeMix *data = (NodeAttributeMix *)MEM_callocN(sizeof(NodeAttributeMix),
- "attribute mix node");
+ NodeAttributeMix *data = MEM_cnew<NodeAttributeMix>("attribute mix node");
data->blend_type = MA_RAMP_BLEND;
data->input_type_factor = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc
index 080bf38a740..e1b7f9452f3 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc
@@ -44,8 +44,8 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryAttributeProximity *node_storage = (NodeGeometryAttributeProximity *)MEM_callocN(
- sizeof(NodeGeometryAttributeProximity), __func__);
+ NodeGeometryAttributeProximity *node_storage = MEM_cnew<NodeGeometryAttributeProximity>(
+ __func__);
node_storage->target_geometry_element = GEO_NODE_PROXIMITY_TARGET_FACES;
node->storage = node_storage;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc
index ab2bc7b379c..f0aa8361e6e 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc
@@ -81,8 +81,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeRandomize *data = (NodeAttributeRandomize *)MEM_callocN(
- sizeof(NodeAttributeRandomize), __func__);
+ NodeAttributeRandomize *data = MEM_cnew<NodeAttributeRandomize>(__func__);
data->data_type = CD_PROP_FLOAT;
data->domain = ATTR_DOMAIN_POINT;
data->operation = GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc
index c5aac118baf..c30a9d3a7dd 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc
@@ -41,8 +41,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeSeparateXYZ *data = (NodeAttributeSeparateXYZ *)MEM_callocN(
- sizeof(NodeAttributeSeparateXYZ), __func__);
+ NodeAttributeSeparateXYZ *data = MEM_cnew<NodeAttributeSeparateXYZ>(__func__);
data->input_type = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
node->storage = data;
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc
index 686edc80f62..2552308a8c2 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc
@@ -50,8 +50,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryAttributeTransfer *data = (NodeGeometryAttributeTransfer *)MEM_callocN(
- sizeof(NodeGeometryAttributeTransfer), __func__);
+ NodeGeometryAttributeTransfer *data = MEM_cnew<NodeGeometryAttributeTransfer>(__func__);
data->domain = ATTR_DOMAIN_AUTO;
node->storage = data;
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc
index 68051e81f57..c9e8ce88b25 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc
@@ -103,8 +103,7 @@ static CustomDataType operation_get_read_type_c(const NodeVectorMathOperation op
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeVectorMath *data = (NodeAttributeVectorMath *)MEM_callocN(
- sizeof(NodeAttributeVectorMath), __func__);
+ NodeAttributeVectorMath *data = MEM_cnew<NodeAttributeVectorMath>(__func__);
data->operation = NODE_VECTOR_MATH_ADD;
data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc
index 1ef50e69775..bdc09eb3408 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc
@@ -112,8 +112,7 @@ static float3 vector_rotate_around_axis(const float3 vector,
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeAttributeVectorRotate *node_storage = (NodeAttributeVectorRotate *)MEM_callocN(
- sizeof(NodeAttributeVectorRotate), __func__);
+ NodeAttributeVectorRotate *node_storage = MEM_cnew<NodeAttributeVectorRotate>(__func__);
node_storage->mode = GEO_NODE_VECTOR_ROTATE_TYPE_AXIS;
node_storage->input_type_vector = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc
index c702e9ff686..e86b0f225e3 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc
@@ -40,8 +40,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSelectHandles *data = (NodeGeometryCurveSelectHandles *)MEM_callocN(
- sizeof(NodeGeometryCurveSelectHandles), __func__);
+ NodeGeometryCurveSelectHandles *data = MEM_cnew<NodeGeometryCurveSelectHandles>(__func__);
data->handle_type = GEO_NODE_CURVE_HANDLE_AUTO;
data->mode = GEO_NODE_CURVE_HANDLE_LEFT | GEO_NODE_CURVE_HANDLE_RIGHT;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc
index 1e476d01148..b4106e69bbd 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc
@@ -38,8 +38,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSetHandles *data = (NodeGeometryCurveSetHandles *)MEM_callocN(
- sizeof(NodeGeometryCurveSetHandles), __func__);
+ NodeGeometryCurveSetHandles *data = MEM_cnew<NodeGeometryCurveSetHandles>(__func__);
data->handle_type = GEO_NODE_CURVE_HANDLE_AUTO;
data->mode = GEO_NODE_CURVE_HANDLE_LEFT | GEO_NODE_CURVE_HANDLE_RIGHT;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc
index f3599f4328f..cbd4e3b29f2 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc
@@ -39,8 +39,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSplineType *data = (NodeGeometryCurveSplineType *)MEM_callocN(
- sizeof(NodeGeometryCurveSplineType), __func__);
+ NodeGeometryCurveSplineType *data = MEM_cnew<NodeGeometryCurveSplineType>(__func__);
data->spline_type = GEO_NODE_SPLINE_TYPE_POLY;
node->storage = data;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc
index 9878402dd35..e4db622ad52 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc
@@ -44,8 +44,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSubdivide *data = (NodeGeometryCurveSubdivide *)MEM_callocN(
- sizeof(NodeGeometryCurveSubdivide), __func__);
+ NodeGeometryCurveSubdivide *data = MEM_cnew<NodeGeometryCurveSubdivide>(__func__);
data->cuts_type = GEO_NODE_ATTRIBUTE_INPUT_INTEGER;
node->storage = data;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc
index 3bd03f3cee0..a5d135582eb 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc
@@ -95,8 +95,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveToPoints *data = (NodeGeometryCurveToPoints *)MEM_callocN(
- sizeof(NodeGeometryCurveToPoints), __func__);
+ NodeGeometryCurveToPoints *data = MEM_cnew<NodeGeometryCurveToPoints>(__func__);
data->mode = GEO_NODE_CURVE_RESAMPLE_COUNT;
node->storage = data;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc
index 8915a58feb1..61fea9fee11 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc
@@ -46,8 +46,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryPointInstance *data = (NodeGeometryPointInstance *)MEM_callocN(
- sizeof(NodeGeometryPointInstance), __func__);
+ NodeGeometryPointInstance *data = MEM_cnew<NodeGeometryPointInstance>(__func__);
data->instance_type = GEO_NODE_POINT_INSTANCE_TYPE_OBJECT;
data->flag |= GEO_NODE_POINT_INSTANCE_WHOLE_COLLECTION;
node->storage = data;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc
index a0a7674797a..26fae8093a5 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc
@@ -59,8 +59,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryRotatePoints *node_storage = (NodeGeometryRotatePoints *)MEM_callocN(
- sizeof(NodeGeometryRotatePoints), __func__);
+ NodeGeometryRotatePoints *node_storage = MEM_cnew<NodeGeometryRotatePoints>(__func__);
node_storage->type = GEO_NODE_POINT_ROTATE_TYPE_EULER;
node_storage->space = GEO_NODE_POINT_ROTATE_SPACE_OBJECT;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc
index d38df124979..bf2db79515e 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc
@@ -43,8 +43,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryPointScale *data = (NodeGeometryPointScale *)MEM_callocN(
- sizeof(NodeGeometryPointScale), __func__);
+ NodeGeometryPointScale *data = MEM_cnew<NodeGeometryPointScale>(__func__);
data->input_type = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
node->storage = data;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc
index c70478182ec..555bd228ac6 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc
@@ -74,8 +74,7 @@ static void node_geo_exec(GeoNodeExecParams params)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryPointTranslate *data = (NodeGeometryPointTranslate *)MEM_callocN(
- sizeof(NodeGeometryPointTranslate), __func__);
+ NodeGeometryPointTranslate *data = MEM_cnew<NodeGeometryPointTranslate>(__func__);
data->input_type = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
node->storage = data;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc
index ec1ab67b530..a0cddab702b 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc
@@ -51,8 +51,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)MEM_callocN(
- sizeof(NodeGeometryPointsToVolume), __func__);
+ NodeGeometryPointsToVolume *data = MEM_cnew<NodeGeometryPointsToVolume>(__func__);
data->resolution_mode = GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT;
data->input_type_radius = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
node->storage = data;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc
index 599ffd617a5..5a950114840 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc
@@ -58,8 +58,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryRaycast *data = (NodeGeometryRaycast *)MEM_callocN(sizeof(NodeGeometryRaycast),
- __func__);
+ NodeGeometryRaycast *data = MEM_cnew<NodeGeometryRaycast>(__func__);
data->input_type_ray_direction = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
data->input_type_ray_length = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
node->storage = data;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc
index 819ffb2c20c..dca5c58d164 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc
@@ -47,8 +47,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometrySubdivisionSurface *data = (NodeGeometrySubdivisionSurface *)MEM_callocN(
- sizeof(NodeGeometrySubdivisionSurface), __func__);
+ NodeGeometrySubdivisionSurface *data = MEM_cnew<NodeGeometrySubdivisionSurface>(__func__);
data->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES;
data->boundary_smooth = SUBSURF_BOUNDARY_SMOOTH_ALL;
node->storage = data;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc
index acff0be7126..77ace8d072a 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc
@@ -57,8 +57,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)MEM_callocN(
- sizeof(NodeGeometryVolumeToMesh), __func__);
+ NodeGeometryVolumeToMesh *data = MEM_cnew<NodeGeometryVolumeToMesh>(__func__);
data->resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_GRID;
bNodeSocket *grid_socket = nodeFindSocket(node, SOCK_IN, "Density");
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 be0baa706af..6c4dd96ea9c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
@@ -54,8 +54,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryAttributeCapture *data = (NodeGeometryAttributeCapture *)MEM_callocN(
- sizeof(NodeGeometryAttributeCapture), __func__);
+ NodeGeometryAttributeCapture *data = MEM_cnew<NodeGeometryAttributeCapture>(__func__);
data->data_type = CD_PROP_FLOAT;
data->domain = ATTR_DOMAIN_POINT;
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 3aabf8e21eb..92dbca060b2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
@@ -48,8 +48,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryCurveFill *data = (NodeGeometryCurveFill *)MEM_callocN(sizeof(NodeGeometryCurveFill),
- __func__);
+ NodeGeometryCurveFill *data = MEM_cnew<NodeGeometryCurveFill>(__func__);
data->mode = GEO_NODE_CURVE_FILL_MODE_TRIANGULATED;
node->storage = data;
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 a438c1d6086..f69f773ce21 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
@@ -55,8 +55,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveFillet *data = (NodeGeometryCurveFillet *)MEM_callocN(
- sizeof(NodeGeometryCurveFillet), __func__);
+ NodeGeometryCurveFillet *data = MEM_cnew<NodeGeometryCurveFillet>(__func__);
data->mode = GEO_NODE_CURVE_FILLET_BEZIER;
node->storage = data;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
index 381bb0fc1d0..50eb5dfc1a1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
@@ -38,8 +38,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSelectHandles *data = (NodeGeometryCurveSelectHandles *)MEM_callocN(
- sizeof(NodeGeometryCurveSelectHandles), __func__);
+ NodeGeometryCurveSelectHandles *data = MEM_cnew<NodeGeometryCurveSelectHandles>(__func__);
data->handle_type = GEO_NODE_CURVE_HANDLE_AUTO;
data->mode = GEO_NODE_CURVE_HANDLE_LEFT | GEO_NODE_CURVE_HANDLE_RIGHT;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
index 4299b5cc022..a9829b64150 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
@@ -62,8 +62,8 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurvePrimitiveBezierSegment *data = (NodeGeometryCurvePrimitiveBezierSegment *)
- MEM_callocN(sizeof(NodeGeometryCurvePrimitiveBezierSegment), __func__);
+ NodeGeometryCurvePrimitiveBezierSegment *data =
+ MEM_cnew<NodeGeometryCurvePrimitiveBezierSegment>(__func__);
data->mode = GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT_POSITION;
node->storage = data;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
index 70abf4c64a7..6d689b907fc 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
@@ -68,8 +68,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurvePrimitiveCircle *data = (NodeGeometryCurvePrimitiveCircle *)MEM_callocN(
- sizeof(NodeGeometryCurvePrimitiveCircle), __func__);
+ NodeGeometryCurvePrimitiveCircle *data = MEM_cnew<NodeGeometryCurvePrimitiveCircle>(__func__);
data->mode = GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS;
node->storage = data;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
index 6d71c97b15a..592374ddd81 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
@@ -52,8 +52,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurvePrimitiveLine *data = (NodeGeometryCurvePrimitiveLine *)MEM_callocN(
- sizeof(NodeGeometryCurvePrimitiveLine), __func__);
+ NodeGeometryCurvePrimitiveLine *data = MEM_cnew<NodeGeometryCurvePrimitiveLine>(__func__);
data->mode = GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS;
node->storage = data;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
index ff6294b9b6b..98480971fbd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
@@ -89,8 +89,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurvePrimitiveQuad *data = (NodeGeometryCurvePrimitiveQuad *)MEM_callocN(
- sizeof(NodeGeometryCurvePrimitiveQuad), __func__);
+ NodeGeometryCurvePrimitiveQuad *data = MEM_cnew<NodeGeometryCurvePrimitiveQuad>(__func__);
data->mode = GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE;
node->storage = data;
}
@@ -113,35 +112,26 @@ static void node_update(bNodeTree *ntree, bNode *node)
bNodeSocket *p3 = p2->next;
bNodeSocket *p4 = p3->next;
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
- nodeSetSocketAvailability(ntree, sock, false);
- }
+ Vector<bNodeSocket *> available_sockets;
if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE) {
- nodeSetSocketAvailability(ntree, width, true);
- nodeSetSocketAvailability(ntree, height, true);
+ available_sockets.extend({width, height});
}
else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_PARALLELOGRAM) {
- nodeSetSocketAvailability(ntree, width, true);
- nodeSetSocketAvailability(ntree, height, true);
- nodeSetSocketAvailability(ntree, offset, true);
+ available_sockets.extend({width, height, offset});
}
else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID) {
- nodeSetSocketAvailability(ntree, bottom, true);
- nodeSetSocketAvailability(ntree, top, true);
- nodeSetSocketAvailability(ntree, offset, true);
- nodeSetSocketAvailability(ntree, height, true);
+ available_sockets.extend({bottom, top, offset, height});
}
else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_KITE) {
- nodeSetSocketAvailability(ntree, width, true);
- nodeSetSocketAvailability(ntree, bottom_height, true);
- nodeSetSocketAvailability(ntree, top_height, true);
+ available_sockets.extend({width, bottom_height, top_height});
}
else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_POINTS) {
- nodeSetSocketAvailability(ntree, p1, true);
- nodeSetSocketAvailability(ntree, p2, true);
- nodeSetSocketAvailability(ntree, p3, true);
- nodeSetSocketAvailability(ntree, p4, true);
+ available_sockets.extend({p1, p2, p3, p4});
+ }
+
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ nodeSetSocketAvailability(ntree, sock, available_sockets.contains(sock));
}
}
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 7e465714265..741dad95362 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
@@ -50,8 +50,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveResample *data = (NodeGeometryCurveResample *)MEM_callocN(
- sizeof(NodeGeometryCurveResample), __func__);
+ NodeGeometryCurveResample *data = MEM_cnew<NodeGeometryCurveResample>(__func__);
data->mode = GEO_NODE_CURVE_RESAMPLE_COUNT;
node->storage = data;
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 8c0827570c6..0124e9bd9dd 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
@@ -40,8 +40,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSetHandles *data = (NodeGeometryCurveSetHandles *)MEM_callocN(
- sizeof(NodeGeometryCurveSetHandles), __func__);
+ NodeGeometryCurveSetHandles *data = MEM_cnew<NodeGeometryCurveSetHandles>(__func__);
data->handle_type = GEO_NODE_CURVE_HANDLE_AUTO;
data->mode = GEO_NODE_CURVE_HANDLE_LEFT;
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 eef8c1b0db5..2d07ac5411f 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
@@ -41,8 +41,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSplineType *data = (NodeGeometryCurveSplineType *)MEM_callocN(
- sizeof(NodeGeometryCurveSplineType), __func__);
+ NodeGeometryCurveSplineType *data = MEM_cnew<NodeGeometryCurveSplineType>(__func__);
data->spline_type = GEO_NODE_SPLINE_TYPE_POLY;
node->storage = data;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
index 0e9425246cb..d20fd66017e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
@@ -72,8 +72,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveToPoints *data = (NodeGeometryCurveToPoints *)MEM_callocN(
- sizeof(NodeGeometryCurveToPoints), __func__);
+ NodeGeometryCurveToPoints *data = MEM_cnew<NodeGeometryCurveToPoints>(__func__);
data->mode = GEO_NODE_CURVE_RESAMPLE_COUNT;
node->storage = data;
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 746392a66cc..2f96696cee4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
@@ -67,8 +67,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveTrim *data = (NodeGeometryCurveTrim *)MEM_callocN(sizeof(NodeGeometryCurveTrim),
- __func__);
+ NodeGeometryCurveTrim *data = MEM_cnew<NodeGeometryCurveTrim>(__func__);
data->mode = GEO_NODE_CURVE_SAMPLE_FACTOR;
node->storage = data;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
index 1de809b30e4..a5197b23adb 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
@@ -979,8 +979,8 @@ static void do_mesh_separation(GeometrySet &geometry_set,
/* Needed in all cases. */
Vector<int> selected_poly_indices;
Vector<int> new_loop_starts;
- int num_selected_polys;
- int num_selected_loops;
+ int num_selected_polys = 0;
+ int num_selected_loops = 0;
const Mesh &mesh_in = *in_component.get_for_read();
Mesh *mesh_out;
@@ -1307,8 +1307,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryDeleteGeometry *data = (NodeGeometryDeleteGeometry *)MEM_callocN(
- sizeof(NodeGeometryDeleteGeometry), __func__);
+ NodeGeometryDeleteGeometry *data = MEM_cnew<NodeGeometryDeleteGeometry>(__func__);
data->domain = ATTR_DOMAIN_POINT;
data->mode = GEO_NODE_DELETE_GEOMETRY_MODE_ALL;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
index a3bbeca7af3..d1cbaa540d7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
@@ -537,6 +537,77 @@ static void add_edge(const Mesh &mesh,
loop_edges.append(new_edge_i);
}
+/* Returns true if the vertex is connected only to the two polygons and is not on the boundary. */
+static bool vertex_needs_dissolving(const int vertex,
+ const int first_poly_index,
+ const int second_poly_index,
+ const Span<VertexType> vertex_types,
+ const Span<Vector<int>> vertex_poly_indices)
+{
+ /* Order is guaranteed to be the same because 2poly verts that are not on the boundary are
+ * ignored in `sort_vertex_polys`. */
+ return (vertex_types[vertex] != VertexType::Boundary &&
+ vertex_poly_indices[vertex].size() == 2 &&
+ vertex_poly_indices[vertex][0] == first_poly_index &&
+ vertex_poly_indices[vertex][1] == second_poly_index);
+}
+
+/**
+ * Finds 'normal' vertices which are connected to only two polygons and marks them to not be
+ * used in the datastructures derived from the mesh. For each pair of polygons which has such a
+ * vertex, an edge is created for the dual mesh between the centers of those two polygons. All
+ * edges in the input mesh which contain such a vertex are marked as 'done' to prevent duplicate
+ * edges being created. (See T94144)
+ */
+static void dissolve_redundant_verts(const Mesh &mesh,
+ const Span<Vector<int>> vertex_poly_indices,
+ MutableSpan<VertexType> vertex_types,
+ MutableSpan<int> old_to_new_edges_map,
+ Vector<MEdge> &new_edges,
+ Vector<int> &new_to_old_edges_map)
+{
+ for (const int vert_i : IndexRange(mesh.totvert)) {
+ if (vertex_poly_indices[vert_i].size() != 2 || vertex_types[vert_i] != VertexType::Normal) {
+ continue;
+ }
+ const int first_poly_index = vertex_poly_indices[vert_i][0];
+ const int second_poly_index = vertex_poly_indices[vert_i][1];
+ const int new_edge_index = new_edges.size();
+ bool edge_created = false;
+ const MPoly &poly = mesh.mpoly[first_poly_index];
+ for (const MLoop &loop : Span<MLoop>(&mesh.mloop[poly.loopstart], poly.totloop)) {
+ const MEdge &edge = mesh.medge[loop.e];
+ const int v1 = edge.v1;
+ const int v2 = edge.v2;
+ bool mark_edge = false;
+ if (vertex_needs_dissolving(
+ v1, first_poly_index, second_poly_index, vertex_types, vertex_poly_indices)) {
+ /* This vertex is now 'removed' and should be ignored elsewhere. */
+ vertex_types[v1] = VertexType::Loose;
+ mark_edge = true;
+ }
+ if (vertex_needs_dissolving(
+ v2, first_poly_index, second_poly_index, vertex_types, vertex_poly_indices)) {
+ /* This vertex is now 'removed' and should be ignored elsewhere. */
+ vertex_types[v2] = VertexType::Loose;
+ mark_edge = true;
+ }
+ if (mark_edge) {
+ if (!edge_created) {
+ MEdge new_edge = MEdge(edge);
+ /* The vertex indices in the dual mesh are the polygon indices of the input mesh. */
+ new_edge.v1 = first_poly_index;
+ new_edge.v2 = second_poly_index;
+ new_to_old_edges_map.append(loop.e);
+ new_edges.append(new_edge);
+ edge_created = true;
+ }
+ old_to_new_edges_map[loop.e] = new_edge_index;
+ }
+ }
+ }
+}
+
/**
* Calculate the barycentric dual of a mesh. The dual is only "dual" in terms of connectivity,
* i.e. applying the function twice will give the same vertices, edges, and faces, but not the
@@ -564,6 +635,9 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
Array<VertexType> vertex_types(mesh_in.totvert);
Array<EdgeType> edge_types(mesh_in.totedge);
calc_boundaries(mesh_in, vertex_types, edge_types);
+ /* Stores the indices of the polygons connected to the vertex. Because the polygons are looped
+ * over in order of their indices, the polygon's indices will be sorted in ascending order.
+ (This can change once they are sorted using `sort_vertex_polys`). */
Array<Vector<int>> vertex_poly_indices(mesh_in.totvert);
Array<Array<int>> vertex_shared_edges(mesh_in.totvert);
Array<Array<int>> vertex_corners(mesh_in.totvert);
@@ -632,6 +706,16 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
* don't need a hashmap for that. */
Array<int> old_to_new_edges_map(mesh_in.totedge);
old_to_new_edges_map.fill(-1);
+
+ /* This is necessary to prevent duplicate edges from being created, but will likely not do
+ * anything for most meshes. */
+ dissolve_redundant_verts(mesh_in,
+ vertex_poly_indices,
+ vertex_types,
+ old_to_new_edges_map,
+ new_edges,
+ new_to_old_edges_map);
+
for (const int i : IndexRange(mesh_in.totvert)) {
if (vertex_types[i] == VertexType::Loose || vertex_types[i] >= VertexType::NonManifold ||
(!keep_boundaries && vertex_types[i] == VertexType::Boundary)) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc b/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc
index 0003f15854d..52ef48f147b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc
@@ -55,8 +55,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryImageTexture *tex = (NodeGeometryImageTexture *)MEM_callocN(
- sizeof(NodeGeometryImageTexture), __func__);
+ NodeGeometryImageTexture *tex = MEM_cnew<NodeGeometryImageTexture>(__func__);
node->storage = tex;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
index 7a1cb8a62a3..503915872d6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
@@ -52,8 +52,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryMeshCircle *node_storage = (NodeGeometryMeshCircle *)MEM_callocN(
- sizeof(NodeGeometryMeshCircle), __func__);
+ NodeGeometryMeshCircle *node_storage = MEM_cnew<NodeGeometryMeshCircle>(__func__);
node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NONE;
@@ -214,8 +213,6 @@ static void node_geo_exec(GeoNodeExecParams params)
Mesh *mesh = create_circle_mesh(radius, verts_num, fill);
- BLI_assert(BKE_mesh_is_valid(mesh));
-
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
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 70b093798f8..b6ddbb4dd27 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
@@ -770,8 +770,7 @@ static void node_declare(NodeDeclarationBuilder &b)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryMeshCone *node_storage = (NodeGeometryMeshCone *)MEM_callocN(
- sizeof(NodeGeometryMeshCone), __func__);
+ NodeGeometryMeshCone *node_storage = MEM_cnew<NodeGeometryMeshCone>(__func__);
node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NGON;
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 b8d2ed3be92..ae270495b07 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
@@ -71,8 +71,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryMeshCylinder *node_storage = (NodeGeometryMeshCylinder *)MEM_callocN(
- sizeof(NodeGeometryMeshCylinder), __func__);
+ NodeGeometryMeshCylinder *node_storage = MEM_cnew<NodeGeometryMeshCylinder>(__func__);
node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NGON;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
index 77634a03af6..4a5668453bf 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
@@ -14,6 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include "BLI_task.hh"
+
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -38,11 +40,13 @@ static void calculate_uvs(
const float dx = (size_x == 0.0f) ? 0.0f : 1.0f / size_x;
const float dy = (size_y == 0.0f) ? 0.0f : 1.0f / size_y;
- for (const int i : loops.index_range()) {
- const float3 &co = verts[loops[i].v].co;
- uvs[i].x = (co.x + size_x * 0.5f) * dx;
- uvs[i].y = (co.y + size_y * 0.5f) * dy;
- }
+ threading::parallel_for(loops.index_range(), 1024, [&](IndexRange range) {
+ for (const int i : range) {
+ const float3 &co = verts[loops[i].v].co;
+ uvs[i].x = (co.x + size_x * 0.5f) * dx;
+ uvs[i].y = (co.y + size_y * 0.5f) * dy;
+ }
+ });
uv_attribute.save();
}
@@ -70,72 +74,95 @@ Mesh *create_grid_mesh(const int verts_x,
const float dy = edges_y == 0 ? 0.0f : size_y / edges_y;
const float x_shift = edges_x / 2.0f;
const float y_shift = edges_y / 2.0f;
- for (const int x_index : IndexRange(verts_x)) {
- for (const int y_index : IndexRange(verts_y)) {
- const int vert_index = x_index * verts_y + y_index;
- verts[vert_index].co[0] = (x_index - x_shift) * dx;
- verts[vert_index].co[1] = (y_index - y_shift) * dy;
- verts[vert_index].co[2] = 0.0f;
+ threading::parallel_for(IndexRange(verts_x), 512, [&](IndexRange x_range) {
+ for (const int x : x_range) {
+ const int y_offset = x * verts_y;
+ threading::parallel_for(IndexRange(verts_y), 512, [&](IndexRange y_range) {
+ for (const int y : y_range) {
+ const int vert_index = y_offset + y;
+ verts[vert_index].co[0] = (x - x_shift) * dx;
+ verts[vert_index].co[1] = (y - y_shift) * dy;
+ verts[vert_index].co[2] = 0.0f;
+ }
+ });
}
- }
+ });
}
/* Point all vertex normals in the up direction. */
- const short up_normal[3] = {0, 0, SHRT_MAX};
- for (MVert &vert : verts) {
- copy_v3_v3_short(vert.no, up_normal);
+ {
+ const short up_normal[3] = {0, 0, SHRT_MAX};
+ for (MVert &vert : verts) {
+ copy_v3_v3_short(vert.no, up_normal);
+ }
}
- /* Build the horizontal edges in the X direction. */
const int y_edges_start = 0;
+ const int x_edges_start = verts_x * edges_y;
const short edge_flag = (edges_x == 0 || edges_y == 0) ? ME_LOOSEEDGE :
ME_EDGEDRAW | ME_EDGERENDER;
- int edge_index = 0;
- for (const int x : IndexRange(verts_x)) {
- for (const int y : IndexRange(edges_y)) {
- const int vert_index = x * verts_y + y;
- MEdge &edge = edges[edge_index++];
- edge.v1 = vert_index;
- edge.v2 = vert_index + 1;
- edge.flag = edge_flag;
+
+ /* Build the horizontal edges in the X direction. */
+ threading::parallel_for(IndexRange(verts_x), 512, [&](IndexRange x_range) {
+ for (const int x : x_range) {
+ const int y_vert_offset = x * verts_y;
+ const int y_edge_offset = y_edges_start + x * edges_y;
+ threading::parallel_for(IndexRange(edges_y), 512, [&](IndexRange y_range) {
+ for (const int y : y_range) {
+ const int vert_index = y_vert_offset + y;
+ MEdge &edge = edges[y_edge_offset + y];
+ edge.v1 = vert_index;
+ edge.v2 = vert_index + 1;
+ edge.flag = edge_flag;
+ }
+ });
}
- }
+ });
/* Build the vertical edges in the Y direction. */
- const int x_edges_start = edge_index;
- for (const int y : IndexRange(verts_y)) {
- for (const int x : IndexRange(edges_x)) {
- const int vert_index = x * verts_y + y;
- MEdge &edge = edges[edge_index++];
- edge.v1 = vert_index;
- edge.v2 = vert_index + verts_y;
- edge.flag = edge_flag;
+ threading::parallel_for(IndexRange(verts_y), 512, [&](IndexRange y_range) {
+ for (const int y : y_range) {
+ const int x_edge_offset = x_edges_start + y * edges_x;
+ threading::parallel_for(IndexRange(edges_x), 512, [&](IndexRange x_range) {
+ for (const int x : x_range) {
+ const int vert_index = x * verts_y + y;
+ MEdge &edge = edges[x_edge_offset + x];
+ edge.v1 = vert_index;
+ edge.v2 = vert_index + verts_y;
+ edge.flag = edge_flag;
+ }
+ });
}
- }
-
- int loop_index = 0;
- int poly_index = 0;
- for (const int x : IndexRange(edges_x)) {
- for (const int y : IndexRange(edges_y)) {
- MPoly &poly = polys[poly_index++];
- poly.loopstart = loop_index;
- poly.totloop = 4;
- const int vert_index = x * verts_y + y;
-
- MLoop &loop_a = loops[loop_index++];
- loop_a.v = vert_index;
- loop_a.e = x_edges_start + edges_x * y + x;
- MLoop &loop_b = loops[loop_index++];
- loop_b.v = vert_index + verts_y;
- loop_b.e = y_edges_start + edges_y * (x + 1) + y;
- MLoop &loop_c = loops[loop_index++];
- loop_c.v = vert_index + verts_y + 1;
- loop_c.e = x_edges_start + edges_x * (y + 1) + x;
- MLoop &loop_d = loops[loop_index++];
- loop_d.v = vert_index + 1;
- loop_d.e = y_edges_start + edges_y * x + y;
+ });
+
+ threading::parallel_for(IndexRange(edges_x), 512, [&](IndexRange x_range) {
+ for (const int x : x_range) {
+ const int y_offset = x * edges_y;
+ threading::parallel_for(IndexRange(edges_y), 512, [&](IndexRange y_range) {
+ for (const int y : y_range) {
+ const int poly_index = y_offset + y;
+ const int loop_index = poly_index * 4;
+ MPoly &poly = polys[poly_index];
+ poly.loopstart = loop_index;
+ poly.totloop = 4;
+ const int vert_index = x * verts_y + y;
+
+ MLoop &loop_a = loops[loop_index];
+ loop_a.v = vert_index;
+ loop_a.e = x_edges_start + edges_x * y + x;
+ MLoop &loop_b = loops[loop_index + 1];
+ loop_b.v = vert_index + verts_y;
+ loop_b.e = y_edges_start + edges_y * (x + 1) + y;
+ MLoop &loop_c = loops[loop_index + 2];
+ loop_c.v = vert_index + verts_y + 1;
+ loop_c.e = x_edges_start + edges_x * (y + 1) + x;
+ MLoop &loop_d = loops[loop_index + 3];
+ loop_d.v = vert_index + 1;
+ loop_d.e = y_edges_start + edges_y * x + y;
+ }
+ });
}
- }
+ });
if (mesh->totpoly != 0) {
calculate_uvs(mesh, verts, loops, size_x, size_y);
@@ -185,7 +212,6 @@ static void node_geo_exec(GeoNodeExecParams params)
}
Mesh *mesh = create_grid_mesh(verts_x, verts_y, size_x, size_y);
- BLI_assert(BKE_mesh_is_valid(mesh));
BKE_id_material_eval_ensure_default_slot(&mesh->id);
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
index 9a87c040bdf..29f1e62b820 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
@@ -67,8 +67,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryMeshLine *node_storage = (NodeGeometryMeshLine *)MEM_callocN(
- sizeof(NodeGeometryMeshLine), __func__);
+ NodeGeometryMeshLine *node_storage = MEM_cnew<NodeGeometryMeshLine>(__func__);
node_storage->mode = GEO_NODE_MESH_LINE_MODE_OFFSET;
node_storage->count_mode = GEO_NODE_MESH_LINE_COUNT_TOTAL;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
index ce2e0923a30..f3213f791de 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
@@ -287,8 +287,6 @@ static Mesh *create_uv_sphere_mesh(const float radius, const int segments, const
calculate_sphere_uvs(mesh, segments, rings);
- BLI_assert(BKE_mesh_is_valid(mesh));
-
return mesh;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
index 77314341fec..384ab43751f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
@@ -50,8 +50,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryMeshToPoints *data = (NodeGeometryMeshToPoints *)MEM_callocN(
- sizeof(NodeGeometryMeshToPoints), __func__);
+ NodeGeometryMeshToPoints *data = MEM_cnew<NodeGeometryMeshToPoints>(__func__);
data->mode = GEO_NODE_MESH_TO_POINTS_VERTICES;
node->storage = data;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
index 744cce6d445..351e0881fd4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
@@ -66,8 +66,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)MEM_callocN(
- sizeof(NodeGeometryPointsToVolume), __func__);
+ NodeGeometryPointsToVolume *data = MEM_cnew<NodeGeometryPointsToVolume>(__func__);
data->resolution_mode = GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT;
node->storage = data;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
index d255fe482f6..82e96267a11 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
@@ -75,8 +75,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryRaycast *data = (NodeGeometryRaycast *)MEM_callocN(sizeof(NodeGeometryRaycast),
- __func__);
+ NodeGeometryRaycast *data = MEM_cnew<NodeGeometryRaycast>(__func__);
data->mapping = GEO_NODE_RAYCAST_INTERPOLATED;
data->data_type = CD_PROP_FLOAT;
node->storage = data;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
index 7f1cc1be421..57e5eb63157 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
@@ -44,8 +44,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometrySeparateGeometry *data = (NodeGeometrySeparateGeometry *)MEM_callocN(
- sizeof(NodeGeometrySeparateGeometry), __func__);
+ NodeGeometrySeparateGeometry *data = MEM_cnew<NodeGeometrySeparateGeometry>(__func__);
data->domain = ATTR_DOMAIN_POINT;
node->storage = data;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
index 30a61574e19..bf8c71e1c91 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
@@ -41,8 +41,8 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometrySetCurveHandlePositions *data = (NodeGeometrySetCurveHandlePositions *)MEM_callocN(
- sizeof(NodeGeometrySetCurveHandlePositions), __func__);
+ NodeGeometrySetCurveHandlePositions *data = MEM_cnew<NodeGeometrySetCurveHandlePositions>(
+ __func__);
data->mode = GEO_NODE_CURVE_HANDLE_LEFT;
node->storage = data;
@@ -65,7 +65,7 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode,
evaluator.add(position_field);
evaluator.add(offset_field);
evaluator.evaluate();
- const IndexMask selection = evaluator.get_evaluated_as_mask(0);
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
CurveComponent *curve_component = static_cast<CurveComponent *>(&component);
CurveEval *curve = curve_component->get_for_write();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
index 33614eb3c46..910dfe261e8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
@@ -88,8 +88,7 @@ static void node_layout(uiLayout *layout, struct bContext *C, PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryStringToCurves *data = (NodeGeometryStringToCurves *)MEM_callocN(
- sizeof(NodeGeometryStringToCurves), __func__);
+ NodeGeometryStringToCurves *data = MEM_cnew<NodeGeometryStringToCurves>(__func__);
data->overflow = GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW;
data->align_x = GEO_NODE_STRING_TO_CURVES_ALIGN_X_LEFT;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
index 74e0560b32f..f5694ab10af 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
@@ -52,8 +52,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometrySubdivisionSurface *data = (NodeGeometrySubdivisionSurface *)MEM_callocN(
- sizeof(NodeGeometrySubdivisionSurface), __func__);
+ NodeGeometrySubdivisionSurface *data = MEM_cnew<NodeGeometrySubdivisionSurface>(__func__);
data->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES;
data->boundary_smooth = SUBSURF_BOUNDARY_SMOOTH_ALL;
node->storage = data;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_switch.cc b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
index d22522fe087..91aa1432ee2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_switch.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
@@ -94,7 +94,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeSwitch *data = (NodeSwitch *)MEM_callocN(sizeof(NodeSwitch), __func__);
+ NodeSwitch *data = MEM_cnew<NodeSwitch>(__func__);
data->input_type = SOCK_GEOMETRY;
node->storage = data;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
index 1f099dcd04d..285f7c6d42d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
@@ -88,8 +88,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryTransferAttribute *data = (NodeGeometryTransferAttribute *)MEM_callocN(
- sizeof(NodeGeometryTransferAttribute), __func__);
+ NodeGeometryTransferAttribute *data = MEM_cnew<NodeGeometryTransferAttribute>(__func__);
data->data_type = CD_PROP_FLOAT;
data->mode = GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED;
node->storage = data;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
index 18f2fa4cd36..6110ee42eea 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
@@ -42,8 +42,7 @@ static void node_declare(NodeDeclarationBuilder &b)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryViewer *data = (NodeGeometryViewer *)MEM_callocN(sizeof(NodeGeometryViewer),
- __func__);
+ NodeGeometryViewer *data = MEM_cnew<NodeGeometryViewer>(__func__);
data->data_type = CD_PROP_FLOAT;
node->storage = data;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
index 0819b401941..94e1dbfa4ad 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
@@ -69,8 +69,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)MEM_callocN(
- sizeof(NodeGeometryVolumeToMesh), __func__);
+ NodeGeometryVolumeToMesh *data = MEM_cnew<NodeGeometryVolumeToMesh>(__func__);
data->resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_GRID;
node->storage = data;
}
diff --git a/source/blender/nodes/intern/node_common.cc b/source/blender/nodes/intern/node_common.cc
index c302b1081af..a1fccc401a4 100644
--- a/source/blender/nodes/intern/node_common.cc
+++ b/source/blender/nodes/intern/node_common.cc
@@ -38,6 +38,7 @@
#include "BLT_translation.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "RNA_types.h"
@@ -153,8 +154,6 @@ static void update_socket_to_match_interface(bNodeTree &node_tree,
/* Update socket type if necessary */
if (socket_to_update.typeinfo != interface_socket.typeinfo) {
nodeModifySocketType(&node_tree, &node, &socket_to_update, interface_socket.idname);
- /* Flag the tree to make sure link validity is updated after type changes. */
- node_tree.update |= NTREE_UPDATE_LINKS;
}
if (interface_socket.typeinfo->interface_verify_socket) {
diff --git a/source/blender/nodes/intern/node_exec.cc b/source/blender/nodes/intern/node_exec.cc
index 95070bf735e..f5b64f8499c 100644
--- a/source/blender/nodes/intern/node_exec.cc
+++ b/source/blender/nodes/intern/node_exec.cc
@@ -28,6 +28,7 @@
#include "BKE_global.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "MEM_guardedalloc.h"
@@ -170,7 +171,7 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context,
/* Using global main here is likely totally wrong, not sure what to do about that one though...
* We cannot even check ntree is in global main,
* since most of the time it won't be (thanks to ntree design)!!! */
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
/* get a dependency-sorted list of nodes */
ntreeGetDependencyList(ntree, &nodelist, &totnodes);
diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc
index d83c05b38a1..46cb9dcf891 100644
--- a/source/blender/nodes/intern/node_socket.cc
+++ b/source/blender/nodes/intern/node_socket.cc
@@ -236,6 +236,14 @@ static void refresh_socket_list(bNodeTree &ntree,
link->tosock = new_socket;
}
}
+ LISTBASE_FOREACH (bNodeLink *, internal_link, &node.internal_links) {
+ if (internal_link->fromsock == old_socket_with_same_identifier) {
+ internal_link->fromsock = new_socket;
+ }
+ else if (internal_link->tosock == old_socket_with_same_identifier) {
+ internal_link->tosock = new_socket;
+ }
+ }
}
}
}
diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc
index 912d5e5322c..ffe0edb9762 100644
--- a/source/blender/nodes/intern/node_tree_ref.cc
+++ b/source/blender/nodes/intern/node_tree_ref.cc
@@ -70,6 +70,8 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree)
break;
}
}
+ BLI_assert(internal_link.from_ != nullptr);
+ BLI_assert(internal_link.to_ != nullptr);
node.internal_links_.append(&internal_link);
}
diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c
index 7620c8fa1a8..5c2d84cf605 100644
--- a/source/blender/nodes/intern/node_util.c
+++ b/source/blender/nodes/intern/node_util.c
@@ -35,6 +35,7 @@
#include "BKE_colortools.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "RNA_access.h"
#include "RNA_enum_types.h"
@@ -340,188 +341,6 @@ void node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Internal Links (mute and disconnect)
- * \{ */
-
-/**
- * Common datatype priorities, works for compositor, shader and texture nodes alike
- * defines priority of datatype connection based on output type (to):
- * `< 0`: never connect these types.
- * `>= 0`: priority of connection (higher values chosen first).
- */
-static int node_datatype_priority(const bNodeSocketType *from, const bNodeSocketType *to)
-{
- switch (to->type) {
- case SOCK_RGBA:
- switch (from->type) {
- case SOCK_RGBA:
- return 4;
- case SOCK_FLOAT:
- return 3;
- case SOCK_INT:
- return 2;
- case SOCK_BOOLEAN:
- return 1;
- }
- return -1;
- case SOCK_VECTOR:
- switch (from->type) {
- case SOCK_VECTOR:
- return 4;
- case SOCK_FLOAT:
- return 3;
- case SOCK_INT:
- return 2;
- case SOCK_BOOLEAN:
- return 1;
- }
- return -1;
- case SOCK_FLOAT:
- switch (from->type) {
- case SOCK_FLOAT:
- return 5;
- case SOCK_INT:
- return 4;
- case SOCK_BOOLEAN:
- return 3;
- case SOCK_RGBA:
- return 2;
- case SOCK_VECTOR:
- return 1;
- }
- return -1;
- case SOCK_INT:
- switch (from->type) {
- case SOCK_INT:
- return 5;
- case SOCK_FLOAT:
- return 4;
- case SOCK_BOOLEAN:
- return 3;
- case SOCK_RGBA:
- return 2;
- case SOCK_VECTOR:
- return 1;
- }
- return -1;
- case SOCK_BOOLEAN:
- switch (from->type) {
- case SOCK_BOOLEAN:
- return 5;
- case SOCK_INT:
- return 4;
- case SOCK_FLOAT:
- return 3;
- case SOCK_RGBA:
- return 2;
- case SOCK_VECTOR:
- return 1;
- }
- return -1;
- }
-
- /* The rest of the socket types only allow an internal link if both the input and output socket
- * have the same type. If the sockets are custom, we check the idname instead. */
- if (to->type == from->type && (to->type != SOCK_CUSTOM || STREQ(to->idname, from->idname))) {
- return 1;
- }
-
- return -1;
-}
-
-/* select a suitable input socket for an output */
-static bNodeSocket *select_internal_link_input(bNode *node, bNodeSocket *output)
-{
- if (node->type == NODE_REROUTE) {
- return node->inputs.first;
- }
-
- bNodeSocket *selected = NULL, *input;
- int i;
- int sel_priority = -1;
- bool sel_is_linked = false;
-
- for (input = node->inputs.first, i = 0; input; input = input->next, i++) {
- int priority = node_datatype_priority(input->typeinfo, output->typeinfo);
- bool is_linked = (input->link != NULL);
- bool preferred;
-
- if (nodeSocketIsHidden(input) || /* ignore hidden sockets */
- input->flag &
- SOCK_NO_INTERNAL_LINK || /* ignore if input is not allowed for internal connections */
- priority < 0 || /* ignore incompatible types */
- priority < sel_priority) /* ignore if we already found a higher priority input */
- {
- continue;
- }
-
- /* determine if this input is preferred over the currently selected */
- preferred = (priority > sel_priority) || /* prefer higher datatype priority */
- (is_linked && !sel_is_linked); /* prefer linked over unlinked */
-
- if (preferred) {
- selected = input;
- sel_is_linked = is_linked;
- sel_priority = priority;
- }
- }
-
- return selected;
-}
-
-void node_internal_links_create(bNodeTree *ntree, bNode *node)
-{
- bNodeLink *link;
- bNodeSocket *output, *input;
-
- /* sanity check */
- if (!ntree) {
- return;
- }
-
- /* use link pointer as a tag for handled sockets (for outputs is unused anyway) */
- for (output = node->outputs.first; output; output = output->next) {
- output->link = NULL;
- }
-
- for (link = ntree->links.first; link; link = link->next) {
- if (nodeLinkIsHidden(link)) {
- continue;
- }
-
- output = link->fromsock;
- if (link->fromnode != node || output->link) {
- continue;
- }
- if (nodeSocketIsHidden(output) || output->flag & SOCK_NO_INTERNAL_LINK) {
- continue;
- }
- output->link = link; /* not really used, just for tagging handled sockets */
-
- /* look for suitable input */
- input = select_internal_link_input(node, output);
-
- if (input) {
- bNodeLink *ilink = MEM_callocN(sizeof(bNodeLink), "internal node link");
- ilink->fromnode = node;
- ilink->fromsock = input;
- ilink->tonode = node;
- ilink->tosock = output;
- /* internal link is always valid */
- ilink->flag |= NODE_LINK_VALID;
- BLI_addtail(&node->internal_links, ilink);
- }
- }
-
- /* clean up */
- for (output = node->outputs.first; output; output = output->next) {
- output->link = NULL;
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Default value RNA access
* \{ */
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c
index c3b5236373c..b19835fae19 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -44,6 +44,7 @@
#include "BKE_lib_id.h"
#include "BKE_linestyle.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_scene.h"
#include "RNA_access.h"
@@ -148,26 +149,11 @@ static void localize(bNodeTree *localtree, bNodeTree *UNUSED(ntree))
}
}
-static void local_sync(bNodeTree *localtree, bNodeTree *ntree)
-{
- BKE_node_preview_sync_tree(ntree, localtree);
-}
-
-static void local_merge(Main *UNUSED(bmain), bNodeTree *localtree, bNodeTree *ntree)
-{
- BKE_node_preview_merge_tree(ntree, localtree, true);
-}
-
static void update(bNodeTree *ntree)
{
ntreeSetOutput(ntree);
ntree_update_reroute_nodes(ntree);
-
- if (ntree->update & NTREE_UPDATE_NODES) {
- /* clean up preview cache, in case nodes have been removed */
- BKE_node_preview_remove_unused(ntree);
- }
}
static bool shader_validate_link(eNodeSocketDatatype from, eNodeSocketDatatype to)
@@ -202,8 +188,6 @@ void register_node_tree_type_sh(void)
tt->foreach_nodeclass = foreach_nodeclass;
tt->localize = localize;
- tt->local_sync = local_sync;
- tt->local_merge = local_merge;
tt->update = update;
tt->poll = shader_tree_poll;
tt->get_from_context = shader_get_from_context;
@@ -364,7 +348,7 @@ static void ntree_shader_unlink_hidden_value_sockets(bNode *group_node, bNodeSoc
}
if (removed_link) {
- ntreeUpdateTree(G.main, group_ntree);
+ BKE_ntree_update_main_tree(G.main, group_ntree, NULL);
}
}
@@ -423,7 +407,7 @@ static void ntree_shader_groups_expand_inputs(bNodeTree *localtree)
}
if (link_added) {
- ntreeUpdateTree(G.main, localtree);
+ BKE_ntree_update_main_tree(G.main, localtree, NULL);
}
}
@@ -503,7 +487,7 @@ static void flatten_group_do(bNodeTree *ntree, bNode *gnode)
ntreeFreeLocalNode(ntree, node);
}
- ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_all(ntree);
}
/* Flatten group to only have a simple single tree */
@@ -528,7 +512,7 @@ static void ntree_shader_groups_flatten(bNodeTree *localtree)
}
}
- ntreeUpdateTree(G.main, localtree);
+ BKE_ntree_update_main_tree(G.main, localtree, NULL);
}
/* Check whether shader has a displacement.
@@ -548,7 +532,7 @@ static bool ntree_shader_has_displacement(bNodeTree *ntree,
return false;
}
/* Make sure sockets links pointers are correct. */
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, NULL);
bNodeSocket *displacement = ntree_shader_node_find_input(output_node, "Displacement");
if (displacement == NULL) {
@@ -637,7 +621,7 @@ static void ntree_shader_bypass_tagged_bump_nodes(bNodeTree *ntree)
ntree_shader_bypass_bump_link(ntree, node, link);
}
}
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, NULL);
}
static bool ntree_branch_count_and_tag_nodes(bNode *fromnode, bNode *tonode, void *userdata)
@@ -722,7 +706,7 @@ static void ntree_shader_copy_branch_displacement(bNodeTree *ntree,
nodeRemLink(ntree, displacement_link);
nodeAddLink(ntree, displacement_node, displacement_socket, tonode, tosock);
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, NULL);
}
/* Re-link displacement output to unconnected normal sockets via bump node.
@@ -786,12 +770,12 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree, bNode *output_nod
geo_node->tmp_flag = -2;
bump_node->tmp_flag = -2;
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, NULL);
/* Connect all free-standing Normal inputs and relink geometry/coordinate nodes. */
ntree_shader_link_builtin_normal(ntree, bump_node, bump_output_socket);
/* We modified the tree, it needs to be updated now. */
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, NULL);
}
static void node_tag_branch_as_derivative(bNode *node, int dx)
@@ -871,7 +855,7 @@ void ntree_shader_tag_nodes(bNodeTree *ntree, bNode *output_node, nTreeTags *tag
return;
}
/* Make sure sockets links pointers are correct. */
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, NULL);
nodeChainIterBackwards(ntree, output_node, ntree_tag_bsdf_cb, tags, 0);
}
diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c
index 14597050524..1125936aded 100644
--- a/source/blender/nodes/texture/node_texture_tree.c
+++ b/source/blender/nodes/texture/node_texture_tree.c
@@ -132,24 +132,9 @@ static void localize(bNodeTree *UNUSED(localtree), bNodeTree *UNUSED(ntree))
}
#endif
-static void local_sync(bNodeTree *localtree, bNodeTree *ntree)
-{
- BKE_node_preview_sync_tree(ntree, localtree);
-}
-
-static void local_merge(Main *UNUSED(bmain), bNodeTree *localtree, bNodeTree *ntree)
-{
- BKE_node_preview_merge_tree(ntree, localtree, true);
-}
-
static void update(bNodeTree *ntree)
{
ntree_update_reroute_nodes(ntree);
-
- if (ntree->update & NTREE_UPDATE_NODES) {
- /* clean up preview cache, in case nodes have been removed */
- BKE_node_preview_remove_unused(ntree);
- }
}
static bool texture_node_tree_socket_type_valid(bNodeTreeType *UNUSED(ntreetype),
@@ -175,8 +160,6 @@ void register_node_tree_type_tex(void)
tt->foreach_nodeclass = foreach_nodeclass;
tt->update = update;
tt->localize = localize;
- tt->local_sync = local_sync;
- tt->local_merge = local_merge;
tt->get_from_context = texture_get_from_context;
tt->valid_socket_type = texture_node_tree_socket_type_valid;
diff --git a/source/blender/nodes/texture/node_texture_util.c b/source/blender/nodes/texture/node_texture_util.c
index fe8e68bfc42..1ba693bf4a4 100644
--- a/source/blender/nodes/texture/node_texture_util.c
+++ b/source/blender/nodes/texture/node_texture_util.c
@@ -63,10 +63,6 @@ static void tex_call_delegate(TexDelegate *dg, float *out, TexParams *params, sh
{
if (dg->node->need_exec) {
dg->fn(out, params, dg->node, dg->in, thread);
-
- if (dg->cdata->do_preview) {
- tex_do_preview(dg->preview, params->previewco, out, dg->cdata->do_manage);
- }
}
}
@@ -123,19 +119,6 @@ void params_from_cdata(TexParams *out, TexCallData *in)
out->mtex = in->mtex;
}
-void tex_do_preview(bNodePreview *preview,
- const float coord[2],
- const float col[4],
- bool do_manage)
-{
- if (preview) {
- int xs = ((coord[0] + 1.0f) * 0.5f) * preview->xsize;
- int ys = ((coord[1] + 1.0f) * 0.5f) * preview->ysize;
-
- BKE_node_preview_set_pixel(preview, col, xs, ys, do_manage);
- }
-}
-
void tex_output(bNode *node,
bNodeExecData *execdata,
bNodeStack **in,
diff --git a/source/blender/nodes/texture/node_texture_util.h b/source/blender/nodes/texture/node_texture_util.h
index 84d2c5c903a..473cef81359 100644
--- a/source/blender/nodes/texture/node_texture_util.h
+++ b/source/blender/nodes/texture/node_texture_util.h
@@ -121,10 +121,6 @@ void tex_output(bNode *node,
bNodeStack *out,
TexFn texfn,
TexCallData *data);
-void tex_do_preview(bNodePreview *preview,
- const float coord[2],
- const float col[4],
- bool do_manage);
void params_from_cdata(TexParams *out, TexCallData *in);
diff --git a/source/blender/nodes/texture/nodes/node_texture_output.c b/source/blender/nodes/texture/nodes/node_texture_output.c
index 19e24c9f82a..50f41239581 100644
--- a/source/blender/nodes/texture/nodes/node_texture_output.c
+++ b/source/blender/nodes/texture/nodes/node_texture_output.c
@@ -37,7 +37,7 @@ static bNodeSocketTemplate inputs[] = {
static void exec(void *data,
int UNUSED(thread),
bNode *node,
- bNodeExecData *execdata,
+ bNodeExecData *UNUSED(execdata),
bNodeStack **in,
bNodeStack **UNUSED(out))
{
@@ -54,7 +54,6 @@ static void exec(void *data,
else {
tex_input_rgba(&target->tr, in[0], &params, cdata->thread);
}
- tex_do_preview(execdata->preview, params.co, &target->tr, cdata->do_manage);
}
else {
/* 0 means don't care, so just use first */
diff --git a/source/blender/nodes/texture/nodes/node_texture_viewer.c b/source/blender/nodes/texture/nodes/node_texture_viewer.c
index 18b11b86d6f..1c22561bec4 100644
--- a/source/blender/nodes/texture/nodes/node_texture_viewer.c
+++ b/source/blender/nodes/texture/nodes/node_texture_viewer.c
@@ -36,7 +36,7 @@ static bNodeSocketTemplate outputs[] = {
static void exec(void *data,
int UNUSED(thread),
bNode *UNUSED(node),
- bNodeExecData *execdata,
+ bNodeExecData *UNUSED(execdata),
bNodeStack **in,
bNodeStack **UNUSED(out))
{
@@ -48,7 +48,6 @@ static void exec(void *data,
params_from_cdata(&params, cdata);
tex_input_rgba(col, in[0], &params, cdata->thread);
- tex_do_preview(execdata->preview, params.previewco, col, cdata->do_manage);
}
}
diff --git a/source/blender/render/intern/pipeline.c b/source/blender/render/intern/pipeline.c
index a800361a41f..721abe45932 100644
--- a/source/blender/render/intern/pipeline.c
+++ b/source/blender/render/intern/pipeline.c
@@ -1131,7 +1131,7 @@ static void do_render_compositor_scenes(Render *re)
render_scene_has_layers_to_render(scene, false)) {
do_render_compositor_scene(re, scene, cfra);
BLI_gset_add(scenes_rendered, scene);
- nodeUpdate(restore_scene->nodetree, node);
+ node->typeinfo->updatefunc(restore_scene->nodetree, node);
}
}
}
@@ -1821,7 +1821,7 @@ void RE_RenderFrame(Render *re,
render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_INIT);
/* Ugly global still...
- * is to prevent preview events and signal subsurfs etc to make full resol. */
+ * is to prevent preview events and signal subdivision-surface etc to make full resolution. */
G.is_rendering = true;
scene->r.cfra = frame;
@@ -2331,8 +2331,8 @@ void RE_RenderAnim(Render *re,
}
}
- /* Ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol
- * is also set by caller renderwin.c */
+ /* Ugly global still... is to prevent renderwin events and signal subdivision-surface etc
+ * to make full resolution is also set by caller renderwin.c */
G.is_rendering = true;
re->flag |= R_ANIMATION;
diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c
index 908a5bd4f79..e4120a3cf95 100644
--- a/source/blender/sequencer/intern/sequencer.c
+++ b/source/blender/sequencer/intern/sequencer.c
@@ -140,6 +140,7 @@ Sequence *SEQ_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int
seq->pitch = 1.0f;
seq->scene_sound = NULL;
seq->type = type;
+ seq->blend_mode = SEQ_TYPE_ALPHAOVER;
seq->strip = seq_strip_alloc(type);
seq->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Sequence Stereo Format");
@@ -418,6 +419,10 @@ void SEQ_meta_stack_free(Editing *ed, MetaStack *ms)
MetaStack *SEQ_meta_stack_active_get(const Editing *ed)
{
+ if (ed == NULL) {
+ return NULL;
+ }
+
return ed->metastack.last;
}
diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c
index a4b537b9074..f342765eec9 100644
--- a/source/blender/sequencer/intern/strip_add.c
+++ b/source/blender/sequencer/intern/strip_add.c
@@ -141,7 +141,6 @@ Sequence *SEQ_add_scene_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDat
{
Sequence *seq = SEQ_sequence_alloc(
seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_SCENE);
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
seq->scene = load_data->scene;
seq->len = load_data->scene->r.efra - load_data->scene->r.sfra + 1;
id_us_ensure_real((ID *)load_data->scene);
@@ -154,7 +153,6 @@ Sequence *SEQ_add_movieclip_strip(Scene *scene, ListBase *seqbase, struct SeqLoa
{
Sequence *seq = SEQ_sequence_alloc(
seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_MOVIECLIP);
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
seq->clip = load_data->clip;
seq->len = BKE_movieclip_get_duration(load_data->clip);
id_us_ensure_real((ID *)load_data->clip);
@@ -167,7 +165,6 @@ Sequence *SEQ_add_mask_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData
{
Sequence *seq = SEQ_sequence_alloc(
seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_MASK);
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
seq->mask = load_data->mask;
seq->len = BKE_mask_get_duration(load_data->mask);
id_us_ensure_real((ID *)load_data->mask);
@@ -191,9 +188,6 @@ Sequence *SEQ_add_effect_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDa
if (SEQ_effect_get_num_inputs(seq->type) == 1) {
seq->blend_mode = seq->seq1->blend_mode;
}
- else {
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
- }
if (!load_data->effect.seq1) {
seq->len = 1; /* Effect is generator, set non zero length. */
@@ -250,7 +244,6 @@ Sequence *SEQ_add_image_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL
{
Sequence *seq = SEQ_sequence_alloc(
seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_IMAGE);
- seq->blend_mode = SEQ_TYPE_ALPHAOVER; /* so alpha adjustment fade to the strip below */
seq->len = load_data->image.len;
Strip *strip = seq->strip;
strip->stripdata = MEM_callocN(load_data->image.len * sizeof(StripElem), "stripelem");
@@ -482,8 +475,6 @@ Sequence *SEQ_add_movie_strip(
}
}
- seq->blend_mode = SEQ_TYPE_ALPHAOVER; /* so alpha adjustment fade to the strip below */
-
if (anim_arr[0] != NULL) {
seq->len = IMB_anim_get_duration(anim_arr[0], IMB_TC_RECORD_RUN);
diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c
index 912ba9d41db..cf303e5be4e 100644
--- a/source/blender/sequencer/intern/strip_edit.c
+++ b/source/blender/sequencer/intern/strip_edit.c
@@ -489,21 +489,27 @@ Sequence *SEQ_edit_strip_split(Main *bmain,
ListBase right_strips = {NULL, NULL};
SEQ_sequence_base_dupli_recursive(scene, scene, &right_strips, &left_strips, SEQ_DUPE_ALL, 0);
- /* Split strips. */
Sequence *left_seq = left_strips.first;
Sequence *right_seq = right_strips.first;
- Sequence *return_seq = right_strips.first;
+ Sequence *return_seq = NULL;
- /* Strips can't be tagged while in detached `seqbase`. Collect all strips which needs to be
- * deleted and delay tagging until they are moved back to `seqbase` in `Editing`. */
- SeqCollection *strips_to_delete = SEQ_collection_create(__func__);
+ /* Move strips from detached `ListBase`, otherwise they can't be flagged for removal,
+ * SEQ_time_update_sequence can fail to update meta strips and they can't be renamed.
+ * This is because these functions check all strips in `Editing` to manage relationships. */
+ BLI_movelisttolist(seqbase, &left_strips);
+ BLI_movelisttolist(seqbase, &right_strips);
+ /* Split strips. */
while (left_seq && right_seq) {
if (left_seq->startdisp >= timeline_frame) {
- SEQ_collection_append_strip(left_seq, strips_to_delete);
+ SEQ_edit_flag_for_removal(scene, seqbase, left_seq);
}
if (right_seq->enddisp <= timeline_frame) {
- SEQ_collection_append_strip(right_seq, strips_to_delete);
+ SEQ_edit_flag_for_removal(scene, seqbase, right_seq);
+ }
+ else if (return_seq == NULL) {
+ /* Store return value - pointer to strip that will not be removed. */
+ return_seq = right_seq;
}
seq_edit_split_handle_strip_offsets(
@@ -512,20 +518,14 @@ Sequence *SEQ_edit_strip_split(Main *bmain,
right_seq = right_seq->next;
}
- seq = right_strips.first;
- BLI_movelisttolist(seqbase, &left_strips);
- BLI_movelisttolist(seqbase, &right_strips);
+ SEQ_edit_remove_flagged_sequences(scene, seqbase);
- for (; seq; seq = seq->next) {
- SEQ_ensure_unique_name(seq, scene);
+ /* Rename duplicated strips. */
+ Sequence *seq_rename = return_seq;
+ for (; seq_rename; seq_rename = seq_rename->next) {
+ SEQ_ensure_unique_name(seq_rename, scene);
}
- Sequence *seq_delete;
- SEQ_ITERATOR_FOREACH (seq_delete, strips_to_delete) {
- SEQ_edit_flag_for_removal(scene, seqbase, seq_delete);
- }
- SEQ_edit_remove_flagged_sequences(scene, seqbase);
- SEQ_collection_free(strips_to_delete);
return return_seq;
}
diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c
index 3228277ce72..31ee20cb6ca 100644
--- a/source/blender/sequencer/intern/strip_time.c
+++ b/source/blender/sequencer/intern/strip_time.c
@@ -193,6 +193,10 @@ static void seq_time_update_meta_strip(Scene *scene, Sequence *seq_meta)
void SEQ_time_update_meta_strip_range(Scene *scene, Sequence *seq_meta)
{
+ if (seq_meta == NULL) {
+ return;
+ }
+
seq_time_update_meta_strip(scene, seq_meta);
/* Prevent meta-strip to move in timeline. */
diff --git a/source/blender/sequencer/intern/utils.c b/source/blender/sequencer/intern/utils.c
index cd779b0b0c7..156c6ac4cb9 100644
--- a/source/blender/sequencer/intern/utils.c
+++ b/source/blender/sequencer/intern/utils.c
@@ -446,7 +446,7 @@ Sequence *SEQ_get_meta_by_seqbase(ListBase *seqbase_main, ListBase *meta_seqbase
{
SeqCollection *strips = SEQ_query_all_strips_recursive(seqbase_main);
- Sequence *seq;
+ Sequence *seq = NULL;
SEQ_ITERATOR_FOREACH (seq, strips) {
if (seq->type == SEQ_TYPE_META && &seq->seqbase == meta_seqbase) {
break;
diff --git a/source/tools b/source/tools
-Subproject b22d19e47f4d0353082f3d9f30ee8d244c5266d
+Subproject 26bc78162ec89f21453ce3ded7b999bc6649f32