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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2022-01-27 16:37:24 +0300
committerClément Foucault <foucault.clem@gmail.com>2022-01-27 16:37:24 +0300
commit6016dbb1a75566e1fb3ca257a1f13b9bba4467fd (patch)
tree30ca1741378f36e7c6af17beb1b12c46fb487d05 /source/blender/editors
parentc453aaa0b2408b50af7d47722114f1903f27a6fc (diff)
parent0379ddac7d68114798c8963821fd821c1b3d7d28 (diff)
Merge branch 'master' into temp-gpu-image-engine
# Conflicts: # source/blender/blenkernel/CMakeLists.txt # source/blender/draw/CMakeLists.txt
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/animation/drivers.c20
-rw-r--r--source/blender/editors/animation/keyframes_draw.c2
-rw-r--r--source/blender/editors/animation/keyframes_edit.c55
-rw-r--r--source/blender/editors/animation/keyframes_general.c80
-rw-r--r--source/blender/editors/animation/keyframes_keylist.cc3
-rw-r--r--source/blender/editors/animation/keyframes_keylist_test.cc12
-rw-r--r--source/blender/editors/animation/keyframing.c2
-rw-r--r--source/blender/editors/armature/armature_intern.h2
-rw-r--r--source/blender/editors/armature/meshlaplacian.c3
-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/CMakeLists.txt1
-rw-r--r--source/blender/editors/asset/ED_asset_catalog.h2
-rw-r--r--source/blender/editors/asset/ED_asset_mark_clear.h5
-rw-r--r--source/blender/editors/asset/ED_asset_type.h5
-rw-r--r--source/blender/editors/asset/intern/asset_indexer.cc85
-rw-r--r--source/blender/editors/asset/intern/asset_list.cc6
-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/asset/intern/asset_type.cc2
-rw-r--r--source/blender/editors/curve/curve_intern.h2
-rw-r--r--source/blender/editors/curve/editcurve.c11
-rw-r--r--source/blender/editors/curve/editcurve_add.c6
-rw-r--r--source/blender/editors/geometry/CMakeLists.txt8
-rw-r--r--source/blender/editors/geometry/geometry_attributes.c182
-rw-r--r--source/blender/editors/geometry/geometry_attributes.cc385
-rw-r--r--source/blender/editors/geometry/geometry_intern.hh (renamed from source/blender/editors/geometry/geometry_intern.h)7
-rw-r--r--source/blender/editors/geometry/geometry_ops.cc (renamed from source/blender/editors/geometry/geometry_ops.c)5
-rw-r--r--source/blender/editors/gizmo_library/gizmo_library_intern.h21
-rw-r--r--source/blender/editors/gpencil/annotate_draw.c14
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c61
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c29
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c8
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c13
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h4
-rw-r--r--source/blender/editors/gpencil/gpencil_mesh.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c135
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c60
-rw-r--r--source/blender/editors/gpencil/gpencil_sculpt_paint.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_trace.h10
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c10
-rw-r--r--source/blender/editors/gpencil/gpencil_vertex_paint.c12
-rw-r--r--source/blender/editors/gpencil/gpencil_weight_paint.c4
-rw-r--r--source/blender/editors/include/BIF_glutil.h146
-rw-r--r--source/blender/editors/include/ED_armature.h26
-rw-r--r--source/blender/editors/include/ED_buttons.h4
-rw-r--r--source/blender/editors/include/ED_curve.h2
-rw-r--r--source/blender/editors/include/ED_file_indexer.h2
-rw-r--r--source/blender/editors/include/ED_fileselect.h8
-rw-r--r--source/blender/editors/include/ED_gizmo_library.h10
-rw-r--r--source/blender/editors/include/ED_gpencil.h42
-rw-r--r--source/blender/editors/include/ED_image.h12
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h43
-rw-r--r--source/blender/editors/include/ED_keyframes_keylist.h27
-rw-r--r--source/blender/editors/include/ED_keyframing.h12
-rw-r--r--source/blender/editors/include/ED_lattice.h2
-rw-r--r--source/blender/editors/include/ED_mask.h29
-rw-r--r--source/blender/editors/include/ED_mesh.h203
-rw-r--r--source/blender/editors/include/ED_node.h29
-rw-r--r--source/blender/editors/include/ED_numinput.h2
-rw-r--r--source/blender/editors/include/ED_object.h59
-rw-r--r--source/blender/editors/include/ED_particle.h9
-rw-r--r--source/blender/editors/include/ED_render.h16
-rw-r--r--source/blender/editors/include/ED_screen.h40
-rw-r--r--source/blender/editors/include/ED_sculpt.h2
-rw-r--r--source/blender/editors/include/ED_select_utils.h16
-rw-r--r--source/blender/editors/include/ED_space_api.h2
-rw-r--r--source/blender/editors/include/ED_transform.h17
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h4
-rw-r--r--source/blender/editors/include/ED_transverts.h2
-rw-r--r--source/blender/editors/include/ED_util.h12
-rw-r--r--source/blender/editors/include/ED_uvedit.h78
-rw-r--r--source/blender/editors/include/ED_view3d.h140
-rw-r--r--source/blender/editors/include/ED_view3d_offscreen.h8
-rw-r--r--source/blender/editors/include/UI_interface.h256
-rw-r--r--source/blender/editors/include/UI_interface.hh6
-rw-r--r--source/blender/editors/include/UI_interface_icons.h29
-rw-r--r--source/blender/editors/include/UI_resources.h2
-rw-r--r--source/blender/editors/include/UI_tree_view.hh2
-rw-r--r--source/blender/editors/include/UI_view2d.h4
-rw-r--r--source/blender/editors/interface/CMakeLists.txt4
-rw-r--r--source/blender/editors/interface/interface.c409
-rw-r--r--source/blender/editors/interface/interface_draw.c55
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c8
-rw-r--r--source/blender/editors/interface/interface_eyedropper_color.c22
-rw-r--r--source/blender/editors/interface/interface_eyedropper_datablock.c2
-rw-r--r--source/blender/editors/interface/interface_eyedropper_depth.c4
-rw-r--r--source/blender/editors/interface/interface_eyedropper_driver.c2
-rw-r--r--source/blender/editors/interface/interface_eyedropper_intern.h2
-rw-r--r--source/blender/editors/interface/interface_handlers.c112
-rw-r--r--source/blender/editors/interface/interface_icons.c125
-rw-r--r--source/blender/editors/interface/interface_intern.h51
-rw-r--r--source/blender/editors/interface/interface_layout.c5
-rw-r--r--source/blender/editors/interface/interface_ops.c128
-rw-r--r--source/blender/editors/interface/interface_panel.c1
-rw-r--r--source/blender/editors/interface/interface_region_search.cc4
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.c15
-rw-r--r--source/blender/editors/interface/interface_style.c23
-rw-r--r--source/blender/editors/interface/interface_template_list.cc1
-rw-r--r--source/blender/editors/interface/interface_template_search_menu.cc3
-rw-r--r--source/blender/editors/interface/interface_templates.c227
-rw-r--r--source/blender/editors/interface/interface_view.cc4
-rw-r--r--source/blender/editors/interface/interface_widgets.c7
-rw-r--r--source/blender/editors/io/CMakeLists.txt4
-rw-r--r--source/blender/editors/io/io_cache.c168
-rw-r--r--source/blender/editors/io/io_cache.h4
-rw-r--r--source/blender/editors/io/io_obj.c369
-rw-r--r--source/blender/editors/io/io_obj.h25
-rw-r--r--source/blender/editors/io/io_ops.c7
-rw-r--r--source/blender/editors/mask/mask_draw.c9
-rw-r--r--source/blender/editors/mask/mask_intern.h12
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c2
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c18
-rw-r--r--source/blender/editors/mesh/editmesh_mask_extract.c3
-rw-r--r--source/blender/editors/mesh/editmesh_path.c2
-rw-r--r--source/blender/editors/mesh/editmesh_select_similar.c28
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c14
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c5
-rw-r--r--source/blender/editors/mesh/mesh_data.c9
-rw-r--r--source/blender/editors/mesh/mesh_intern.h8
-rw-r--r--source/blender/editors/mesh/meshtools.c3
-rw-r--r--source/blender/editors/object/object_add.c21
-rw-r--r--source/blender/editors/object/object_bake.c15
-rw-r--r--source/blender/editors/object/object_bake_api.c38
-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_gpencil_modifier.c15
-rw-r--r--source/blender/editors/object/object_hook.c2
-rw-r--r--source/blender/editors/object/object_intern.h4
-rw-r--r--source/blender/editors/object/object_relations.c7
-rw-r--r--source/blender/editors/object/object_remesh.cc6
-rw-r--r--source/blender/editors/object/object_shapekey.c3
-rw-r--r--source/blender/editors/object/object_transform.c17
-rw-r--r--source/blender/editors/object/object_utils.c2
-rw-r--r--source/blender/editors/physics/dynamicpaint_ops.c2
-rw-r--r--source/blender/editors/physics/particle_edit.c14
-rw-r--r--source/blender/editors/physics/particle_object.c19
-rw-r--r--source/blender/editors/render/CMakeLists.txt17
-rw-r--r--source/blender/editors/render/render_intern.hh (renamed from source/blender/editors/render/render_intern.h)0
-rw-r--r--source/blender/editors/render/render_internal.cc (renamed from source/blender/editors/render/render_internal.c)144
-rw-r--r--source/blender/editors/render/render_opengl.cc (renamed from source/blender/editors/render/render_opengl.c)186
-rw-r--r--source/blender/editors/render/render_ops.cc (renamed from source/blender/editors/render/render_ops.c)6
-rw-r--r--source/blender/editors/render/render_preview.cc (renamed from source/blender/editors/render/render_preview.c)454
-rw-r--r--source/blender/editors/render/render_shading.cc (renamed from source/blender/editors/render/render_shading.c)189
-rw-r--r--source/blender/editors/render/render_update.cc (renamed from source/blender/editors/render/render_update.c)64
-rw-r--r--source/blender/editors/render/render_view.cc (renamed from source/blender/editors/render/render_view.c)52
-rw-r--r--source/blender/editors/screen/area.c4
-rw-r--r--source/blender/editors/screen/glutil.c375
-rw-r--r--source/blender/editors/screen/screen_context.c2
-rw-r--r--source/blender/editors/screen/screen_draw.c4
-rw-r--r--source/blender/editors/screen/screen_intern.h25
-rw-r--r--source/blender/editors/screen/screen_ops.c76
-rw-r--r--source/blender/editors/screen/screendump.c8
-rw-r--r--source/blender/editors/screen/workspace_edit.c2
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt3
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c23
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h79
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c45
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c102
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_proj.c26
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c4045
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_boundary.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_brush_types.c2847
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_cloth.c9
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_detail.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mask.c9
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mesh.c9
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h1685
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c7
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_ops.c1141
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_smooth.c7
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_transform.c45
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c4
-rw-r--r--source/blender/editors/space_action/action_edit.c4
-rw-r--r--source/blender/editors/space_action/space_action.c18
-rw-r--r--source/blender/editors/space_api/spacetypes.c7
-rw-r--r--source/blender/editors/space_buttons/buttons_texture.c4
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c68
-rw-r--r--source/blender/editors/space_clip/CMakeLists.txt7
-rw-r--r--source/blender/editors/space_clip/clip_editor.c11
-rw-r--r--source/blender/editors/space_clip/clip_intern.h2
-rw-r--r--source/blender/editors/space_clip/clip_ops.c6
-rw-r--r--source/blender/editors/space_clip/space_clip.c35
-rw-r--r--source/blender/editors/space_file/CMakeLists.txt2
-rw-r--r--source/blender/editors/space_file/asset_catalog_tree_view.cc7
-rw-r--r--source/blender/editors/space_file/file_draw.c32
-rw-r--r--source/blender/editors/space_file/file_intern.h8
-rw-r--r--source/blender/editors/space_file/file_ops.c8
-rw-r--r--source/blender/editors/space_file/filelist.c22
-rw-r--r--source/blender/editors/space_file/filelist.h38
-rw-r--r--source/blender/editors/space_file/filesel.c7
-rw-r--r--source/blender/editors/space_file/fsmenu.c4
-rw-r--r--source/blender/editors/space_file/fsmenu.h2
-rw-r--r--source/blender/editors/space_file/space_file.c14
-rw-r--r--source/blender/editors/space_graph/graph_edit.c97
-rw-r--r--source/blender/editors/space_graph/graph_intern.h16
-rw-r--r--source/blender/editors/space_graph/graph_ops.c3
-rw-r--r--source/blender/editors/space_graph/graph_slider_ops.c262
-rw-r--r--source/blender/editors/space_graph/space_graph.c18
-rw-r--r--source/blender/editors/space_image/image_draw.c2
-rw-r--r--source/blender/editors/space_image/image_ops.c32
-rw-r--r--source/blender/editors/space_image/image_sequence.c68
-rw-r--r--source/blender/editors/space_image/space_image.c27
-rw-r--r--source/blender/editors/space_info/info_ops.c10
-rw-r--r--source/blender/editors/space_info/info_stats.cc3
-rw-r--r--source/blender/editors/space_info/textview.h2
-rw-r--r--source/blender/editors/space_nla/nla_draw.c2
-rw-r--r--source/blender/editors/space_nla/space_nla.c16
-rw-r--r--source/blender/editors/space_node/CMakeLists.txt2
-rw-r--r--source/blender/editors/space_node/drawnode.cc2085
-rw-r--r--source/blender/editors/space_node/link_drag_search.cc327
-rw-r--r--source/blender/editors/space_node/node_add.cc140
-rw-r--r--source/blender/editors/space_node/node_context_path.cc4
-rw-r--r--source/blender/editors/space_node/node_draw.cc102
-rw-r--r--source/blender/editors/space_node/node_edit.cc359
-rw-r--r--source/blender/editors/space_node/node_geometry_attribute_search.cc12
-rw-r--r--source/blender/editors/space_node/node_gizmo.cc12
-rw-r--r--source/blender/editors/space_node/node_group.cc120
-rw-r--r--source/blender/editors/space_node/node_intern.hh92
-rw-r--r--source/blender/editors/space_node/node_ops.cc22
-rw-r--r--source/blender/editors/space_node/node_relationships.cc477
-rw-r--r--source/blender/editors/space_node/node_select.cc125
-rw-r--r--source/blender/editors/space_node/node_templates.cc75
-rw-r--r--source/blender/editors/space_node/node_view.cc12
-rw-r--r--source/blender/editors/space_node/space_node.cc136
-rw-r--r--source/blender/editors/space_outliner/CMakeLists.txt33
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.cc (renamed from source/blender/editors/space_outliner/outliner_collections.c)260
-rw-r--r--source/blender/editors/space_outliner/outliner_context.cc (renamed from source/blender/editors/space_outliner/outliner_context.c)4
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.cc (renamed from source/blender/editors/space_outliner/outliner_dragdrop.c)233
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.cc (renamed from source/blender/editors/space_outliner/outliner_draw.c)448
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.cc (renamed from source/blender/editors/space_outliner/outliner_edit.c)227
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.hh (renamed from source/blender/editors/space_outliner/outliner_intern.h)74
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.cc (renamed from source/blender/editors/space_outliner/outliner_ops.c)2
-rw-r--r--source/blender/editors/space_outliner/outliner_select.cc (renamed from source/blender/editors/space_outliner/outliner_select.c)164
-rw-r--r--source/blender/editors/space_outliner/outliner_sync.cc (renamed from source/blender/editors/space_outliner/outliner_sync.c)31
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.cc (renamed from source/blender/editors/space_outliner/outliner_tools.c)447
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.cc (renamed from source/blender/editors/space_outliner/outliner_tree.c)427
-rw-r--r--source/blender/editors/space_outliner/outliner_utils.cc (renamed from source/blender/editors/space_outliner/outliner_utils.c)39
-rw-r--r--source/blender/editors/space_outliner/space_outliner.cc (renamed from source/blender/editors/space_outliner/space_outliner.c)142
-rw-r--r--source/blender/editors/space_outliner/tree/common.cc38
-rw-r--r--source/blender/editors/space_outliner/tree/common.hh (renamed from source/blender/editors/space_node/node_toolbar.cc)23
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display.cc45
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display.h76
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display.hh35
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_data.cc5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_libraries.cc12
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_orphaned.cc5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_override_library.cc10
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_scenes.cc6
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_sequencer.cc6
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_view_layer.cc5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element.cc145
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element.h48
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element.hh51
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_anim_data.cc4
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_collection.cc5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_driver.cc4
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc3
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id.cc13
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id.hh5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id_library.cc3
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id_library.hh2
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id_scene.cc5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_nla.cc4
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_overrides.cc5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_rna.cc268
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_rna.hh86
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc6
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh2
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_seq.cc111
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_seq.hh60
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_view_layer.cc5
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c63
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c37
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c148
-rw-r--r--source/blender/editors/space_sequencer/sequencer_intern.h8
-rw-r--r--source/blender/editors/space_sequencer/sequencer_proxy.c4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_thumbnails.c2
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c16
-rw-r--r--source/blender/editors/space_spreadsheet/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_spreadsheet/space_spreadsheet.cc68
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh64
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column.cc43
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column.hh2
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh60
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_context.cc9
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc438
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh2
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_intern.hh4
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_layout.cc170
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_layout.hh2
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_panels.cc2
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc412
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh8
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc10
-rw-r--r--source/blender/editors/space_text/space_text.c15
-rw-r--r--source/blender/editors/space_text/text_format.h6
-rw-r--r--source/blender/editors/space_text/text_intern.h2
-rw-r--r--source/blender/editors/space_text/text_ops.c2
-rw-r--r--source/blender/editors/space_topbar/space_topbar.c60
-rw-r--r--source/blender/editors/space_userpref/space_userpref.c4
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c77
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c68
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c1
-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/space_view3d/view3d_intern.h16
-rw-r--r--source/blender/editors/space_view3d/view3d_iterators.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c7
-rw-r--r--source/blender/editors/transform/transform.h6
-rw-r--r--source/blender/editors/transform/transform_convert.c4
-rw-r--r--source/blender/editors/transform/transform_convert.h21
-rw-r--r--source/blender/editors/transform/transform_convert_armature.c2
-rw-r--r--source/blender/editors/transform/transform_convert_curve.c35
-rw-r--r--source/blender/editors/transform/transform_convert_mask.c7
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c9
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_edge.c4
-rw-r--r--source/blender/editors/transform/transform_convert_node.c3
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer.c5
-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_data.h4
-rw-r--r--source/blender/editors/transform/transform_generics.c5
-rw-r--r--source/blender/editors/transform/transform_gizmo_extrude_3d.c5
-rw-r--r--source/blender/editors/transform/transform_mode.c9
-rw-r--r--source/blender/editors/transform/transform_mode.h9
-rw-r--r--source/blender/editors/transform/transform_mode_edge_crease.c13
-rw-r--r--source/blender/editors/transform/transform_mode_edge_slide.c2
-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_ops.c31
-rw-r--r--source/blender/editors/transform/transform_orientations.c4
-rw-r--r--source/blender/editors/transform/transform_orientations.h8
-rw-r--r--source/blender/editors/transform/transform_snap.c30
-rw-r--r--source/blender/editors/transform/transform_snap.h10
-rw-r--r--source/blender/editors/transform/transform_snap_object.c244
-rw-r--r--source/blender/editors/undo/ed_undo.c123
-rw-r--r--source/blender/editors/util/CMakeLists.txt1
-rw-r--r--source/blender/editors/util/ed_draw.c34
-rw-r--r--source/blender/editors/util/ed_transverts.c12
-rw-r--r--source/blender/editors/util/ed_util.c28
-rw-r--r--source/blender/editors/util/ed_util_imbuf.c28
-rw-r--r--source/blender/editors/util/ed_util_ops.cc63
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h20
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c2
351 files changed, 14187 insertions, 13524 deletions
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index f509898f2ee..bdcbac80699 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;
@@ -961,7 +961,7 @@ static int add_driver_button_none(bContext *C, wmOperator *op, short mapping_typ
}
if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
- char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
+ char *path = RNA_path_from_ID_to_property(&ptr, prop);
short flags = CREATEDRIVER_WITH_DEFAULT_DVAR;
if (path) {
@@ -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 ------------------------ */
@@ -1055,7 +1055,7 @@ static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent *
if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
/* 1) Create a new "empty" driver for this property */
- char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
+ char *path = RNA_path_from_ID_to_property(&ptr, prop);
short flags = CREATEDRIVER_WITH_DEFAULT_DVAR;
bool changed = false;
@@ -1115,7 +1115,7 @@ static int remove_driver_button_exec(bContext *C, wmOperator *op)
}
if (ptr.owner_id && ptr.data && prop) {
- char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
+ char *path = RNA_path_from_ID_to_property(&ptr, prop);
if (path) {
changed = ANIM_remove_driver(op->reports, ptr.owner_id, path, index, 0);
@@ -1200,7 +1200,7 @@ static int copy_driver_button_exec(bContext *C, wmOperator *op)
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
- char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
+ char *path = RNA_path_from_ID_to_property(&ptr, prop);
if (path) {
/* only copy the driver for the button that this was involved for */
@@ -1244,7 +1244,7 @@ static int paste_driver_button_exec(bContext *C, wmOperator *op)
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
- char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
+ char *path = RNA_path_from_ID_to_property(&ptr, prop);
if (path) {
/* only copy the driver for the button that this was involved for */
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index 6fba2d9c258..ae8d04f51d3 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -496,7 +496,7 @@ static void ED_keylist_draw_list_elem_prepare_for_drawing(AnimKeylistDrawListEle
}
typedef struct AnimKeylistDrawList {
- ListBase /* AnimKeylistDrawListElem*/ channels;
+ ListBase /* AnimKeylistDrawListElem */ channels;
} AnimKeylistDrawList;
AnimKeylistDrawList *ED_keylist_draw_list_create(void)
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index 145d67b7810..dfe6566df67 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -1283,6 +1283,61 @@ static short set_bezt_sine(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
return 0;
}
+static void handle_flatten(float vec[3][3], const int idx, const float direction[2])
+{
+ BLI_assert_msg(idx == 0 || idx == 2, "handle_flatten() expects a handle index");
+
+ add_v2_v2v2(vec[idx], vec[1], direction);
+}
+
+static void handle_set_length(float vec[3][3], const int idx, const float handle_length)
+{
+ BLI_assert_msg(idx == 0 || idx == 2, "handle_set_length() expects a handle index");
+
+ float handle_direction[2];
+ sub_v2_v2v2(handle_direction, vec[idx], vec[1]);
+ normalize_v2_length(handle_direction, handle_length);
+ add_v2_v2v2(vec[idx], vec[1], handle_direction);
+}
+
+void ANIM_fcurve_equalize_keyframes_loop(FCurve *fcu,
+ const eEditKeyframes_Equalize mode,
+ const float handle_length,
+ const bool flatten)
+{
+ uint i;
+ BezTriple *bezt;
+ const float flat_direction_left[2] = {-handle_length, 0.f};
+ const float flat_direction_right[2] = {handle_length, 0.f};
+
+ /* Loop through an F-Curves keyframes. */
+ for (bezt = fcu->bezt, i = 0; i < fcu->totvert; bezt++, i++) {
+ if ((bezt->f2 & SELECT) == 0) {
+ continue;
+ }
+
+ /* Perform handle equalization if mode is 'Both' or 'Left'. */
+ if (mode & EQUALIZE_HANDLES_LEFT) {
+ if (flatten) {
+ handle_flatten(bezt->vec, 0, flat_direction_left);
+ }
+ else {
+ handle_set_length(bezt->vec, 0, handle_length);
+ }
+ }
+
+ /* Perform handle equalization if mode is 'Both' or 'Right'. */
+ if (mode & EQUALIZE_HANDLES_RIGHT) {
+ if (flatten) {
+ handle_flatten(bezt->vec, 2, flat_direction_right);
+ }
+ else {
+ handle_set_length(bezt->vec, 2, handle_length);
+ }
+ }
+ }
+}
+
KeyframeEditFunc ANIM_editkeyframes_ipo(short mode)
{
switch (mode) {
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index dc5d71b5a1e..92017c02858 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -307,11 +307,13 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo
}
}
-/** Find the first segment of consecutive selected curve points, starting from \a start_index.
+/**
+ * Find the first segment of consecutive selected curve points, starting from \a start_index.
* Keys that have BEZT_FLAG_IGNORE_TAG set are treated as unselected.
* \param r_segment_start_idx: returns the start index of the segment.
* \param r_segment_len: returns the number of curve points in the segment.
- * \return whether such a segment was found or not.*/
+ * \return whether such a segment was found or not.
+ */
static bool find_fcurve_segment(FCurve *fcu,
const int start_index,
int *r_segment_start_idx,
@@ -345,6 +347,67 @@ static bool find_fcurve_segment(FCurve *fcu,
return in_segment;
}
+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;
+}
+
+static BezTriple fcurve_segment_start_get(FCurve *fcu, int index)
+{
+ BezTriple start_bezt = index - 1 >= 0 ? fcu->bezt[index - 1] : fcu->bezt[index];
+ return start_bezt;
+}
+
+static BezTriple fcurve_segment_end_get(FCurve *fcu, int index)
+{
+ BezTriple end_bezt = index < fcu->totvert ? fcu->bezt[index] : fcu->bezt[index - 1];
+ return end_bezt;
+}
+
+/* ---------------- */
+
+void blend_to_neighbor_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor)
+{
+ const float blend_factor = fabs(factor * 2 - 1);
+ BezTriple target_bezt;
+ /* Find which key to blend towards. */
+ if (factor < 0.5f) {
+ target_bezt = fcurve_segment_start_get(fcu, segment->start_index);
+ }
+ else {
+ target_bezt = fcurve_segment_end_get(fcu, segment->start_index + segment->length);
+ }
+ /* Blend each key individually. */
+ for (int i = segment->start_index; i < segment->start_index + segment->length; i++) {
+ fcu->bezt[i].vec[1][1] = interpf(target_bezt.vec[1][1], fcu->bezt[i].vec[1][1], blend_factor);
+ }
+}
+
+/* ---------------- */
+
+void breakdown_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor)
+{
+ BezTriple left_bezt = fcurve_segment_start_get(fcu, segment->start_index);
+ BezTriple right_bezt = fcurve_segment_end_get(fcu, segment->start_index + segment->length);
+
+ for (int i = segment->start_index; i < segment->start_index + segment->length; i++) {
+ fcu->bezt[i].vec[1][1] = interpf(right_bezt.vec[1][1], left_bezt.vec[1][1], factor);
+ }
+}
+
/* ---------------- */
/* Check if the keyframe interpolation type is supported */
@@ -440,15 +503,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/animation/keyframes_keylist.cc b/source/blender/editors/animation/keyframes_keylist.cc
index 8dae46766fa..aba73ec141b 100644
--- a/source/blender/editors/animation/keyframes_keylist.cc
+++ b/source/blender/editors/animation/keyframes_keylist.cc
@@ -80,7 +80,7 @@ struct AnimKeylist {
ListBase /* ActKeyColumn */ key_columns;
/* Last accessed column in the key_columns list base. Inserting columns are typically done in
* order. The last accessed column is used as starting point to search for a location to add or
- * update the next column.*/
+ * update the next column. */
std::optional<ActKeyColumn *> last_accessed_column = std::nullopt;
struct {
@@ -850,7 +850,6 @@ bool actkeyblock_is_valid(const ActKeyColumn *ac)
return ac != nullptr && ac->next != nullptr && ac->totblock > 0;
}
-/* Checks if ActKeyBlock should exist... */
int actkeyblock_get_valid_hold(const ActKeyColumn *ac)
{
/* check that block is valid */
diff --git a/source/blender/editors/animation/keyframes_keylist_test.cc b/source/blender/editors/animation/keyframes_keylist_test.cc
index 17a21be5ae8..914693842ca 100644
--- a/source/blender/editors/animation/keyframes_keylist_test.cc
+++ b/source/blender/editors/animation/keyframes_keylist_test.cc
@@ -26,12 +26,12 @@ static void build_fcurve(FCurve &fcurve)
fcurve.totvert = 3;
fcurve.bezt = static_cast<BezTriple *>(
MEM_callocN(sizeof(BezTriple) * fcurve.totvert, "BezTriples"));
- fcurve.bezt[0].vec[1][0] = 10.f;
- fcurve.bezt[0].vec[1][1] = 1.f;
- fcurve.bezt[1].vec[1][0] = 20.f;
- fcurve.bezt[1].vec[1][1] = 2.f;
- fcurve.bezt[2].vec[1][0] = 30.f;
- fcurve.bezt[2].vec[1][1] = 1.f;
+ fcurve.bezt[0].vec[1][0] = 10.0f;
+ fcurve.bezt[0].vec[1][1] = 1.0f;
+ fcurve.bezt[1].vec[1][0] = 20.0f;
+ fcurve.bezt[1].vec[1][1] = 2.0f;
+ fcurve.bezt[2].vec[1][0] = 30.0f;
+ fcurve.bezt[2].vec[1][1] = 1.0f;
}
static AnimKeylist *create_test_keylist()
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 25d2f6c510b..0a435a9034a 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -580,7 +580,7 @@ int insert_vert_fcurve(
beztr.ipo = BEZT_IPO_BEZ;
}
else {
- /* for UI usage - defaults should come from the userprefs and/or toolsettings */
+ /* For UI usage - defaults should come from the user-preferences and/or tool-settings. */
beztr.h1 = beztr.h2 = U.keyhandles_new; /* use default handle type here */
/* use default interpolation mode, with exceptions for int/discrete values */
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index 97f8c0cf630..252cf806e34 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -297,7 +297,7 @@ void armature_tag_select_mirrored(struct bArmature *arm);
* Helper function for tools to work on mirrored parts.
* it leaves mirrored bones selected then too, which is a good indication of what happened.
*/
-void armature_select_mirrored_ex(struct bArmature *arm, const int flag);
+void armature_select_mirrored_ex(struct bArmature *arm, int flag);
void armature_select_mirrored(struct bArmature *arm);
/** Only works when tagged. */
void armature_tag_unselect(struct bArmature *arm);
diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c
index 990e7589d9d..787d7cbaab0 100644
--- a/source/blender/editors/armature/meshlaplacian.c
+++ b/source/blender/editors/armature/meshlaplacian.c
@@ -1618,8 +1618,7 @@ static void harmonic_coordinates_bind(MeshDeformModifierData *mmd, MeshDeformBin
mdb->cagemesh_cache.mpoly = me->mpoly;
mdb->cagemesh_cache.mloop = me->mloop;
mdb->cagemesh_cache.looptri = BKE_mesh_runtime_looptri_ensure(me);
- /* can be NULL */
- mdb->cagemesh_cache.poly_nors = CustomData_get_layer(&me->pdata, CD_NORMAL);
+ mdb->cagemesh_cache.poly_nors = BKE_mesh_poly_normals_ensure(me);
}
/* make bounding box equal size in all directions, add padding, and compute
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/CMakeLists.txt b/source/blender/editors/asset/CMakeLists.txt
index 2391f4af14d..086fab4ab47 100644
--- a/source/blender/editors/asset/CMakeLists.txt
+++ b/source/blender/editors/asset/CMakeLists.txt
@@ -48,6 +48,7 @@ set(SRC
ED_asset_catalog.hh
ED_asset_filter.h
ED_asset_handle.h
+ ED_asset_indexer.h
ED_asset_library.h
ED_asset_list.h
ED_asset_list.hh
diff --git a/source/blender/editors/asset/ED_asset_catalog.h b/source/blender/editors/asset/ED_asset_catalog.h
index be99de01173..acb0b67d9c0 100644
--- a/source/blender/editors/asset/ED_asset_catalog.h
+++ b/source/blender/editors/asset/ED_asset_catalog.h
@@ -28,8 +28,8 @@
extern "C" {
#endif
-struct Main;
struct AssetLibrary;
+struct Main;
void ED_asset_catalogs_save_from_main_path(struct AssetLibrary *library, const struct Main *bmain);
diff --git a/source/blender/editors/asset/ED_asset_mark_clear.h b/source/blender/editors/asset/ED_asset_mark_clear.h
index 8e6a8e11d69..8f10e769c52 100644
--- a/source/blender/editors/asset/ED_asset_mark_clear.h
+++ b/source/blender/editors/asset/ED_asset_mark_clear.h
@@ -25,8 +25,8 @@ extern "C" {
#endif
struct ID;
-struct bContext;
struct Main;
+struct bContext;
/**
* Mark the datablock as asset.
@@ -50,7 +50,8 @@ void ED_asset_generate_preview(const struct bContext *C, struct ID *id);
* This clears the Fake User. If for some reason the datablock is meant to be saved anyway, the
* caller is responsible for explicitly setting the Fake User.
*
- * \return whether the asset metadata was actually removed; false when the ID was not an asset. */
+ * \return whether the asset metadata was actually removed; false when the ID was not an asset.
+ */
bool ED_asset_clear_id(struct ID *id);
void ED_assets_pre_save(struct Main *bmain);
diff --git a/source/blender/editors/asset/ED_asset_type.h b/source/blender/editors/asset/ED_asset_type.h
index 36cbb4591e9..e1c327808aa 100644
--- a/source/blender/editors/asset/ED_asset_type.h
+++ b/source/blender/editors/asset/ED_asset_type.h
@@ -30,7 +30,7 @@ struct ID;
bool ED_asset_type_id_is_non_experimental(const struct ID *id);
#define ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_FLAGS \
- (FILTER_ID_MA | FILTER_ID_OB | FILTER_ID_AC | FILTER_ID_WO)
+ (FILTER_ID_MA | FILTER_ID_OB | FILTER_ID_AC | FILTER_ID_WO | FILTER_ID_NT)
/**
* Check if the asset type for \a id (which doesn't need to be an asset right now) can be an asset,
@@ -52,7 +52,8 @@ int64_t ED_asset_types_supported_as_filter_flags(void);
* strings with this (not all UI code supports dynamic strings nicely).
* Should start with a consonant, so usages can prefix it with "a" (not "an").
*/
-#define ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_UI_STRING "Material, Object, Pose Action, or World"
+#define ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_UI_STRING \
+ "Material, Object, Pose Action, Node Group or World"
#ifdef __cplusplus
}
diff --git a/source/blender/editors/asset/intern/asset_indexer.cc b/source/blender/editors/asset/intern/asset_indexer.cc
index 4107d28b5e3..336ccff900c 100644
--- a/source/blender/editors/asset/intern/asset_indexer.cc
+++ b/source/blender/editors/asset/intern/asset_indexer.cc
@@ -39,6 +39,7 @@
#include "BKE_appdir.h"
#include "BKE_asset.h"
#include "BKE_asset_catalog.hh"
+#include "BKE_idprop.hh"
#include "BKE_preferences.h"
#include "CLG_log.h"
@@ -49,6 +50,7 @@ namespace blender::ed::asset::index {
using namespace blender::io::serialize;
using namespace blender::bke;
+using namespace blender::bke::idprop;
/**
* \file asset_indexer.cc
@@ -69,12 +71,13 @@ using namespace blender::bke;
* "catalog_name": "<catalog_name>",
* "description": "<description>",
* "author": "<author>",
- * "tags": ["<tag>"]
+ * "tags": ["<tag>"],
+ * "properties": [..]
* }]
* }
* \endcode
*
- * NOTE: entries, author, description and tags are optional attributes.
+ * NOTE: entries, author, description, tags and properties are optional attributes.
*
* NOTE: File browser uses name and idcode separate. Inside the index they are joined together like
* #ID.name.
@@ -88,6 +91,7 @@ constexpr StringRef ATTRIBUTE_ENTRIES_CATALOG_NAME("catalog_name");
constexpr StringRef ATTRIBUTE_ENTRIES_DESCRIPTION("description");
constexpr StringRef ATTRIBUTE_ENTRIES_AUTHOR("author");
constexpr StringRef ATTRIBUTE_ENTRIES_TAGS("tags");
+constexpr StringRef ATTRIBUTE_ENTRIES_PROPERTIES("properties");
/** Abstract class for #BlendFile and #AssetIndexFile. */
class AbstractFile {
@@ -145,7 +149,7 @@ struct AssetEntryReader {
/**
* \brief Lookup table containing the elements of the entry.
*/
- ObjectValue::Lookup lookup;
+ DictionaryValue::Lookup lookup;
StringRefNull get_name_with_idcode() const
{
@@ -153,7 +157,7 @@ struct AssetEntryReader {
}
public:
- AssetEntryReader(const ObjectValue &entry) : lookup(entry.create_lookup())
+ AssetEntryReader(const DictionaryValue &entry) : lookup(entry.create_lookup())
{
}
@@ -204,7 +208,7 @@ struct AssetEntryReader {
void add_tags_to_meta_data(AssetMetaData *asset_data) const
{
- const ObjectValue::LookupValue *value_ptr = lookup.lookup_ptr(ATTRIBUTE_ENTRIES_TAGS);
+ const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(ATTRIBUTE_ENTRIES_TAGS);
if (value_ptr == nullptr) {
return;
}
@@ -216,14 +220,28 @@ struct AssetEntryReader {
BKE_asset_metadata_tag_add(asset_data, tag_name.c_str());
}
}
+
+ void add_properties_to_meta_data(AssetMetaData *asset_data) const
+ {
+ BLI_assert(asset_data->properties == nullptr);
+ const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(
+ ATTRIBUTE_ENTRIES_PROPERTIES);
+ if (value_ptr == nullptr) {
+ return;
+ }
+
+ const Value &value = *(value_ptr->get());
+ IDProperty *properties = convert_from_serialize_value(value);
+ asset_data->properties = properties;
+ }
};
struct AssetEntryWriter {
private:
- ObjectValue::Items &attributes;
+ DictionaryValue::Items &attributes;
public:
- AssetEntryWriter(ObjectValue &entry) : attributes(entry.elements())
+ AssetEntryWriter(DictionaryValue &entry) : attributes(entry.elements())
{
}
@@ -274,6 +292,15 @@ struct AssetEntryWriter {
tag_items.append_as(new StringValue(tag->name));
}
}
+
+ void add_properties(const IDProperty *properties)
+ {
+ std::unique_ptr<Value> value = convert_to_serialize_values(properties);
+ if (value == nullptr) {
+ return;
+ }
+ attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_PROPERTIES, value.release()));
+ }
};
static void init_value_from_file_indexer_entry(AssetEntryWriter &result,
@@ -298,10 +325,14 @@ static void init_value_from_file_indexer_entry(AssetEntryWriter &result,
result.add_tags(&asset_data.tags);
}
+ if (asset_data.properties != nullptr) {
+ result.add_properties(asset_data.properties);
+ }
+
/* TODO: asset_data.IDProperties */
}
-static void init_value_from_file_indexer_entries(ObjectValue &result,
+static void init_value_from_file_indexer_entries(DictionaryValue &result,
const FileIndexerEntries &indexer_entries)
{
ArrayValue *entries = new ArrayValue();
@@ -313,7 +344,7 @@ static void init_value_from_file_indexer_entries(ObjectValue &result,
if (indexer_entry->datablock_info.asset_data == nullptr) {
continue;
}
- ObjectValue *entry_value = new ObjectValue();
+ DictionaryValue *entry_value = new DictionaryValue();
AssetEntryWriter entry(*entry_value);
init_value_from_file_indexer_entry(entry, indexer_entry);
items.append_as(entry_value);
@@ -326,7 +357,7 @@ static void init_value_from_file_indexer_entries(ObjectValue &result,
return;
}
- ObjectValue::Items &attributes = result.elements();
+ DictionaryValue::Items &attributes = result.elements();
attributes.append_as(std::pair(ATTRIBUTE_ENTRIES, entries));
}
@@ -363,13 +394,14 @@ static void init_indexer_entry_from_value(FileIndexerEntry &indexer_entry,
asset_data->catalog_id = entry.get_catalog_id();
entry.add_tags_to_meta_data(asset_data);
+ entry.add_properties_to_meta_data(asset_data);
}
static int init_indexer_entries_from_value(FileIndexerEntries &indexer_entries,
- const ObjectValue &value)
+ const DictionaryValue &value)
{
- const ObjectValue::Lookup attributes = value.create_lookup();
- const ObjectValue::LookupValue *entries_value = attributes.lookup_ptr(ATTRIBUTE_ENTRIES);
+ const DictionaryValue::Lookup attributes = value.create_lookup();
+ const DictionaryValue::LookupValue *entries_value = attributes.lookup_ptr(ATTRIBUTE_ENTRIES);
BLI_assert(entries_value != nullptr);
if (entries_value == nullptr) {
@@ -379,7 +411,7 @@ static int init_indexer_entries_from_value(FileIndexerEntries &indexer_entries,
int num_entries_read = 0;
const ArrayValue::Items elements = (*entries_value)->as_array_value()->elements();
for (ArrayValue::Item element : elements) {
- const AssetEntryReader asset_entry(*element->as_object_value());
+ const AssetEntryReader asset_entry(*element->as_dictionary_value());
FileIndexerEntry *entry = static_cast<FileIndexerEntry *>(
MEM_callocN(sizeof(FileIndexerEntry), __func__));
@@ -534,9 +566,9 @@ struct AssetIndex {
/**
* `blender::io::serialize::Value` representing the contents of an index file.
*
- * Value is used over #ObjectValue as the contents of the index could be corrupted and doesn't
- * represent an object. In case corrupted files are detected the `get_version` would return
- * `UNKNOWN_VERSION`.
+ * Value is used over #DictionaryValue as the contents of the index could be corrupted and
+ * doesn't represent an object. In case corrupted files are detected the `get_version` would
+ * return `UNKNOWN_VERSION`.
*/
std::unique_ptr<Value> contents;
@@ -546,8 +578,8 @@ struct AssetIndex {
*/
AssetIndex(const FileIndexerEntries &indexer_entries)
{
- std::unique_ptr<ObjectValue> root = std::make_unique<ObjectValue>();
- ObjectValue::Items &root_attributes = root->elements();
+ std::unique_ptr<DictionaryValue> root = std::make_unique<DictionaryValue>();
+ DictionaryValue::Items &root_attributes = root->elements();
root_attributes.append_as(std::pair(ATTRIBUTE_VERSION, new IntValue(CURRENT_VERSION)));
init_value_from_file_indexer_entries(*root, indexer_entries);
@@ -564,12 +596,12 @@ struct AssetIndex {
int get_version() const
{
- const ObjectValue *root = contents->as_object_value();
+ const DictionaryValue *root = contents->as_dictionary_value();
if (root == nullptr) {
return UNKNOWN_VERSION;
}
- const ObjectValue::Lookup attributes = root->create_lookup();
- const ObjectValue::LookupValue *version_value = attributes.lookup_ptr(ATTRIBUTE_VERSION);
+ const DictionaryValue::Lookup attributes = root->create_lookup();
+ const DictionaryValue::LookupValue *version_value = attributes.lookup_ptr(ATTRIBUTE_VERSION);
if (version_value == nullptr) {
return UNKNOWN_VERSION;
}
@@ -588,7 +620,7 @@ struct AssetIndex {
*/
int extract_into(FileIndexerEntries &indexer_entries) const
{
- const ObjectValue *root = contents->as_object_value();
+ const DictionaryValue *root = contents->as_dictionary_value();
const int num_entries_read = init_indexer_entries_from_value(indexer_entries, *root);
return num_entries_read;
}
@@ -742,16 +774,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_list.cc b/source/blender/editors/asset/intern/asset_list.cc
index 1bfdd83b8e3..c075ae390d9 100644
--- a/source/blender/editors/asset/intern/asset_list.cc
+++ b/source/blender/editors/asset/intern/asset_list.cc
@@ -49,10 +49,6 @@
#include "ED_asset_list.hh"
#include "asset_library_reference.hh"
-/* Enable asset indexing. Currently disabled as ID properties aren't indexed yet and is needed for
- * object snapping. See {D12990}. */
-//#define SPACE_FILE_ENABLE_ASSET_INDEXING
-
namespace blender::ed::asset {
/* -------------------------------------------------------------------- */
@@ -174,9 +170,7 @@ void AssetList::setup()
"",
"");
-#ifdef SPACE_FILE_ENABLE_ASSET_INDEXING
filelist_setindexer(files, &file_indexer_asset);
-#endif
char path[FILE_MAXDIR] = "";
if (user_library) {
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/asset/intern/asset_type.cc b/source/blender/editors/asset/intern/asset_type.cc
index 028c0cb9ffc..3d6ce3e3409 100644
--- a/source/blender/editors/asset/intern/asset_type.cc
+++ b/source/blender/editors/asset/intern/asset_type.cc
@@ -30,7 +30,7 @@ bool ED_asset_type_id_is_non_experimental(const ID *id)
{
/* Remember to update #ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_UI_STRING and
* #ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_FLAGS() with this! */
- return ELEM(GS(id->name), ID_MA, ID_OB, ID_AC, ID_WO);
+ return ELEM(GS(id->name), ID_MA, ID_OB, ID_AC, ID_WO, ID_NT);
}
bool ED_asset_type_is_supported(const ID *id)
diff --git a/source/blender/editors/curve/curve_intern.h b/source/blender/editors/curve/curve_intern.h
index 03ddeebde42..0d17af1983d 100644
--- a/source/blender/editors/curve/curve_intern.h
+++ b/source/blender/editors/curve/curve_intern.h
@@ -155,7 +155,7 @@ void ed_editnurb_translate_flag(struct ListBase *editnurb,
/**
* Only for #OB_SURF.
*/
-bool ed_editnurb_extrude_flag(struct EditNurb *editnurb, const uint8_t flag);
+bool ed_editnurb_extrude_flag(struct EditNurb *editnurb, uint8_t flag);
/**
* \param axis: is in world-space.
* \param cent: is in object-space.
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index a034e4bb10e..a70bc1c0350 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -4953,19 +4953,22 @@ bool ed_editnurb_spin(
if ((a & 1) == 0) {
rotateflagNurb(editnurb, SELECT, cent, scalemat1);
- weightflagNurb(editnurb, SELECT, 0.25 * M_SQRT2);
+ weightflagNurb(editnurb, SELECT, 0.5 * M_SQRT2);
}
else {
rotateflagNurb(editnurb, SELECT, cent, scalemat2);
- weightflagNurb(editnurb, SELECT, 4.0 / M_SQRT2);
+ weightflagNurb(editnurb, SELECT, 2.0 / M_SQRT2);
}
}
if (ok) {
LISTBASE_FOREACH (Nurb *, nu, editnurb) {
if (ED_curve_nurb_select_check(v3d, nu)) {
- nu->orderv = 4;
- nu->flagv |= CU_NURB_CYCLIC;
+ nu->orderv = 3;
+ /* It is challenging to create a good approximation of a circle with uniform knots vector
+ * (which is forced in Blender for cyclic NURBS curves). Here a NURBS circle is constructed
+ * by connecting four Bezier arcs. */
+ nu->flagv |= CU_NURB_CYCLIC | CU_NURB_BEZIER;
BKE_nurb_knot_calc_v(nu);
}
}
diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c
index 614805a70f5..daef4a21692 100644
--- a/source/blender/editors/curve/editcurve_add.c
+++ b/source/blender/editors/curve/editcurve_add.c
@@ -306,9 +306,9 @@ Nurb *ED_curve_add_nurbs_primitive(
else if (cutype == CU_NURBS) { /* nurb */
nu->pntsu = 8;
nu->pntsv = 1;
- nu->orderu = 4;
+ nu->orderu = 3;
nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * nu->pntsu, "addNurbprim6");
- nu->flagu = CU_NURB_CYCLIC;
+ nu->flagu = CU_NURB_CYCLIC | CU_NURB_BEZIER;
bp = nu->bp;
for (a = 0; a < 8; a++) {
@@ -322,7 +322,7 @@ Nurb *ED_curve_add_nurbs_primitive(
bp->vec[2] += 0.25f * nurbcircle[a][1] * grid;
}
if (a & 1) {
- bp->vec[3] = 0.25 * M_SQRT2;
+ bp->vec[3] = 0.5 * M_SQRT2;
}
else {
bp->vec[3] = 1.0;
diff --git a/source/blender/editors/geometry/CMakeLists.txt b/source/blender/editors/geometry/CMakeLists.txt
index 75b334b9ec6..8c920915937 100644
--- a/source/blender/editors/geometry/CMakeLists.txt
+++ b/source/blender/editors/geometry/CMakeLists.txt
@@ -20,19 +20,21 @@ set(INC
../../blenkernel
../../blenlib
../../depsgraph
+ ../../functions
../../makesdna
../../makesrna
../../windowmanager
+ ../../../../intern/guardedalloc
)
set(INC_SYS
)
set(SRC
- geometry_attributes.c
- geometry_ops.c
+ geometry_attributes.cc
+ geometry_ops.cc
- geometry_intern.h
+ geometry_intern.hh
)
set(LIB
diff --git a/source/blender/editors/geometry/geometry_attributes.c b/source/blender/editors/geometry/geometry_attributes.c
deleted file mode 100644
index 5cb491f116a..00000000000
--- a/source/blender/editors/geometry/geometry_attributes.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2020 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup edgeometry
- */
-
-#include "BKE_attribute.h"
-#include "BKE_context.h"
-
-#include "RNA_access.h"
-#include "RNA_define.h"
-#include "RNA_enum_types.h"
-
-#include "DEG_depsgraph.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "ED_object.h"
-
-#include "geometry_intern.h"
-
-/*********************** Attribute Operators ************************/
-
-static bool geometry_attributes_poll(bContext *C)
-{
- Object *ob = ED_object_context(C);
- ID *data = (ob) ? ob->data : NULL;
- return (ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data)) &&
- BKE_id_attributes_supported(data);
-}
-
-static bool geometry_attributes_remove_poll(bContext *C)
-{
- if (!geometry_attributes_poll(C)) {
- return false;
- }
-
- Object *ob = ED_object_context(C);
- ID *data = (ob) ? ob->data : NULL;
- if (BKE_id_attributes_active_get(data) != NULL) {
- return true;
- }
-
- return false;
-}
-
-static const EnumPropertyItem *geometry_attribute_domain_itemf(bContext *C,
- PointerRNA *UNUSED(ptr),
- PropertyRNA *UNUSED(prop),
- bool *r_free)
-{
- if (C == NULL) {
- return DummyRNA_NULL_items;
- }
-
- Object *ob = ED_object_context(C);
- if (ob == NULL) {
- return DummyRNA_NULL_items;
- }
-
- return rna_enum_attribute_domain_itemf(ob->data, r_free);
-}
-
-static int geometry_attribute_add_exec(bContext *C, wmOperator *op)
-{
- Object *ob = ED_object_context(C);
- ID *id = ob->data;
-
- char name[MAX_NAME];
- RNA_string_get(op->ptr, "name", name);
- CustomDataType type = (CustomDataType)RNA_enum_get(op->ptr, "data_type");
- AttributeDomain domain = (AttributeDomain)RNA_enum_get(op->ptr, "domain");
- CustomDataLayer *layer = BKE_id_attribute_new(id, name, type, domain, op->reports);
-
- if (layer == NULL) {
- return OPERATOR_CANCELLED;
- }
-
- BKE_id_attributes_active_set(id, layer);
-
- DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
- WM_main_add_notifier(NC_GEOM | ND_DATA, id);
-
- return OPERATOR_FINISHED;
-}
-
-void GEOMETRY_OT_attribute_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Add Geometry Attribute";
- ot->description = "Add attribute to geometry";
- ot->idname = "GEOMETRY_OT_attribute_add";
-
- /* api callbacks */
- ot->poll = geometry_attributes_poll;
- ot->exec = geometry_attribute_add_exec;
- ot->invoke = WM_operator_props_popup_confirm;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- PropertyRNA *prop;
-
- prop = RNA_def_string(ot->srna, "name", "Attribute", MAX_NAME, "Name", "Name of new attribute");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-
- prop = RNA_def_enum(ot->srna,
- "domain",
- rna_enum_attribute_domain_items,
- ATTR_DOMAIN_POINT,
- "Domain",
- "Type of element that attribute is stored on");
- RNA_def_enum_funcs(prop, geometry_attribute_domain_itemf);
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-
- prop = RNA_def_enum(ot->srna,
- "data_type",
- rna_enum_attribute_type_items,
- CD_PROP_FLOAT,
- "Data Type",
- "Type of data stored in attribute");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-}
-
-static int geometry_attribute_remove_exec(bContext *C, wmOperator *op)
-{
- Object *ob = ED_object_context(C);
- ID *id = ob->data;
- CustomDataLayer *layer = BKE_id_attributes_active_get(id);
-
- if (layer == NULL) {
- return OPERATOR_CANCELLED;
- }
-
- if (!BKE_id_attribute_remove(id, layer, op->reports)) {
- return OPERATOR_CANCELLED;
- }
-
- int *active_index = BKE_id_attributes_active_index_p(id);
- if (*active_index > 0) {
- *active_index -= 1;
- }
-
- DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
- WM_main_add_notifier(NC_GEOM | ND_DATA, id);
-
- return OPERATOR_FINISHED;
-}
-
-void GEOMETRY_OT_attribute_remove(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Remove Geometry Attribute";
- ot->description = "Remove attribute from geometry";
- ot->idname = "GEOMETRY_OT_attribute_remove";
-
- /* api callbacks */
- ot->exec = geometry_attribute_remove_exec;
- ot->poll = geometry_attributes_remove_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc
new file mode 100644
index 00000000000..56ecd108bba
--- /dev/null
+++ b/source/blender/editors/geometry/geometry_attributes.cc
@@ -0,0 +1,385 @@
+/*
+ * 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) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edgeometry
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_attribute.h"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_geometry_set.hh"
+#include "BKE_object_deform.h"
+#include "BKE_report.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "ED_object.h"
+
+#include "geometry_intern.hh"
+
+namespace blender::ed::geometry {
+
+using fn::CPPType;
+using fn::GArray;
+using fn::GVArray;
+
+/*********************** Attribute Operators ************************/
+
+static bool geometry_attributes_poll(bContext *C)
+{
+ Object *ob = ED_object_context(C);
+ ID *data = (ob) ? static_cast<ID *>(ob->data) : nullptr;
+ return (ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data)) &&
+ BKE_id_attributes_supported(data);
+}
+
+static bool geometry_attributes_remove_poll(bContext *C)
+{
+ if (!geometry_attributes_poll(C)) {
+ return false;
+ }
+
+ Object *ob = ED_object_context(C);
+ ID *data = (ob) ? static_cast<ID *>(ob->data) : nullptr;
+ if (BKE_id_attributes_active_get(data) != nullptr) {
+ return true;
+ }
+
+ return false;
+}
+
+static const EnumPropertyItem *geometry_attribute_domain_itemf(bContext *C,
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ if (C == nullptr) {
+ return DummyRNA_NULL_items;
+ }
+
+ Object *ob = ED_object_context(C);
+ if (ob == nullptr) {
+ return DummyRNA_NULL_items;
+ }
+
+ return rna_enum_attribute_domain_itemf(static_cast<ID *>(ob->data), false, r_free);
+}
+
+static int geometry_attribute_add_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_context(C);
+ ID *id = static_cast<ID *>(ob->data);
+
+ char name[MAX_NAME];
+ RNA_string_get(op->ptr, "name", name);
+ CustomDataType type = (CustomDataType)RNA_enum_get(op->ptr, "data_type");
+ AttributeDomain domain = (AttributeDomain)RNA_enum_get(op->ptr, "domain");
+ CustomDataLayer *layer = BKE_id_attribute_new(id, name, type, domain, op->reports);
+
+ if (layer == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_id_attributes_active_set(id, layer);
+
+ DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, id);
+
+ return OPERATOR_FINISHED;
+}
+
+void GEOMETRY_OT_attribute_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Geometry Attribute";
+ ot->description = "Add attribute to geometry";
+ ot->idname = "GEOMETRY_OT_attribute_add";
+
+ /* api callbacks */
+ ot->poll = geometry_attributes_poll;
+ ot->exec = geometry_attribute_add_exec;
+ ot->invoke = WM_operator_props_popup_confirm;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ PropertyRNA *prop;
+
+ prop = RNA_def_string(ot->srna, "name", "Attribute", MAX_NAME, "Name", "Name of new attribute");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_enum(ot->srna,
+ "domain",
+ rna_enum_attribute_domain_items,
+ ATTR_DOMAIN_POINT,
+ "Domain",
+ "Type of element that attribute is stored on");
+ RNA_def_enum_funcs(prop, geometry_attribute_domain_itemf);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_enum(ot->srna,
+ "data_type",
+ rna_enum_attribute_type_items,
+ CD_PROP_FLOAT,
+ "Data Type",
+ "Type of data stored in attribute");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+static int geometry_attribute_remove_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_context(C);
+ ID *id = static_cast<ID *>(ob->data);
+ CustomDataLayer *layer = BKE_id_attributes_active_get(id);
+
+ if (layer == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!BKE_id_attribute_remove(id, layer, op->reports)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ int *active_index = BKE_id_attributes_active_index_p(id);
+ if (*active_index > 0) {
+ *active_index -= 1;
+ }
+
+ DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, id);
+
+ return OPERATOR_FINISHED;
+}
+
+void GEOMETRY_OT_attribute_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Geometry Attribute";
+ ot->description = "Remove attribute from geometry";
+ ot->idname = "GEOMETRY_OT_attribute_remove";
+
+ /* api callbacks */
+ ot->exec = geometry_attribute_remove_exec;
+ ot->poll = geometry_attributes_remove_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+enum class ConvertAttributeMode {
+ Generic,
+ UVMap,
+ VertexGroup,
+ VertexColor,
+};
+
+static bool geometry_attribute_convert_poll(bContext *C)
+{
+ if (!geometry_attributes_poll(C)) {
+ return false;
+ }
+
+ Object *ob = ED_object_context(C);
+ ID *data = static_cast<ID *>(ob->data);
+ if (GS(data->name) != ID_ME) {
+ return false;
+ }
+ CustomDataLayer *layer = BKE_id_attributes_active_get(data);
+ if (layer == nullptr) {
+ return false;
+ }
+ return true;
+}
+
+static int geometry_attribute_convert_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_context(C);
+ ID *ob_data = static_cast<ID *>(ob->data);
+ CustomDataLayer *layer = BKE_id_attributes_active_get(ob_data);
+ const std::string name = layer->name;
+
+ const ConvertAttributeMode mode = static_cast<ConvertAttributeMode>(
+ RNA_enum_get(op->ptr, "mode"));
+
+ Mesh *mesh = reinterpret_cast<Mesh *>(ob_data);
+ MeshComponent mesh_component;
+ mesh_component.replace(mesh, GeometryOwnershipType::Editable);
+
+ /* General conversion steps are always the same:
+ * 1. Convert old data to right domain and data type.
+ * 2. Copy the data into a new array so that it does not depend on the old attribute anymore.
+ * 3. Delete the old attribute.
+ * 4. Create a new attribute based on the previously copied data. */
+ switch (mode) {
+ case ConvertAttributeMode::Generic: {
+ const AttributeDomain dst_domain = static_cast<AttributeDomain>(
+ RNA_enum_get(op->ptr, "domain"));
+ const CustomDataType dst_type = static_cast<CustomDataType>(
+ RNA_enum_get(op->ptr, "data_type"));
+
+ if (ELEM(dst_type, CD_PROP_STRING, CD_MLOOPCOL)) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot convert to the selected type");
+ return OPERATOR_CANCELLED;
+ }
+
+ GVArray src_varray = mesh_component.attribute_get_for_read(name, dst_domain, dst_type);
+ const CPPType &cpp_type = src_varray.type();
+ void *new_data = MEM_malloc_arrayN(src_varray.size(), cpp_type.size(), __func__);
+ src_varray.materialize_to_uninitialized(new_data);
+ mesh_component.attribute_try_delete(name);
+ mesh_component.attribute_try_create(name, dst_domain, dst_type, AttributeInitMove(new_data));
+ break;
+ }
+ case ConvertAttributeMode::UVMap: {
+ MLoopUV *dst_uvs = static_cast<MLoopUV *>(
+ MEM_calloc_arrayN(mesh->totloop, sizeof(MLoopUV), __func__));
+ VArray<float2> src_varray = mesh_component.attribute_get_for_read<float2>(
+ name, ATTR_DOMAIN_CORNER, {0.0f, 0.0f});
+ for (const int i : IndexRange(mesh->totloop)) {
+ copy_v2_v2(dst_uvs[i].uv, src_varray[i]);
+ }
+ mesh_component.attribute_try_delete(name);
+ CustomData_add_layer_named(
+ &mesh->ldata, CD_MLOOPUV, CD_ASSIGN, dst_uvs, mesh->totloop, name.c_str());
+ break;
+ }
+ case ConvertAttributeMode::VertexColor: {
+ MLoopCol *dst_colors = static_cast<MLoopCol *>(
+ MEM_calloc_arrayN(mesh->totloop, sizeof(MLoopCol), __func__));
+ VArray<ColorGeometry4f> src_varray = mesh_component.attribute_get_for_read<ColorGeometry4f>(
+ name, ATTR_DOMAIN_CORNER, ColorGeometry4f{0.0f, 0.0f, 0.0f, 1.0f});
+ for (const int i : IndexRange(mesh->totloop)) {
+ ColorGeometry4b encoded_color = src_varray[i].encode();
+ copy_v4_v4_uchar(&dst_colors[i].r, &encoded_color.r);
+ }
+ mesh_component.attribute_try_delete(name);
+ CustomData_add_layer_named(
+ &mesh->ldata, CD_MLOOPCOL, CD_ASSIGN, dst_colors, mesh->totloop, name.c_str());
+ break;
+ }
+ case ConvertAttributeMode::VertexGroup: {
+ Array<float> src_weights(mesh->totvert);
+ VArray<float> src_varray = mesh_component.attribute_get_for_read<float>(
+ name, ATTR_DOMAIN_POINT, 0.0f);
+ src_varray.materialize(src_weights);
+ mesh_component.attribute_try_delete(name);
+
+ bDeformGroup *defgroup = BKE_object_defgroup_new(ob, name.c_str());
+ const int defgroup_index = BLI_findindex(BKE_id_defgroup_list_get(&mesh->id), defgroup);
+ MDeformVert *dverts = BKE_object_defgroup_data_create(&mesh->id);
+ for (const int i : IndexRange(mesh->totvert)) {
+ const float weight = src_weights[i];
+ if (weight > 0.0f) {
+ BKE_defvert_add_index_notest(dverts + i, defgroup_index, weight);
+ }
+ }
+ break;
+ }
+ }
+
+ int *active_index = BKE_id_attributes_active_index_p(&mesh->id);
+ if (*active_index > 0) {
+ *active_index -= 1;
+ }
+
+ DEG_id_tag_update(&mesh->id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, &mesh->id);
+
+ return OPERATOR_FINISHED;
+}
+
+static void geometry_attribute_convert_ui(bContext *UNUSED(C), wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+
+ uiItemR(layout, op->ptr, "mode", 0, nullptr, ICON_NONE);
+
+ const ConvertAttributeMode mode = static_cast<ConvertAttributeMode>(
+ RNA_enum_get(op->ptr, "mode"));
+
+ if (mode == ConvertAttributeMode::Generic) {
+ uiItemR(layout, op->ptr, "domain", 0, nullptr, ICON_NONE);
+ uiItemR(layout, op->ptr, "data_type", 0, nullptr, ICON_NONE);
+ }
+}
+
+static int geometry_attribute_convert_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ return WM_operator_props_dialog_popup(C, op, 300);
+}
+
+void GEOMETRY_OT_attribute_convert(wmOperatorType *ot)
+{
+ ot->name = "Convert Attribute";
+ ot->description = "Change how the attribute is stored";
+ ot->idname = "GEOMETRY_OT_attribute_convert";
+
+ ot->invoke = geometry_attribute_convert_invoke;
+ ot->exec = geometry_attribute_convert_exec;
+ ot->poll = geometry_attribute_convert_poll;
+ ot->ui = geometry_attribute_convert_ui;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ static EnumPropertyItem mode_items[] = {
+ {int(ConvertAttributeMode::Generic), "GENERIC", 0, "Generic", ""},
+ {int(ConvertAttributeMode::UVMap), "UV_MAP", 0, "UV Map", ""},
+ {int(ConvertAttributeMode::VertexGroup), "VERTEX_GROUP", 0, "Vertex Group", ""},
+ {int(ConvertAttributeMode::VertexColor), "VERTEX_COLOR", 0, "Vertex Color", ""},
+ {0, nullptr, 0, nullptr, nullptr},
+ };
+
+ PropertyRNA *prop;
+
+ RNA_def_enum(
+ ot->srna, "mode", mode_items, static_cast<int>(ConvertAttributeMode::Generic), "Mode", "");
+
+ prop = RNA_def_enum(ot->srna,
+ "domain",
+ rna_enum_attribute_domain_items,
+ ATTR_DOMAIN_POINT,
+ "Domain",
+ "Which geometry element to move the attribute to");
+ RNA_def_enum_funcs(prop, geometry_attribute_domain_itemf);
+
+ RNA_def_enum(
+ ot->srna, "data_type", rna_enum_attribute_type_items, CD_PROP_FLOAT, "Data Type", "");
+}
+
+} // namespace blender::ed::geometry
diff --git a/source/blender/editors/geometry/geometry_intern.h b/source/blender/editors/geometry/geometry_intern.hh
index 8a0f9294722..30a2a1d6eb1 100644
--- a/source/blender/editors/geometry/geometry_intern.h
+++ b/source/blender/editors/geometry/geometry_intern.hh
@@ -25,6 +25,11 @@
struct wmOperatorType;
-/* *** geometry_attributes.c *** */
+namespace blender::ed::geometry {
+
+/* *** geometry_attributes.cc *** */
void GEOMETRY_OT_attribute_add(struct wmOperatorType *ot);
void GEOMETRY_OT_attribute_remove(struct wmOperatorType *ot);
+void GEOMETRY_OT_attribute_convert(struct wmOperatorType *ot);
+
+} // namespace blender::ed::geometry
diff --git a/source/blender/editors/geometry/geometry_ops.c b/source/blender/editors/geometry/geometry_ops.cc
index ed0aeda731b..8933b2a7f00 100644
--- a/source/blender/editors/geometry/geometry_ops.c
+++ b/source/blender/editors/geometry/geometry_ops.cc
@@ -25,12 +25,15 @@
#include "ED_geometry.h"
-#include "geometry_intern.h"
+#include "geometry_intern.hh"
/**************************** registration **********************************/
void ED_operatortypes_geometry(void)
{
+ using namespace blender::ed::geometry;
+
WM_operatortype_append(GEOMETRY_OT_attribute_add);
WM_operatortype_append(GEOMETRY_OT_attribute_remove);
+ WM_operatortype_append(GEOMETRY_OT_attribute_convert);
}
diff --git a/source/blender/editors/gizmo_library/gizmo_library_intern.h b/source/blender/editors/gizmo_library/gizmo_library_intern.h
index a75a6b9a6ef..4a481f4bc59 100644
--- a/source/blender/editors/gizmo_library/gizmo_library_intern.h
+++ b/source/blender/editors/gizmo_library/gizmo_library_intern.h
@@ -52,22 +52,19 @@ typedef struct GizmoInteraction {
float precision_offset;
} GizmoInteraction;
-float gizmo_offset_from_value(GizmoCommonData *data,
- const float value,
- const bool constrained,
- const bool inverted);
+float gizmo_offset_from_value(GizmoCommonData *data, float value, bool constrained, bool inverted);
float gizmo_value_from_offset(GizmoCommonData *data,
GizmoInteraction *inter,
- const float offset,
- const bool constrained,
- const bool inverted,
- const bool use_precision);
+ float offset,
+ bool constrained,
+ bool inverted,
+ bool use_precision);
void gizmo_property_data_update(struct wmGizmo *gz,
GizmoCommonData *data,
wmGizmoProperty *gz_prop,
- const bool constrained,
- const bool inverted);
+ bool constrained,
+ bool inverted);
void gizmo_property_value_reset(bContext *C,
const struct wmGizmo *gz,
@@ -76,7 +73,7 @@ void gizmo_property_value_reset(bContext *C,
/* -------------------------------------------------------------------- */
-void gizmo_color_get(const struct wmGizmo *gz, const bool highlight, float r_color[4]);
+void gizmo_color_get(const struct wmGizmo *gz, bool highlight, float r_color[4]);
/**
* Takes mouse coordinates and returns them in relation to the gizmo.
@@ -101,7 +98,7 @@ bool gizmo_window_project_3d(
* Main draw call for #GizmoGeomInfo data
*/
void wm_gizmo_geometryinfo_draw(const struct GizmoGeomInfo *info,
- const bool select,
+ bool select,
const float color[4]);
void wm_gizmo_vec_draw(
const float color[4], const float (*verts)[3], uint vert_count, uint pos, uint primitive_type);
diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c
index 3705ea38e11..ae00fc41f40 100644
--- a/source/blender/editors/gpencil/annotate_draw.c
+++ b/source/blender/editors/gpencil/annotate_draw.c
@@ -165,7 +165,7 @@ static void annotation_draw_stroke_buffer(bGPdata *gps,
immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
immUniformColor3fvAlpha(ink, ink[3]);
immBegin(GPU_PRIM_POINTS, 1);
- immVertex2fv(pos, &pt->x);
+ immVertex2fv(pos, pt->m_xy);
}
else {
float oldpressure = points[0].pressure;
@@ -191,7 +191,7 @@ static void annotation_draw_stroke_buffer(bGPdata *gps,
if (fabsf(pt->pressure - oldpressure) > 0.2f) {
/* need to have 2 points to avoid immEnd assert error */
if (draw_points < 2) {
- immVertex2fv(pos, &(pt - 1)->x);
+ immVertex2fv(pos, (pt - 1)->m_xy);
}
immEnd();
@@ -202,7 +202,7 @@ static void annotation_draw_stroke_buffer(bGPdata *gps,
/* need to roll-back one point to ensure that there are no gaps in the stroke */
if (i != 0) {
- immVertex2fv(pos, &(pt - 1)->x);
+ immVertex2fv(pos, (pt - 1)->m_xy);
draw_points++;
}
@@ -210,12 +210,12 @@ static void annotation_draw_stroke_buffer(bGPdata *gps,
}
/* now the point we want */
- immVertex2fv(pos, &pt->x);
+ immVertex2fv(pos, pt->m_xy);
draw_points++;
}
/* need to have 2 points to avoid immEnd assert error */
if (draw_points < 2) {
- immVertex2fv(pos, &(pt - 1)->x);
+ immVertex2fv(pos, (pt - 1)->m_xy);
}
}
@@ -227,14 +227,14 @@ static void annotation_draw_stroke_buffer(bGPdata *gps,
if ((sflag & GP_STROKE_USE_ARROW_END) &&
(runtime.arrow_end_style != GP_STROKE_ARROWSTYLE_NONE)) {
float end[2];
- copy_v2_fl2(end, points[1].x, points[1].y);
+ copy_v2_v2(end, points[1].m_xy);
annotation_draw_stroke_arrow_buffer(pos, end, runtime.arrow_end, runtime.arrow_end_style);
}
/* Draw starting arrow stroke. */
if ((sflag & GP_STROKE_USE_ARROW_START) &&
(runtime.arrow_start_style != GP_STROKE_ARROWSTYLE_NONE)) {
float start[2];
- copy_v2_fl2(start, points[0].x, points[0].y);
+ copy_v2_v2(start, points[0].m_xy);
annotation_draw_stroke_arrow_buffer(
pos, start, runtime.arrow_start, runtime.arrow_start_style);
}
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index fbc44ed58d8..e75e9314659 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -426,25 +426,25 @@ static void annotation_smooth_buffer(tGPsdata *p, float inf, int idx)
/* Compute smoothed coordinate by taking the ones nearby */
if (pta) {
- copy_v2_v2(a, &pta->x);
+ copy_v2_v2(a, pta->m_xy);
madd_v2_v2fl(sco, a, average_fac);
}
if (ptb) {
- copy_v2_v2(b, &ptb->x);
+ copy_v2_v2(b, ptb->m_xy);
madd_v2_v2fl(sco, b, average_fac);
}
if (ptc) {
- copy_v2_v2(c, &ptc->x);
+ copy_v2_v2(c, ptc->m_xy);
madd_v2_v2fl(sco, c, average_fac);
}
if (ptd) {
- copy_v2_v2(d, &ptd->x);
+ copy_v2_v2(d, ptd->m_xy);
madd_v2_v2fl(sco, d, average_fac);
}
/* Based on influence factor, blend between original and optimal smoothed coordinate */
interp_v2_v2v2(c, c, sco, inf);
- copy_v2_v2(&ptc->x, c);
+ copy_v2_v2(ptc->m_xy, c);
}
static void annotation_stroke_arrow_calc_points_segment(float stroke_points[8],
@@ -492,8 +492,8 @@ static void annotation_stroke_arrow_calc_points(tGPspoint *point,
case GP_STROKE_ARROWSTYLE_CLOSED:
mul_v2_fl(norm_dir, arrow_length);
if (point != NULL) {
- add_v2_v2(&point->x, norm_dir);
- copy_v2_v2(corner, &point->x);
+ add_v2_v2(point->m_xy, norm_dir);
+ copy_v2_v2(corner, point->m_xy);
}
annotation_stroke_arrow_calc_points_segment(stroke_points,
corner,
@@ -507,8 +507,8 @@ static void annotation_stroke_arrow_calc_points(tGPspoint *point,
case GP_STROKE_ARROWSTYLE_SQUARE:
mul_v2_fl(norm_dir, arrow_length * 1.5f);
if (point != NULL) {
- add_v2_v2(&point->x, norm_dir);
- copy_v2_v2(corner, &point->x);
+ add_v2_v2(point->m_xy, norm_dir);
+ copy_v2_v2(corner, point->m_xy);
}
annotation_stroke_arrow_calc_points_segment(stroke_points,
corner,
@@ -544,7 +544,7 @@ static short annotation_stroke_addpoint(tGPsdata *p,
pt = (tGPspoint *)(gpd->runtime.sbuffer);
/* store settings */
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
/* T44932 - Pressure vals are unreliable, so ignore for now */
pt->pressure = 1.0f;
pt->strength = 1.0f;
@@ -560,7 +560,7 @@ static short annotation_stroke_addpoint(tGPsdata *p,
pt = ((tGPspoint *)(gpd->runtime.sbuffer) + 1);
/* store settings */
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
/* T44932 - Pressure vals are unreliable, so ignore for now */
pt->pressure = 1.0f;
pt->strength = 1.0f;
@@ -573,10 +573,10 @@ static short annotation_stroke_addpoint(tGPsdata *p,
if (gpd->runtime.sbuffer_sflag & (GP_STROKE_USE_ARROW_START | GP_STROKE_USE_ARROW_END)) {
/* Store start and end point coords for arrows. */
float end[2];
- copy_v2_v2(end, &pt->x);
+ copy_v2_v2(end, pt->m_xy);
pt = ((tGPspoint *)(gpd->runtime.sbuffer));
float start[2];
- copy_v2_v2(start, &pt->x);
+ copy_v2_v2(start, pt->m_xy);
/* Arrow end corner. */
if (gpd->runtime.sbuffer_sflag & GP_STROKE_USE_ARROW_END) {
@@ -609,7 +609,7 @@ static short annotation_stroke_addpoint(tGPsdata *p,
pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_used);
/* store settings */
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
pt->pressure = pressure;
/* Unused for annotations, but initialize for easier conversions to GP Object. */
pt->strength = 1.0f;
@@ -636,7 +636,7 @@ static short annotation_stroke_addpoint(tGPsdata *p,
pt = (tGPspoint *)gpd->runtime.sbuffer;
/* store settings */
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
/* T44932 - Pressure vals are unreliable, so ignore for now */
pt->pressure = 1.0f;
pt->strength = 1.0f;
@@ -678,7 +678,7 @@ static short annotation_stroke_addpoint(tGPsdata *p,
}
/* convert screen-coordinates to appropriate coordinates (and store them) */
- annotation_stroke_convertcoords(p, &pt->x, &pts->x, NULL);
+ annotation_stroke_convertcoords(p, pt->m_xy, &pts->x, NULL);
/* copy pressure and time */
pts->pressure = pt->pressure;
@@ -717,8 +717,8 @@ static void annotation_stroke_arrow_init_point(
{
/* NOTE: provided co_idx should be always pair number as it's [x1, y1, x2, y2, x3, y3]. */
const float real_co[2] = {co[co_idx], co[co_idx + 1]};
- copy_v2_v2(&ptc->x, real_co);
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ copy_v2_v2(ptc->m_xy, real_co);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
annotation_stroke_arrow_init_point_default(pt);
}
@@ -885,7 +885,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
ptc = gpd->runtime.sbuffer;
/* convert screen-coordinates to appropriate coordinates (and store them) */
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
/* copy pressure and time */
pt->pressure = ptc->pressure;
@@ -903,7 +903,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
ptc = ((tGPspoint *)runtime.sbuffer) + (runtime.sbuffer_used - 1);
/* Convert screen-coordinates to appropriate coordinates (and store them). */
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
/* Copy pressure and time. */
pt->pressure = ptc->pressure;
@@ -926,7 +926,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
/* End point. */
ptc = ((tGPspoint *)runtime.sbuffer) + (runtime.sbuffer_used - 1);
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
annotation_stroke_arrow_init_point_default(pt);
/* Fill and convert arrow points to create arrow shape. */
@@ -947,7 +947,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
/* Start point. */
ptc = runtime.sbuffer;
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
annotation_stroke_arrow_init_point_default(pt);
/* Fill and convert arrow points to create arrow shape. */
@@ -961,7 +961,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
ptc = gpd->runtime.sbuffer;
/* convert screen-coordinates to appropriate coordinates (and store them) */
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
/* copy pressure and time */
pt->pressure = ptc->pressure;
@@ -981,7 +981,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
const ViewDepths *depths = p->depths;
for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used; i++, ptc++, pt++) {
- round_v2i_v2fl(mval_i, &ptc->x);
+ round_v2i_v2fl(mval_i, ptc->m_xy);
if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, depth_arr + i) == 0) &&
(i && (ED_view3d_depth_read_cached_seg(
@@ -1041,7 +1041,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used && ptc;
i++, ptc++, pt++) {
/* convert screen-coordinates to appropriate coordinates (and store them) */
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, depth_arr ? depth_arr + i : NULL);
/* copy pressure and time */
pt->pressure = ptc->pressure;
@@ -1132,7 +1132,7 @@ static void annotation_stroke_eraser_dostroke(tGPsdata *p,
if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) {
gpencil_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]);
- /* do boundbox check first */
+ /* Do bound-box check first. */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
if (len_v2v2_int(mval_i, pc1) <= radius) {
@@ -1174,7 +1174,7 @@ static void annotation_stroke_eraser_dostroke(tGPsdata *p,
gpencil_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]);
gpencil_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]);
- /* Check that point segment of the boundbox of the eraser stroke */
+ /* Check that point segment of the bound-box of the eraser stroke. */
if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
/* Check if point segment of stroke had anything to do with
@@ -1473,7 +1473,7 @@ static tGPsdata *annotation_session_initpaint(bContext *C)
return NULL;
}
- /* Radius for eraser circle is defined in userprefs */
+ /* Radius for eraser circle is defined in user-preferences. */
/* NOTE: we do this here, so that if we exit immediately,
* erase size won't get lost
*/
@@ -1811,7 +1811,7 @@ static void annotation_draw_stabilizer(bContext *C, int x, int y, void *p_ptr)
/* Rope Simple. */
immUniformColor4f(color[0], color[1], color[2], 0.8f);
immBegin(GPU_PRIM_LINES, 2);
- immVertex2f(pos, pt->x + region->winrct.xmin, pt->y + region->winrct.ymin);
+ immVertex2f(pos, pt->m_xy[0] + region->winrct.xmin, pt->m_xy[1] + region->winrct.ymin);
immVertex2f(pos, x, y);
immEnd();
@@ -2575,8 +2575,7 @@ static int annotation_draw_modal(bContext *C, wmOperator *op, const wmEvent *eve
*/
if ((p->region) && (p->region->regiontype == RGN_TYPE_TOOLS)) {
/* Change to whatever region is now under the mouse */
- ARegion *current_region = BKE_area_find_region_xy(
- p->area, RGN_TYPE_ANY, event->xy[0], event->xy[1]);
+ ARegion *current_region = BKE_area_find_region_xy(p->area, RGN_TYPE_ANY, event->xy);
if (current_region) {
/* Assume that since we found the cursor in here, it is in bounds
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 6f63529298c..23b579b94f1 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -61,9 +61,12 @@
#include "WM_api.h"
+#include "GPU_batch.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
+#include "GPU_shader_shared.h"
#include "GPU_state.h"
+#include "GPU_uniform_buffer.h"
#include "ED_gpencil.h"
#include "ED_screen.h"
@@ -189,21 +192,27 @@ static void gpencil_draw_stroke_3d(tGPDdraw *tgpw,
};
immBindBuiltinProgram(GPU_SHADER_GPENCIL_STROKE);
- immUniform2fv("Viewport", viewport);
- immUniform1f("pixsize", tgpw->rv3d->pixsize);
+
float obj_scale = tgpw->ob ?
(tgpw->ob->scale[0] + tgpw->ob->scale[1] + tgpw->ob->scale[2]) / 3.0f :
1.0f;
- immUniform1f("objscale", obj_scale);
+ struct GPencilStrokeData gpencil_stroke_data;
+ copy_v2_v2(gpencil_stroke_data.viewport, viewport);
+ gpencil_stroke_data.pixsize = tgpw->rv3d->pixsize;
+ gpencil_stroke_data.objscale = obj_scale;
int keep_size = (int)((tgpw->gpd) && (tgpw->gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS));
- immUniform1i("keep_size", keep_size);
- immUniform1f("pixfactor", tgpw->gpd->pixfactor);
+ gpencil_stroke_data.keep_size = keep_size;
+ gpencil_stroke_data.pixfactor = tgpw->gpd->pixfactor;
/* xray mode always to 3D space to avoid wrong zdepth calculation (T60051) */
- immUniform1i("xraymode", GP_XRAY_3DSPACE);
- immUniform1i("caps_start", (int)tgpw->gps->caps[0]);
- immUniform1i("caps_end", (int)tgpw->gps->caps[1]);
- immUniform1i("fill_stroke", (int)tgpw->is_fill_stroke);
+ gpencil_stroke_data.xraymode = GP_XRAY_3DSPACE;
+ gpencil_stroke_data.caps_start = tgpw->gps->caps[0];
+ gpencil_stroke_data.caps_end = tgpw->gps->caps[1];
+ gpencil_stroke_data.fill_stroke = tgpw->is_fill_stroke;
+
+ GPUUniformBuf *ubo = GPU_uniformbuf_create_ex(
+ sizeof(struct GPencilStrokeData), &gpencil_stroke_data, __func__);
+ immBindUniformBuf("gpencil_stroke_data", ubo);
/* draw stroke curve */
immBeginAtMost(GPU_PRIM_LINE_STRIP_ADJ, totpoints + cyclic_add + 2);
@@ -255,6 +264,8 @@ static void gpencil_draw_stroke_3d(tGPDdraw *tgpw,
immEnd();
immUnbindProgram();
+
+ GPU_uniformbuf_free(ubo);
}
/* ----- Strokes Drawing ------ */
diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c
index 046b3088360..3cc47198cbc 100644
--- a/source/blender/editors/gpencil/editaction_gpencil.c
+++ b/source/blender/editors/gpencil/editaction_gpencil.c
@@ -46,6 +46,8 @@
#include "WM_api.h"
+#include "DEG_depsgraph.h"
+
/* ***************************************** */
/* NOTE ABOUT THIS FILE:
* This file contains code for editing Grease Pencil data in the Action Editor
@@ -453,6 +455,9 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
/* get frame to copy data into (if no frame returned, then just ignore) */
gpf = BKE_gpencil_layer_frame_get(gpld, gpfs->framenum, GP_GETFRAME_ADD_NEW);
if (gpf) {
+ /* Ensure to use same keyframe type. */
+ gpf->key_type = gpfs->key_type;
+
bGPDstroke *gps, *gpsn;
/* This should be the right frame... as it may be a pre-existing frame,
@@ -479,6 +484,9 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
/* unapply offset from buffer-frame */
gpfs->framenum -= offset;
}
+
+ /* Tag destination datablock. */
+ DEG_id_tag_update(ale->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
}
/* clean up */
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index bea8126cfcc..916aa8184aa 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -1468,6 +1468,10 @@ static int gpencil_layer_change_invoke(bContext *C, wmOperator *op, const wmEven
static int gpencil_layer_change_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = CTX_data_gpencil_data(C);
+ if (gpd == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
bGPDlayer *gpl = NULL;
int layer_num = RNA_enum_get(op->ptr, "layer");
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 2a656ac3aad..e71a56894d0 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -3956,8 +3956,8 @@ static void gpencil_smooth_stroke(bContext *C, wmOperator *op)
}
if (smooth_thickness) {
/* thickness need to repeat process several times */
- for (int r2 = 0; r2 < 20; r2++) {
- BKE_gpencil_stroke_smooth_thickness(gps, i, factor);
+ for (int r2 = 0; r2 < repeat * 2; r2++) {
+ BKE_gpencil_stroke_smooth_thickness(gps, i, 1.0f - factor);
}
}
if (smooth_uv) {
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
index c3af28d4382..541b6673cb6 100644
--- a/source/blender/editors/gpencil/gpencil_fill.c
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -1072,7 +1072,7 @@ static void gpencil_erase_processed_area(tGPDfill *tgpf)
/* First set in blue the perimeter. */
for (int i = 0; i < tgpf->sbuffer_used && point2D; i++, point2D++) {
- int image_idx = ibuf->x * (int)point2D->y + (int)point2D->x;
+ int image_idx = ibuf->x * (int)point2D->m_xy[1] + (int)point2D->m_xy[0];
set_pixel(ibuf, image_idx, blue_col);
}
@@ -1393,7 +1393,7 @@ static void gpencil_get_depth_array(tGPDfill *tgpf)
for (i = 0, ptc = tgpf->sbuffer; i < totpoints; i++, ptc++) {
int mval_i[2];
- round_v2i_v2fl(mval_i, &ptc->x);
+ round_v2i_v2fl(mval_i, ptc->m_xy);
if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, tgpf->depth_arr + i) == 0) &&
(i && (ED_view3d_depth_read_cached_seg(
@@ -1437,9 +1437,9 @@ static int gpencil_points_from_stack(tGPDfill *tgpf)
while (!BLI_stack_is_empty(tgpf->stack)) {
int v[2];
BLI_stack_pop(tgpf->stack, &v);
- copy_v2fl_v2i(&point2D->x, v);
+ copy_v2fl_v2i(point2D->m_xy, v);
/* shift points to center of pixel */
- add_v2_fl(&point2D->x, 0.5f);
+ add_v2_fl(point2D->m_xy, 0.5f);
point2D->pressure = 1.0f;
point2D->strength = 1.0f;
point2D->time = 0.0f;
@@ -2108,8 +2108,7 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* first time the event is not enabled to show help lines. */
if ((tgpf->oldkey != -1) || (!help_lines)) {
- ARegion *region = BKE_area_find_region_xy(
- CTX_wm_area(C), RGN_TYPE_ANY, event->xy[0], event->xy[1]);
+ ARegion *region = BKE_area_find_region_xy(CTX_wm_area(C), RGN_TYPE_ANY, event->xy);
if (region) {
bool in_bounds = false;
/* Perform bounds check */
@@ -2126,7 +2125,7 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
tgpf->gps_mouse = BKE_gpencil_stroke_new(0, 1, 10.0f);
tGPspoint point2D;
bGPDspoint *pt = &tgpf->gps_mouse->points[0];
- copy_v2fl_v2i(&point2D.x, tgpf->mouse);
+ copy_v2fl_v2i(point2D.m_xy, tgpf->mouse);
gpencil_stroke_convertcoords_tpoint(
tgpf->scene, tgpf->region, tgpf->ob, &point2D, NULL, &pt->x);
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 601780ea651..0802b806060 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -322,7 +322,7 @@ void gpencil_apply_parent_point(struct Depsgraph *depsgraph,
* generic based on gpencil_point_to_xy_fl
*/
void gpencil_point_3d_to_xy(const GP_SpaceConversion *gsc,
- const short flag,
+ short flag,
const float pt[3],
float xy[2]);
@@ -410,7 +410,7 @@ int gpencil_delete_selected_point_wrap(bContext *C);
* \param gps: Stroke data
* \param subdivide: Number of times to subdivide
*/
-void gpencil_subdivide_stroke(bGPdata *gpd, bGPDstroke *gps, const int subdivide);
+void gpencil_subdivide_stroke(bGPdata *gpd, bGPDstroke *gps, int subdivide);
/* Layers Enums -------------------------------------- */
diff --git a/source/blender/editors/gpencil/gpencil_mesh.c b/source/blender/editors/gpencil/gpencil_mesh.c
index 11e02b9832f..efe29e852f2 100644
--- a/source/blender/editors/gpencil/gpencil_mesh.c
+++ b/source/blender/editors/gpencil/gpencil_mesh.c
@@ -142,6 +142,9 @@ static bool gpencil_bake_ob_list(bContext *C, Depsgraph *depsgraph, Scene *scene
/* Add active object. In some files this could not be in selected array. */
Object *obact = CTX_data_active_object(C);
+ if (obact == NULL) {
+ return false;
+ }
if (obact->type == OB_MESH) {
elem = MEM_callocN(sizeof(GpBakeOb), __func__);
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index dabe2050b28..79dda480a0a 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -54,6 +54,7 @@
#include "BKE_deform.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
+#include "BKE_gpencil_curve.h"
#include "BKE_gpencil_geom.h"
#include "BKE_layer.h"
#include "BKE_main.h"
@@ -493,7 +494,7 @@ static void gpencil_brush_jitter(bGPdata *gpd, tGPspoint *pt, const float amplit
/* Mouse movement in ints -> floats. */
if (gpd->runtime.sbuffer_used > 1) {
tGPspoint *pt_prev = pt - 1;
- sub_v2_v2v2(mvec, &pt->x, &pt_prev->x);
+ sub_v2_v2v2(mvec, pt->m_xy, pt_prev->m_xy);
normalize_v2(mvec);
/* Rotate mvec by 90 degrees... */
float angle = angle_v2v2(mvec, axis);
@@ -502,7 +503,7 @@ static void gpencil_brush_jitter(bGPdata *gpd, tGPspoint *pt, const float amplit
mvec[1] *= sin(angle);
/* Scale by displacement amount, and apply. */
- madd_v2_v2fl(&pt->x, mvec, amplitude * 10.0f);
+ madd_v2_v2fl(pt->m_xy, mvec, amplitude * 10.0f);
}
}
@@ -520,8 +521,7 @@ static void gpencil_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const
/* Apply to first point (only if there are 2 points because before no data to do it ) */
if (gpd->runtime.sbuffer_used == 1) {
- mvec[0] = (mval[0] - (pt - 1)->x);
- mvec[1] = (mval[1] - (pt - 1)->y);
+ sub_v2_v2v2(mvec, mval, (pt - 1)->m_xy);
normalize_v2(mvec);
/* uses > 1.0f to get a smooth transition in first point */
@@ -533,8 +533,7 @@ static void gpencil_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const
/* apply from second point */
if (gpd->runtime.sbuffer_used >= 1) {
- mvec[0] = (mval[0] - (pt - 1)->x);
- mvec[1] = (mval[1] - (pt - 1)->y);
+ sub_v2_v2v2(mvec, mval, (pt - 1)->m_xy);
normalize_v2(mvec);
fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */
@@ -581,25 +580,25 @@ static void gpencil_smooth_buffer(tGPsdata *p, float inf, int idx)
/* Compute smoothed coordinate by taking the ones nearby */
if (pta) {
- copy_v2_v2(a, &pta->x);
+ copy_v2_v2(a, pta->m_xy);
madd_v2_v2fl(sco, a, average_fac);
pressure += pta->pressure * average_fac;
strength += pta->strength * average_fac;
}
if (ptb) {
- copy_v2_v2(b, &ptb->x);
+ copy_v2_v2(b, ptb->m_xy);
madd_v2_v2fl(sco, b, average_fac);
pressure += ptb->pressure * average_fac;
strength += ptb->strength * average_fac;
}
if (ptc) {
- copy_v2_v2(c, &ptc->x);
+ copy_v2_v2(c, ptc->m_xy);
madd_v2_v2fl(sco, c, average_fac);
pressure += ptc->pressure * average_fac;
strength += ptc->strength * average_fac;
}
if (ptd) {
- copy_v2_v2(d, &ptd->x);
+ copy_v2_v2(d, ptd->m_xy);
madd_v2_v2fl(sco, d, average_fac);
pressure += ptd->pressure * average_fac;
strength += ptd->strength * average_fac;
@@ -609,7 +608,7 @@ static void gpencil_smooth_buffer(tGPsdata *p, float inf, int idx)
* for Guide mode. */
if (!guide->use_guide) {
interp_v2_v2v2(c, c, sco, inf);
- copy_v2_v2(&ptc->x, c);
+ copy_v2_v2(ptc->m_xy, c);
}
/* Interpolate pressure. */
ptc->pressure = interpf(ptc->pressure, pressure, inf);
@@ -646,37 +645,37 @@ static void gpencil_smooth_segment(bGPdata *gpd, const float inf, int from_idx,
/* Compute smoothed coordinate by taking the ones nearby */
if (pta) {
- madd_v2_v2fl(sco, &pta->x, average_fac);
+ madd_v2_v2fl(sco, pta->m_xy, average_fac);
pressure += pta->pressure * average_fac;
strength += pta->strength * average_fac;
}
else {
- madd_v2_v2fl(sco, &ptc->x, average_fac);
+ madd_v2_v2fl(sco, ptc->m_xy, average_fac);
pressure += ptc->pressure * average_fac;
strength += ptc->strength * average_fac;
}
if (ptb) {
- madd_v2_v2fl(sco, &ptb->x, average_fac);
+ madd_v2_v2fl(sco, ptb->m_xy, average_fac);
pressure += ptb->pressure * average_fac;
strength += ptb->strength * average_fac;
}
else {
- madd_v2_v2fl(sco, &ptc->x, average_fac);
+ madd_v2_v2fl(sco, ptc->m_xy, average_fac);
pressure += ptc->pressure * average_fac;
strength += ptc->strength * average_fac;
}
- madd_v2_v2fl(sco, &ptc->x, average_fac);
+ madd_v2_v2fl(sco, ptc->m_xy, average_fac);
pressure += ptc->pressure * average_fac;
strength += ptc->strength * average_fac;
- madd_v2_v2fl(sco, &ptd->x, average_fac);
+ madd_v2_v2fl(sco, ptd->m_xy, average_fac);
pressure += ptd->pressure * average_fac;
strength += ptd->strength * average_fac;
/* Based on influence factor, blend between original and optimal smoothed coordinate. */
- interp_v2_v2v2(&ptc->x, &ptc->x, sco, inf);
+ interp_v2_v2v2(ptc->m_xy, ptc->m_xy, sco, inf);
/* Interpolate pressure. */
ptc->pressure = interpf(ptc->pressure, pressure, inf);
@@ -738,7 +737,8 @@ static void gpencil_apply_randomness(tGPsdata *p,
/* Apply randomness to uv texture rotation. */
if ((brush_settings->uv_random > 0.0f) && (uv)) {
if ((brush_settings->flag2 & GP_BRUSH_USE_UV_AT_STROKE) == 0) {
- float rand = BLI_hash_int_01(BLI_hash_int_2d((int)pt->x, gpd->runtime.sbuffer_used)) * 2.0f -
+ float rand = BLI_hash_int_01(BLI_hash_int_2d((int)pt->m_xy[0], gpd->runtime.sbuffer_used)) *
+ 2.0f -
1.0f;
value = rand * M_PI_2 * brush_settings->uv_random;
}
@@ -778,7 +778,7 @@ static short gpencil_stroke_addpoint(tGPsdata *p,
pt = (tGPspoint *)(gpd->runtime.sbuffer);
/* store settings */
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
/* T44932 - Pressure vals are unreliable, so ignore for now */
pt->pressure = 1.0f;
pt->strength = 1.0f;
@@ -794,7 +794,7 @@ static short gpencil_stroke_addpoint(tGPsdata *p,
pt = ((tGPspoint *)(gpd->runtime.sbuffer) + 1);
/* store settings */
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
/* T44932 - Pressure vals are unreliable, so ignore for now */
pt->pressure = 1.0f;
pt->strength = 1.0f;
@@ -825,7 +825,7 @@ static short gpencil_stroke_addpoint(tGPsdata *p,
pt->strength = brush_settings->draw_strength;
pt->pressure = 1.0f;
pt->uv_rot = 0.0f;
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
/* pressure */
if (brush_settings->flag & GP_BRUSH_USE_PRESSURE) {
@@ -835,7 +835,7 @@ static short gpencil_stroke_addpoint(tGPsdata *p,
/* color strength */
if (brush_settings->flag & GP_BRUSH_USE_STRENGTH_PRESSURE) {
pt->strength *= BKE_curvemapping_evaluateF(brush_settings->curve_strength, 0, pressure);
- CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ CLAMP(pt->strength, MIN2(GPENCIL_STRENGTH_MIN, brush_settings->draw_strength), 1.0f);
}
/* Set vertex colors for buffer. */
@@ -919,6 +919,19 @@ static short gpencil_stroke_addpoint(tGPsdata *p,
return GP_STROKEADD_INVALID;
}
+static void gpencil_stroke_unselect(bGPdata *gpd, bGPDstroke *gps)
+{
+ gps->flag &= ~GP_STROKE_SELECT;
+ BKE_gpencil_stroke_select_index_reset(gps);
+ for (int i = 0; i < gps->totpoints; i++) {
+ gps->points[i].flag &= ~GP_SPOINT_SELECT;
+ }
+ /* Update the selection from the stroke to the curve. */
+ if (gps->editcurve) {
+ BKE_gpencil_editcurve_stroke_sync_selection(gpd, gps, gps->editcurve);
+ }
+}
+
/* make a new stroke from the buffer data */
static void gpencil_stroke_newfrombuffer(tGPsdata *p)
{
@@ -929,6 +942,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
tGPspoint *ptc;
MDeformVert *dvert = NULL;
Brush *brush = p->brush;
+ BrushGpencilSettings *brush_settings = brush->gpencil_settings;
ToolSettings *ts = p->scene->toolsettings;
Depsgraph *depsgraph = p->depsgraph;
Object *obact = (Object *)p->ownerPtr.data;
@@ -1013,11 +1027,11 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
ptc = gpd->runtime.sbuffer;
/* convert screen-coordinates to appropriate coordinates (and store them) */
- gpencil_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ gpencil_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
/* copy pressure and time */
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
- CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ CLAMP(pt->strength, MIN2(GPENCIL_STRENGTH_MIN, brush_settings->draw_strength), 1.0f);
copy_v4_v4(pt->vert_color, ptc->vert_color);
pt->time = ptc->time;
/* Apply the vertex color to point. */
@@ -1047,11 +1061,11 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
ptc = ((tGPspoint *)gpd->runtime.sbuffer) + (gpd->runtime.sbuffer_used - 1);
/* convert screen-coordinates to appropriate coordinates (and store them) */
- gpencil_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ gpencil_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
/* copy pressure and time */
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
- CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ CLAMP(pt->strength, MIN2(GPENCIL_STRENGTH_MIN, brush_settings->draw_strength), 1.0f);
pt->time = ptc->time;
/* Apply the vertex color to point. */
ED_gpencil_point_vertex_color_set(ts, brush, pt, ptc);
@@ -1100,7 +1114,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
int i;
for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used; i++, ptc++, pt++) {
- round_v2i_v2fl(mval_i, &ptc->x);
+ round_v2i_v2fl(mval_i, ptc->m_xy);
if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, depth_arr + i) == 0) &&
(i && (ED_view3d_depth_read_cached_seg(
@@ -1171,12 +1185,12 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used && ptc;
i++, ptc++, pt++) {
/* convert screen-coordinates to appropriate coordinates (and store them) */
- gpencil_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL);
+ gpencil_stroke_convertcoords(p, ptc->m_xy, &pt->x, depth_arr ? depth_arr + i : NULL);
/* copy pressure and time */
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
- CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ CLAMP(pt->strength, MIN2(GPENCIL_STRENGTH_MIN, brush_settings->draw_strength), 1.0f);
copy_v4_v4(pt->vert_color, ptc->vert_color);
pt->time = ptc->time;
pt->uv_fac = ptc->uv_fac;
@@ -1283,7 +1297,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
/* Join with existing strokes. */
if (ts->gpencil_flags & GP_TOOL_FLAG_AUTOMERGE_STROKE) {
- if (gps->prev != NULL) {
+ if ((gps->prev != NULL) || (gps->next != NULL)) {
BKE_gpencil_stroke_boundingbox_calc(gps);
float diff_mat[4][4], ctrl1[2], ctrl2[2];
BKE_gpencil_layer_transform_matrix_get(depsgraph, p->ob, gpl, diff_mat);
@@ -1301,7 +1315,12 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
ctrl2,
GPENCIL_MINIMUM_JOIN_DIST,
&pt_index);
+
if (gps_target != NULL) {
+ /* Unselect all points of source and destination strokes. This is required to avoid
+ * a change in the resolution of the original strokes during the join. */
+ gpencil_stroke_unselect(gpd, gps);
+ gpencil_stroke_unselect(gpd, gps_target);
gps = ED_gpencil_stroke_join_and_trim(p->gpd, p->gpf, gps, gps_target, pt_index);
}
else {
@@ -1487,7 +1506,7 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p,
bGPDspoint pt_temp;
gpencil_point_to_parent_space(gps->points, p->diff_mat, &pt_temp);
gpencil_point_to_xy(&p->gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
- /* do boundbox check first */
+ /* Do bound-box check first. */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
if (len_v2v2_int(mval_i, pc1) <= radius) {
@@ -1512,7 +1531,7 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p,
gpencil_point_to_parent_space(pt1, p->diff_mat, &npt);
gpencil_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]);
- /* do boundbox check first */
+ /* Do bound-box check first. */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
if (len_v2v2_int(mval_i, pc1) <= radius) {
@@ -1567,6 +1586,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,13 +1601,7 @@ 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 */
+ /* Check that point segment of the bound-box 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])) ||
((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
@@ -2798,14 +2817,14 @@ static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgra
pt = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_used - 1;
if (p->paintmode != GP_PAINTMODE_ERASER) {
- ED_gpencil_toggle_brush_cursor(C, true, &pt->x);
+ ED_gpencil_toggle_brush_cursor(C, true, pt->m_xy);
}
}
else if ((p->brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) &&
(gpd->runtime.sbuffer_used > 0)) {
pt = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_used - 1;
if (p->paintmode != GP_PAINTMODE_ERASER) {
- ED_gpencil_toggle_brush_cursor(C, true, &pt->x);
+ ED_gpencil_toggle_brush_cursor(C, true, pt->m_xy);
}
}
}
@@ -3303,8 +3322,7 @@ static void gpencil_brush_angle_segment(tGPsdata *p, tGPspoint *pt_prev, tGPspoi
/* angle vector of the brush with full thickness */
const float v0[2] = {cos(angle), sin(angle)};
- mvec[0] = pt->x - pt_prev->x;
- mvec[1] = pt->y - pt_prev->y;
+ sub_v2_v2v2(mvec, pt->m_xy, pt_prev->m_xy);
normalize_v2(mvec);
fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */
/* interpolate with previous point for smoother transitions */
@@ -3355,11 +3373,11 @@ static void gpencil_add_arc_points(tGPsdata *p, const float mval[2], int segment
* for arc curve.
*/
float v_prev[2], v_cur[2], v_half[2];
- sub_v2_v2v2(v_cur, mval, &pt_prev->x);
+ sub_v2_v2v2(v_cur, mval, pt_prev->m_xy);
- sub_v2_v2v2(v_prev, &pt_prev->x, &pt_before->x);
- interp_v2_v2v2(v_half, &pt_prev->x, mval, 0.5f);
- sub_v2_v2(v_half, &pt_prev->x);
+ sub_v2_v2v2(v_prev, pt_prev->m_xy, pt_before->m_xy);
+ interp_v2_v2v2(v_half, pt_prev->m_xy, mval, 0.5f);
+ sub_v2_v2(v_half, pt_prev->m_xy);
/* If angle is too sharp undo all changes and return. */
const float min_angle = DEG2RADF(120.0f);
@@ -3378,14 +3396,14 @@ static void gpencil_add_arc_points(tGPsdata *p, const float mval[2], int segment
/* Calc the position of the control point. */
float ctl[2];
- add_v2_v2v2(ctl, &pt_prev->x, v_prev);
+ add_v2_v2v2(ctl, pt_prev->m_xy, v_prev);
float step = M_PI_2 / (float)(segments + 1);
float a = step;
float midpoint[2], start[2], end[2], cp1[2], corner[2];
- mid_v2_v2v2(midpoint, &pt_prev->x, mval);
- copy_v2_v2(start, &pt_prev->x);
+ mid_v2_v2v2(midpoint, pt_prev->m_xy, mval);
+ copy_v2_v2(start, pt_prev->m_xy);
copy_v2_v2(end, mval);
copy_v2_v2(cp1, ctl);
@@ -3396,8 +3414,8 @@ static void gpencil_add_arc_points(tGPsdata *p, const float mval[2], int segment
tGPspoint *pt_step = pt_prev;
for (int i = 0; i < segments; i++) {
pt = &points[idx_prev + i - 1];
- pt->x = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a);
- pt->y = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a);
+ pt->m_xy[0] = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a);
+ pt->m_xy[1] = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a);
/* Set pressure and strength equals to previous. It will be smoothed later. */
pt->pressure = pt_prev->pressure;
@@ -3460,8 +3478,8 @@ static void gpencil_add_guide_points(const tGPsdata *p,
for (int i = 0; i < segments; i++) {
pt = &points[idx_prev + i - 1];
- gpencil_rotate_v2_v2v2fl(&pt->x, start, p->guide.origin, -a);
- gpencil_snap_to_guide(p, guide, &pt->x);
+ gpencil_rotate_v2_v2v2fl(pt->m_xy, start, p->guide.origin, -a);
+ gpencil_snap_to_guide(p, guide, pt->m_xy);
a += step;
/* Set pressure and strength equals to previous. It will be smoothed later. */
@@ -3477,8 +3495,8 @@ static void gpencil_add_guide_points(const tGPsdata *p,
for (int i = 0; i < segments; i++) {
pt = &points[idx_prev + i - 1];
- interp_v2_v2v2(&pt->x, start, end, a);
- gpencil_snap_to_guide(p, guide, &pt->x);
+ interp_v2_v2v2(pt->m_xy, start, end, a);
+ gpencil_snap_to_guide(p, guide, pt->m_xy);
a += step;
/* Set pressure and strength equals to previous. It will be smoothed later. */
@@ -3681,8 +3699,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
*/
if ((p->region) && (p->region->regiontype == RGN_TYPE_TOOLS)) {
/* Change to whatever region is now under the mouse */
- ARegion *current_region = BKE_area_find_region_xy(
- p->area, RGN_TYPE_ANY, event->xy[0], event->xy[1]);
+ ARegion *current_region = BKE_area_find_region_xy(p->area, RGN_TYPE_ANY, event->xy);
if (current_region) {
/* Assume that since we found the cursor in here, it is in bounds
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index 8157e9d8fe7..2715491414a 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -423,6 +423,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi
Scene *scene = tgpi->scene;
char status_str[UI_MAX_DRAW_STR];
char msg_str[UI_MAX_DRAW_STR];
+ const int cur_subdiv = tgpi->type == GP_STROKE_BOX ? tgpi->tot_edges - 1 : tgpi->tot_edges - 2;
if (tgpi->type == GP_STROKE_LINE) {
BLI_strncpy(msg_str,
@@ -480,7 +481,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi
sizeof(status_str),
"%s: %d (%d, %d) (%d, %d)",
msg_str,
- tgpi->tot_edges,
+ cur_subdiv,
(int)tgpi->start[0],
(int)tgpi->start[1],
(int)tgpi->end[0],
@@ -491,7 +492,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi
sizeof(status_str),
"%s: %d (%d, %d)",
msg_str,
- tgpi->tot_edges,
+ cur_subdiv,
(int)tgpi->end[0],
(int)tgpi->end[1]);
}
@@ -503,7 +504,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi
sizeof(status_str),
"%s: %d (%d, %d) (%d, %d)",
msg_str,
- tgpi->tot_edges,
+ cur_subdiv,
(int)tgpi->start[0],
(int)tgpi->start[1],
(int)tgpi->end[0],
@@ -540,7 +541,7 @@ static void gpencil_primitive_rectangle(tGPDprimitive *tgpi, tGPspoint *points2D
if (tgpi->tot_edges == 1) {
for (int j = 0; j < 4; j++) {
tGPspoint *p2d = &points2D[j];
- copy_v2_v2(&p2d->x, coords[j]);
+ copy_v2_v2(p2d->m_xy, coords[j]);
}
}
else {
@@ -550,7 +551,7 @@ static void gpencil_primitive_rectangle(tGPDprimitive *tgpi, tGPspoint *points2D
float a = 0.0f;
for (int k = 0; k < tgpi->tot_edges; k++) {
tGPspoint *p2d = &points2D[i];
- interp_v2_v2v2(&p2d->x, coords[j], coords[j + 1], a);
+ interp_v2_v2v2(p2d->m_xy, coords[j], coords[j + 1], a);
a += step;
i++;
}
@@ -581,7 +582,7 @@ static void gpencil_primitive_line(tGPDprimitive *tgpi, tGPspoint *points2D, boo
for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
tGPspoint *p2d = &points2D[i];
- interp_v2_v2v2(&p2d->x, tgpi->start, tgpi->end, a);
+ interp_v2_v2v2(p2d->m_xy, tgpi->start, tgpi->end, a);
a += step;
}
@@ -627,8 +628,8 @@ static void gpencil_primitive_arc(tGPDprimitive *tgpi, tGPspoint *points2D)
for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
tGPspoint *p2d = &points2D[i];
- p2d->x = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a);
- p2d->y = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a);
+ p2d->m_xy[0] = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a);
+ p2d->m_xy[1] = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a);
a += step;
}
float color[4];
@@ -663,7 +664,7 @@ static void gpencil_primitive_bezier(tGPDprimitive *tgpi, tGPspoint *points2D)
for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
tGPspoint *p2d = &points2D[i];
- interp_v2_v2v2v2v2_cubic(&p2d->x, bcp1, bcp2, bcp3, bcp4, a);
+ interp_v2_v2v2v2v2_cubic(p2d->m_xy, bcp1, bcp2, bcp3, bcp4, a);
a += step;
}
float color[4];
@@ -697,8 +698,8 @@ static void gpencil_primitive_circle(tGPDprimitive *tgpi, tGPspoint *points2D)
for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
tGPspoint *p2d = &points2D[i];
- p2d->x = (center[0] + cosf(a) * radius[0]);
- p2d->y = (center[1] + sinf(a) * radius[1]);
+ p2d->m_xy[0] = (center[0] + cosf(a) * radius[0]);
+ p2d->m_xy[1] = (center[1] + sinf(a) * radius[1]);
a += step;
}
float color[4];
@@ -726,7 +727,6 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
const bool is_camera = is_lock_axis_view && (tgpi->rv3d->persp == RV3D_CAMOB) && (!is_depth);
if (tgpi->type == GP_STROKE_BOX) {
- tgpi->tot_edges--;
gps->totpoints = (tgpi->tot_edges * 4 + tgpi->tot_stored_edges);
}
else {
@@ -801,7 +801,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
const ViewDepths *depths = tgpi->depths;
tGPspoint *ptc = &points2D[0];
for (int i = 0; i < gps->totpoints; i++, ptc++) {
- round_v2i_v2fl(mval_i, &ptc->x);
+ round_v2i_v2fl(mval_i, ptc->m_xy);
if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, depth_arr + i) == 0) &&
(i && (ED_view3d_depth_read_cached_seg(
depths, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) {
@@ -894,7 +894,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
/* Store original points */
float tmp_xyp[2];
- copy_v2_v2(tmp_xyp, &p2d->x);
+ copy_v2_v2(tmp_xyp, p2d->m_xy);
/* calc pressure */
float curve_pressure = 1.0;
@@ -926,8 +926,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
/* vector */
float mvec[2], svec[2];
if (i > 0) {
- mvec[0] = (p2d->x - (p2d - 1)->x);
- mvec[1] = (p2d->y - (p2d - 1)->y);
+ sub_v2_v2v2(mvec, p2d->m_xy, (p2d - 1)->m_xy);
normalize_v2(mvec);
}
else {
@@ -942,7 +941,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
else {
mul_v2_fl(svec, fac);
}
- add_v2_v2(&p2d->x, svec);
+ add_v2_v2(p2d->m_xy, svec);
}
/* color strength */
@@ -992,7 +991,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
}
}
- copy_v2_v2(&tpt->x, &p2d->x);
+ copy_v2_v2(tpt->m_xy, p2d->m_xy);
tpt->pressure = pressure;
tpt->strength = strength;
@@ -1064,7 +1063,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
}
/* Restore original points */
- copy_v2_v2(&p2d->x, tmp_xyp);
+ copy_v2_v2(p2d->m_xy, tmp_xyp);
}
/* store cps and convert coords */
@@ -1254,7 +1253,7 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op)
tgpi->tot_stored_edges = 0;
tgpi->subdiv = RNA_int_get(op->ptr, "subdivision");
- RNA_int_set(op->ptr, "edges", tgpi->subdiv + 2);
+ RNA_int_set(op->ptr, "edges", tgpi->type == GP_STROKE_BOX ? tgpi->subdiv + 1 : tgpi->subdiv + 2);
tgpi->tot_edges = RNA_int_get(op->ptr, "edges");
tgpi->flag = IDLE;
tgpi->lock_axis = ts->gp_sculpt.lock_axis;
@@ -1617,7 +1616,7 @@ static void gpencil_primitive_move(tGPDprimitive *tgpi, bool reset)
for (int i = 0; i < gps->totpoints; i++) {
tGPspoint *p2d = &points2D[i];
- add_v2_v2(&p2d->x, move);
+ add_v2_v2(p2d->m_xy, move);
}
add_v2_v2(tgpi->start, move);
@@ -1720,7 +1719,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
case WHEELUPMOUSE: {
if ((event->val != KM_RELEASE)) {
tgpi->tot_edges = tgpi->tot_edges + 1;
- CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES);
RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
gpencil_primitive_update(C, op, tgpi);
}
@@ -1730,7 +1729,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
case WHEELDOWNMOUSE: {
if ((event->val != KM_RELEASE)) {
tgpi->tot_edges = tgpi->tot_edges - 1;
- CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES);
RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
gpencil_primitive_update(C, op, tgpi);
}
@@ -1886,7 +1885,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
case WHEELUPMOUSE: {
if ((event->val != KM_RELEASE)) {
tgpi->tot_edges = tgpi->tot_edges + 1;
- CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES);
RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
/* update screen */
@@ -1898,7 +1897,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
case WHEELDOWNMOUSE: {
if ((event->val != KM_RELEASE)) {
tgpi->tot_edges = tgpi->tot_edges - 1;
- CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES);
RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
/* update screen */
@@ -2038,15 +2037,8 @@ static void gpencil_primitive_common_props(wmOperatorType *ot, int subdiv, int t
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
/* Internal prop. */
- prop = RNA_def_int(ot->srna,
- "edges",
- MIN_EDGES,
- MIN_EDGES,
- MAX_EDGES,
- "Edges",
- "Number of points by edge",
- MIN_EDGES,
- MAX_EDGES);
+ prop = RNA_def_int(
+ ot->srna, "edges", 1, 1, MAX_EDGES, "Edges", "Number of points by edge", 1, MAX_EDGES);
RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
RNA_def_enum(ot->srna, "type", gpencil_primitive_type, type, "Type", "Type of shape");
diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
index 186c45c9f39..50c7202599a 100644
--- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c
+++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
@@ -1454,7 +1454,7 @@ static bool gpencil_sculpt_brush_do_stroke(tGP_BrushEditData *gso,
gpencil_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
- /* do boundbox check first */
+ /* Do bound-box check first. */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
int mval_i[2];
@@ -1492,7 +1492,7 @@ static bool gpencil_sculpt_brush_do_stroke(tGP_BrushEditData *gso,
gpencil_point_to_parent_space(pt2, diff_mat, &npt);
gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
- /* Check that point segment of the boundbox of the selection stroke */
+ /* Check that point segment of the bound-box of the selection stroke. */
if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
/* Check if point segment of stroke had anything to do with
diff --git a/source/blender/editors/gpencil/gpencil_trace.h b/source/blender/editors/gpencil/gpencil_trace.h
index 7c62288f65d..77fb823b3b6 100644
--- a/source/blender/editors/gpencil/gpencil_trace.h
+++ b/source/blender/editors/gpencil/gpencil_trace.h
@@ -91,7 +91,7 @@ void ED_gpencil_trace_bitmap_invert(const potrace_bitmap_t *bm);
*/
void ED_gpencil_trace_image_to_bitmap(struct ImBuf *ibuf,
const potrace_bitmap_t *bm,
- const float threshold);
+ float threshold);
/**
* Convert Potrace Bitmap to Grease Pencil strokes
@@ -106,7 +106,7 @@ void ED_gpencil_trace_data_to_strokes(struct Main *bmain,
struct Object *ob,
struct bGPDframe *gpf,
int32_t offset[2],
- const float scale,
- const float sample,
- const int32_t resolution,
- const int32_t thickness);
+ float scale,
+ float sample,
+ int32_t resolution,
+ int32_t thickness);
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index f082af979a1..81a844cf6e1 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -870,7 +870,7 @@ void gpencil_stroke_convertcoords_tpoint(Scene *scene,
}
int mval_i[2];
- round_v2i_v2fl(mval_i, &point2D->x);
+ round_v2i_v2fl(mval_i, point2D->m_xy);
if ((depth != NULL) && (ED_view3d_autodist_simple(region, mval_i, r_out, 0, depth))) {
/* projecting onto 3D-Geometry
@@ -878,7 +878,7 @@ void gpencil_stroke_convertcoords_tpoint(Scene *scene,
*/
}
else {
- float mval_f[2] = {point2D->x, point2D->y};
+ float mval_f[2] = {UNPACK2(point2D->m_xy)};
float mval_prj[2];
float rvec[3], dvec[3];
float zfac;
@@ -2020,7 +2020,7 @@ static void gpencil_stroke_convertcoords(ARegion *region,
const float origin[3],
float out[3])
{
- float mval_f[2] = {(float)point2D->x, (float)point2D->y};
+ float mval_f[2] = {UNPACK2(point2D->m_xy)};
float mval_prj[2];
float rvec[3], dvec[3];
float zfac;
@@ -2808,8 +2808,8 @@ static void gpencil_sbuffer_vertex_color_random(
if (brush_settings->flag & GP_BRUSH_GROUP_RANDOM) {
int seed = ((uint)(ceil(PIL_check_seconds_timer())) + 1) % 128;
- int ix = (int)(tpt->x * seed);
- int iy = (int)(tpt->y * seed);
+ int ix = (int)(tpt->m_xy[0] * seed);
+ int iy = (int)(tpt->m_xy[1] * seed);
int iz = ix + iy * seed;
float hsv[3];
float factor_value[3];
diff --git a/source/blender/editors/gpencil/gpencil_vertex_paint.c b/source/blender/editors/gpencil/gpencil_vertex_paint.c
index 633e371cbd1..05304f9914f 100644
--- a/source/blender/editors/gpencil/gpencil_vertex_paint.c
+++ b/source/blender/editors/gpencil/gpencil_vertex_paint.c
@@ -441,12 +441,12 @@ static bool brush_tint_apply(tGP_BrushVertexpaintData *gso,
CLAMP_MIN(pt->vert_color[3], 0.0f);
}
else {
- /* Premult. */
+ /* Pre-multiply. */
mul_v3_fl(pt->vert_color, pt->vert_color[3]);
/* "Alpha over" blending. */
interp_v3_v3v3(pt->vert_color, pt->vert_color, gso->linear_color, inf);
pt->vert_color[3] = pt->vert_color[3] * (1.0 - inf) + inf;
- /* Un-premult. */
+ /* Un pre-multiply. */
if (pt->vert_color[3] > 0.0f) {
mul_v3_fl(pt->vert_color, 1.0f / pt->vert_color[3]);
}
@@ -460,12 +460,12 @@ static bool brush_tint_apply(tGP_BrushVertexpaintData *gso,
CLAMP_MIN(gps->vert_color_fill[3], 0.0f);
}
else {
- /* Premult. */
+ /* Pre-multiply. */
mul_v3_fl(gps->vert_color_fill, gps->vert_color_fill[3]);
/* "Alpha over" blending. */
interp_v3_v3v3(gps->vert_color_fill, gps->vert_color_fill, gso->linear_color, inf_fill);
gps->vert_color_fill[3] = gps->vert_color_fill[3] * (1.0 - inf_fill) + inf_fill;
- /* Un-premult. */
+ /* Un pre-multiply. */
if (gps->vert_color_fill[3] > 0.0f) {
mul_v3_fl(gps->vert_color_fill, 1.0f / gps->vert_color_fill[3]);
}
@@ -865,7 +865,7 @@ static bool gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso,
gpencil_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
- /* do boundbox check first */
+ /* Do bound-box check first. */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
int mval_i[2];
@@ -905,7 +905,7 @@ static bool gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso,
gpencil_point_to_parent_space(pt2, diff_mat, &npt);
gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
- /* Check that point segment of the boundbox of the selection stroke */
+ /* Check that point segment of the bound-box of the selection stroke. */
if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
/* Check if point segment of stroke had anything to do with
diff --git a/source/blender/editors/gpencil/gpencil_weight_paint.c b/source/blender/editors/gpencil/gpencil_weight_paint.c
index b3249294119..15f99d83f6d 100644
--- a/source/blender/editors/gpencil/gpencil_weight_paint.c
+++ b/source/blender/editors/gpencil/gpencil_weight_paint.c
@@ -432,7 +432,7 @@ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso,
gpencil_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
- /* do boundbox check first */
+ /* Do bound-box check first. */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
int mval_i[2];
@@ -461,7 +461,7 @@ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso,
gpencil_point_to_parent_space(pt2, diff_mat, &npt);
gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
- /* Check that point segment of the boundbox of the selection stroke */
+ /* Check that point segment of the bound-box of the selection stroke */
if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
/* Check if point segment of stroke had anything to do with
diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h
index 8f2a189e35e..61dd0adc84d 100644
--- a/source/blender/editors/include/BIF_glutil.h
+++ b/source/blender/editors/include/BIF_glutil.h
@@ -55,6 +55,36 @@ typedef struct IMMDrawPixelsTexState {
IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin);
/**
+ * Unlike the `immDrawPixelsTexTiled` functions, this doesn't do tiled drawing, but draws into a
+ * full texture.
+ *
+ * Use the currently bound shader.
+ *
+ * Use #immDrawPixelsTexSetup to bind the shader you want before calling #immDrawPixelsTex.
+ *
+ * If using a special shader double check it uses the same attributes "pos" "texCoord" and uniform
+ * "image".
+ *
+ * If color is NULL then use white by default
+ *
+ * Unless <em>state->do_shader_unbind<em> is explicitly set to `false`, the shader is unbound when
+ * finished.
+ */
+void immDrawPixelsTexScaledFullSize(const IMMDrawPixelsTexState *state,
+ const float x,
+ const float y,
+ const int img_w,
+ const int img_h,
+ const eGPUTextureFormat gpu_format,
+ const bool use_filter,
+ const void *rect,
+ const float scaleX,
+ const float scaleY,
+ const float xzoom,
+ const float yzoom,
+ const float color[4]);
+
+/**
* #immDrawPixelsTex - Functions like a limited #glDrawPixels, but actually draws the
* image using textures, which can be tremendously faster on low-end
* cards, and also avoids problems with the raster position being
@@ -68,45 +98,45 @@ IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin);
* model-view and projection matrices are assumed to define a
* 1-to-1 mapping to screen space.
*/
-void immDrawPixelsTex(IMMDrawPixelsTexState *state,
- float x,
- float y,
- int img_w,
- int img_h,
- eGPUTextureFormat gpu_format,
- bool use_filter,
- void *rect,
- float xzoom,
- float yzoom,
- const float color[4]);
-void immDrawPixelsTex_clipping(IMMDrawPixelsTexState *state,
- float x,
- float y,
- int img_w,
- int img_h,
- eGPUTextureFormat gpu_format,
- bool use_filter,
- void *rect,
- float clip_min_x,
- float clip_min_y,
- float clip_max_x,
- float clip_max_y,
- float xzoom,
- float yzoom,
- const float color[4]);
-void immDrawPixelsTexScaled(IMMDrawPixelsTexState *state,
- float x,
- float y,
- int img_w,
- int img_h,
- eGPUTextureFormat gpu_format,
- bool use_filter,
- void *rect,
- float scaleX,
- float scaleY,
- float xzoom,
- float yzoom,
- const float color[4]);
+void immDrawPixelsTexTiled(IMMDrawPixelsTexState *state,
+ float x,
+ float y,
+ int img_w,
+ int img_h,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
+ void *rect,
+ float xzoom,
+ float yzoom,
+ const float color[4]);
+void immDrawPixelsTexTiled_clipping(IMMDrawPixelsTexState *state,
+ float x,
+ float y,
+ int img_w,
+ int img_h,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
+ void *rect,
+ float clip_min_x,
+ float clip_min_y,
+ float clip_max_x,
+ float clip_max_y,
+ float xzoom,
+ float yzoom,
+ const float color[4]);
+void immDrawPixelsTexTiled_scaling(IMMDrawPixelsTexState *state,
+ float x,
+ float y,
+ int img_w,
+ int img_h,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
+ void *rect,
+ float scaleX,
+ float scaleY,
+ float xzoom,
+ float yzoom,
+ const float color[4]);
/**
* Use the currently bound shader.
*
@@ -118,26 +148,26 @@ void immDrawPixelsTexScaled(IMMDrawPixelsTexState *state,
*
* If color is NULL then use white by default
*
- * Be also aware that this function unbinds the shader when
- * it's finished.
+ * Unless <em>state->do_shader_unbind<em> is explicitly set to `false`, the shader is unbound when
+ * finished.
*/
-void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
- float x,
- float y,
- int img_w,
- int img_h,
- eGPUTextureFormat gpu_format,
- bool use_filter,
- void *rect,
- float scaleX,
- float scaleY,
- float clip_min_x,
- float clip_min_y,
- float clip_max_x,
- float clip_max_y,
- float xzoom,
- float yzoom,
- const float color[4]);
+void immDrawPixelsTexTiled_scaling_clipping(IMMDrawPixelsTexState *state,
+ float x,
+ float y,
+ int img_w,
+ int img_h,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
+ void *rect,
+ float scaleX,
+ float scaleY,
+ float clip_min_x,
+ float clip_min_y,
+ float clip_max_x,
+ float clip_max_y,
+ float xzoom,
+ float yzoom,
+ const float color[4]);
/* Image buffer drawing functions, with display transform
*
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 0053bf5c865..7631bd35e79 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -94,7 +94,7 @@ struct EditBone *ED_armature_ebone_add_primitive(struct Object *obedit_arm,
*/
float ED_armature_ebone_roll_to_vector(const struct EditBone *bone,
const float align_axis[3],
- const bool axis_only);
+ bool axis_only);
/**
* \param centermode: 0 == do center, 1 == center new, 2 == center cursor.
*
@@ -105,8 +105,8 @@ void ED_armature_origin_set(
/**
* See #BKE_armature_transform for object-mode transform.
*/
-void ED_armature_edit_transform(struct bArmature *arm, const float mat[4][4], const bool do_props);
-void ED_armature_transform(struct bArmature *arm, const float mat[4][4], const bool do_props);
+void ED_armature_edit_transform(struct bArmature *arm, const float mat[4][4], bool do_props);
+void ED_armature_transform(struct bArmature *arm, const float mat[4][4], bool do_props);
/* armature_naming.c */
@@ -138,7 +138,7 @@ void ED_armature_bone_rename(struct Main *bmain,
void ED_armature_bones_flip_names(struct Main *bmain,
struct bArmature *arm,
struct ListBase *bones_names,
- const bool do_strip_numbers);
+ bool do_strip_numbers);
/* armature_ops.c */
@@ -203,7 +203,7 @@ bool ED_armature_edit_select_pick(
*
* \note Visibility checks must be done by the caller.
*/
-bool ED_armature_edit_select_op_from_tagged(struct bArmature *arm, const int sel_op);
+bool ED_armature_edit_select_op_from_tagged(struct bArmature *arm, int sel_op);
/* armature_skinning.c */
@@ -215,8 +215,8 @@ void ED_object_vgroup_calc_from_armature(struct ReportList *reports,
struct Scene *scene,
struct Object *ob,
struct Object *par,
- const int mode,
- const bool mirror);
+ int mode,
+ bool mirror);
/* editarmature_undo.c */
@@ -251,7 +251,7 @@ bool ED_armature_ebone_is_child_recursive(struct EditBone *ebone_parent,
* \return The shared parent or NULL.
*/
struct EditBone *ED_armature_ebone_find_shared_parent(struct EditBone *ebone_child[],
- const unsigned int ebone_child_tot);
+ unsigned int ebone_child_tot);
void ED_armature_ebone_to_mat3(struct EditBone *ebone, float r_mat[3][3]);
void ED_armature_ebone_to_mat4(struct EditBone *ebone, float r_mat[4][4]);
void ED_armature_ebone_from_mat3(struct EditBone *ebone, const float mat[3][3]);
@@ -282,10 +282,10 @@ void ED_armature_ebone_listbase_temp_clear(struct ListBase *lb);
/**
* Free's bones and their properties.
*/
-void ED_armature_ebone_listbase_free(struct ListBase *lb, const bool do_id_user);
+void ED_armature_ebone_listbase_free(struct ListBase *lb, bool do_id_user);
void ED_armature_ebone_listbase_copy(struct ListBase *lb_dst,
struct ListBase *lb_src,
- const bool do_id_user);
+ bool do_id_user);
int ED_armature_ebone_selectflag_get(const struct EditBone *ebone);
void ED_armature_ebone_selectflag_set(struct EditBone *ebone, int flag);
@@ -353,14 +353,14 @@ void ED_armature_pose_select_in_wpaint_mode(struct ViewLayer *view_layer,
bool ED_pose_deselect_all_multi_ex(struct Base **bases,
uint bases_len,
int select_mode,
- const bool ignore_visibility);
-bool ED_pose_deselect_all_multi(struct bContext *C, int select_mode, const bool ignore_visibility);
+ bool ignore_visibility);
+bool ED_pose_deselect_all_multi(struct bContext *C, int select_mode, bool ignore_visibility);
/**
* 'select_mode' is usual SEL_SELECT/SEL_DESELECT/SEL_TOGGLE/SEL_INVERT.
* When true, 'ignore_visibility' makes this func also affect invisible bones
* (hidden or on hidden layers).
*/
-bool ED_pose_deselect_all(struct Object *ob, int select_mode, const bool ignore_visibility);
+bool ED_pose_deselect_all(struct Object *ob, int select_mode, bool ignore_visibility);
void ED_pose_bone_select_tag_update(struct Object *ob);
/**
* Utility method for changing the selection status of a bone.
diff --git a/source/blender/editors/include/ED_buttons.h b/source/blender/editors/include/ED_buttons.h
index 79404aada41..c3479c10d58 100644
--- a/source/blender/editors/include/ED_buttons.h
+++ b/source/blender/editors/include/ED_buttons.h
@@ -36,7 +36,7 @@ struct bContext;
* \return The total number of items in the array returned.
*/
int ED_buttons_tabs_list(struct SpaceProperties *sbuts, short *context_tabs_array);
-bool ED_buttons_tab_has_search_result(struct SpaceProperties *sbuts, const int index);
+bool ED_buttons_tab_has_search_result(struct SpaceProperties *sbuts, int index);
void ED_buttons_search_string_set(struct SpaceProperties *sbuts, const char *value);
int ED_buttons_search_string_length(struct SpaceProperties *sbuts);
@@ -48,7 +48,7 @@ bool ED_buttons_should_sync_with_outliner(const struct bContext *C,
void ED_buttons_set_context(const struct bContext *C,
struct SpaceProperties *sbuts,
PointerRNA *ptr,
- const int context);
+ int context);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h
index 805d42b6fbc..a9225a5db60 100644
--- a/source/blender/editors/include/ED_curve.h
+++ b/source/blender/editors/include/ED_curve.h
@@ -100,7 +100,7 @@ void ED_curve_editfont_load(struct Object *obedit);
void ED_curve_editfont_make(struct Object *obedit);
void ED_curve_editfont_free(struct Object *obedit);
-void ED_text_to_object(struct bContext *C, const struct Text *text, const bool split_lines);
+void ED_text_to_object(struct bContext *C, const struct Text *text, bool split_lines);
void ED_curve_beztcpy(struct EditNurb *editnurb,
struct BezTriple *dst,
diff --git a/source/blender/editors/include/ED_file_indexer.h b/source/blender/editors/include/ED_file_indexer.h
index 0afa8819def..3b19a738b90 100644
--- a/source/blender/editors/include/ED_file_indexer.h
+++ b/source/blender/editors/include/ED_file_indexer.h
@@ -146,7 +146,7 @@ void ED_file_indexer_entries_clear(FileIndexerEntries *indexer_entries);
void ED_file_indexer_entries_extend_from_datablock_infos(
FileIndexerEntries *indexer_entries,
const LinkNode * /* BLODataBlockInfo */ datablock_infos,
- const int idcode);
+ int idcode);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index 460de58bdb2..0528057fb54 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -127,7 +127,7 @@ void ED_fileselect_set_params_from_userdef(struct SpaceFile *sfile);
*/
void ED_fileselect_params_to_userdef(struct SpaceFile *sfile,
const int temp_win_size[2],
- const bool is_maximized);
+ bool is_maximized);
void ED_fileselect_init_layout(struct SpaceFile *sfile, struct ARegion *region);
@@ -171,9 +171,7 @@ void ED_fileselect_activate_asset_catalog(const struct SpaceFile *sfile, bUUID c
* Activate and select the file that corresponds to the given ID.
* Pass deferred=true to wait for the next refresh before activating.
*/
-void ED_fileselect_activate_by_id(struct SpaceFile *sfile,
- struct ID *asset_id,
- const bool deferred);
+void ED_fileselect_activate_by_id(struct SpaceFile *sfile, struct ID *asset_id, bool deferred);
void ED_fileselect_deselect_all(struct SpaceFile *sfile);
void ED_fileselect_activate_by_relpath(struct SpaceFile *sfile, const char *relative_path);
@@ -256,7 +254,7 @@ char *ED_fsmenu_entry_get_name(struct FSMenuEntry *fsentry);
void ED_fsmenu_entry_set_name(struct FSMenuEntry *fsentry, const char *name);
int ED_fsmenu_entry_get_icon(struct FSMenuEntry *fsentry);
-void ED_fsmenu_entry_set_icon(struct FSMenuEntry *fsentry, const int icon);
+void ED_fsmenu_entry_set_icon(struct FSMenuEntry *fsentry, int icon);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/ED_gizmo_library.h b/source/blender/editors/include/ED_gizmo_library.h
index 55beff40177..8d4177faa0c 100644
--- a/source/blender/editors/include/ED_gizmo_library.h
+++ b/source/blender/editors/include/ED_gizmo_library.h
@@ -65,7 +65,7 @@ void ED_gizmo_draw_preset_circle(const struct wmGizmo *gz,
void ED_gizmo_draw_preset_facemap(const struct bContext *C,
const struct wmGizmo *gz,
struct Object *ob,
- const int facemap,
+ int facemap,
int select_id);
/* -------------------------------------------------------------------- */
@@ -97,13 +97,13 @@ enum {
*
* \note Needs to be called before #WM_gizmo_target_property_def_rna!
*/
-void ED_gizmo_arrow3d_set_ui_range(struct wmGizmo *gz, const float min, const float max);
+void ED_gizmo_arrow3d_set_ui_range(struct wmGizmo *gz, float min, float max);
/**
* Define a custom factor for arrow min/max distance.
*
* \note Needs to be called before #WM_gizmo_target_property_def_rna!
*/
-void ED_gizmo_arrow3d_set_range_fac(struct wmGizmo *gz, const float range_fac);
+void ED_gizmo_arrow3d_set_range_fac(struct wmGizmo *gz, float range_fac);
/* -------------------------------------------------------------------- */
/* Cage Gizmo */
@@ -248,9 +248,9 @@ struct Dial3dParams {
};
void ED_gizmotypes_dial_3d_draw_util(const float matrix_basis[4][4],
const float matrix_final[4][4],
- const float line_width,
+ float line_width,
const float color[4],
- const bool select,
+ bool select,
struct Dial3dParams *params);
/* snap3d_gizmo.c */
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 99164bbe439..919ea3e4a6b 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -94,7 +94,7 @@ typedef enum eGP_TargetObjectMode {
*/
typedef struct tGPspoint {
/** Coordinates x and y of cursor (in relative to area). */
- float x, y;
+ float m_xy[2];
/** Pressure of tablet at this point. */
float pressure;
/** Pressure of tablet at this point for alpha factor. */
@@ -193,7 +193,7 @@ bool ED_gpencil_has_keyframe_v3d(struct Scene *scene, struct Object *ob, int cfr
/* ----------- Stroke Editing Utilities ---------------- */
bool ED_gpencil_frame_has_selected_stroke(const struct bGPDframe *gpf);
-bool ED_gpencil_layer_has_selected_stroke(const struct bGPDlayer *gpl, const bool is_multiedit);
+bool ED_gpencil_layer_has_selected_stroke(const struct bGPDlayer *gpl, bool is_multiedit);
/**
* Check whether given stroke can be edited given the supplied context.
@@ -250,12 +250,8 @@ void ED_annotation_draw_view3d(struct Scene *scene,
struct View3D *v3d,
struct ARegion *region,
bool only3d);
-void ED_annotation_draw_ex(struct Scene *scene,
- struct bGPdata *gpd,
- int winx,
- int winy,
- const int cfra,
- const char spacetype);
+void ED_annotation_draw_ex(
+ struct Scene *scene, struct bGPdata *gpd, int winx, int winy, int cfra, char spacetype);
/* ----------- Grease-Pencil AnimEdit API ------------------ */
/**
@@ -315,7 +311,7 @@ void ED_gpencil_layer_frames_duplicate(struct bGPDlayer *gpl);
void ED_gpencil_layer_merge(struct bGPdata *gpd,
struct bGPDlayer *gpl_src,
struct bGPDlayer *gpl_dst,
- const bool reverse);
+ bool reverse);
/**
* Set keyframe type for selected frames from given gp-layer
@@ -348,14 +344,14 @@ bool ED_gpencil_anim_copybuf_copy(struct bAnimContext *ac);
/**
* Pastes keyframes from buffer, and reports success.
*/
-bool ED_gpencil_anim_copybuf_paste(struct bAnimContext *ac, const short copy_mode);
+bool ED_gpencil_anim_copybuf_paste(struct bAnimContext *ac, short copy_mode);
/* ------------ Grease-Pencil Undo System ------------------ */
int ED_gpencil_session_active(void);
/**
* \param step: eUndoStepDir.
*/
-int ED_undo_gpencil_step(struct bContext *C, const int step); /* eUndoStepDir. */
+int ED_undo_gpencil_step(struct bContext *C, int step); /* eUndoStepDir. */
/* ------------ Grease-Pencil Armature ------------------ */
bool ED_gpencil_add_armature(const struct bContext *C,
@@ -410,7 +406,7 @@ void ED_gpencil_brush_draw_eraser(struct Brush *brush, int x, int y);
*/
void ED_gpencil_stroke_init_data(struct bGPDstroke *gps,
const float *array,
- const int totpoints,
+ int totpoints,
const float mat[4][4]);
/**
@@ -457,7 +453,7 @@ void ED_gpencil_project_stroke_to_plane(const struct Scene *scene,
struct bGPDlayer *gpl,
struct bGPDstroke *gps,
const float origin[3],
- const int axis);
+ int axis);
/**
* Reproject given point to a plane locked to axis to avoid stroke offset
* \param pt: Point to affect (used for input & output).
@@ -467,7 +463,7 @@ void ED_gpencil_project_point_to_plane(const struct Scene *scene,
struct bGPDlayer *gpl,
const struct RegionView3D *rv3d,
const float origin[3],
- const int axis,
+ int axis,
struct bGPDspoint *pt);
/**
* Get drawing reference point for conversion or projection of the stroke
@@ -490,8 +486,8 @@ void ED_gpencil_stroke_reproject(struct Depsgraph *depsgraph,
struct bGPDlayer *gpl,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
- const eGP_ReprojectModes mode,
- const bool keep_original);
+ eGP_ReprojectModes mode,
+ bool keep_original);
/**
* Turn brush cursor in on/off.
@@ -513,7 +509,7 @@ void ED_gpencil_vgroup_remove(struct bContext *C, struct Object *ob);
*/
void ED_gpencil_vgroup_select(struct bContext *C, struct Object *ob);
/**
- * Unselect points of vertex group.
+ * Un-select points of vertex group.
*/
void ED_gpencil_vgroup_deselect(struct bContext *C, struct Object *ob);
@@ -552,7 +548,7 @@ int ED_gpencil_select_stroke_segment(struct bGPdata *gpd,
struct bGPDspoint *pt,
bool select,
bool insert,
- const float scale,
+ float scale,
float r_hita[3],
float r_hitb[3]);
@@ -566,7 +562,7 @@ void ED_gpencil_select_curve_toggle_all(struct bContext *C, int action);
struct tGPspoint *ED_gpencil_sbuffer_ensure(struct tGPspoint *buffer_array,
int *buffer_size,
int *buffer_used,
- const bool clear);
+ bool clear);
void ED_gpencil_sbuffer_update_eval(struct bGPdata *gpd, struct Object *ob_eval);
/**
@@ -600,7 +596,7 @@ void ED_gpencil_init_random_settings(struct Brush *brush,
bool ED_gpencil_stroke_check_collision(const struct GP_SpaceConversion *gsc,
struct bGPDstroke *gps,
const float mouse[2],
- const int radius,
+ int radius,
const float diff_mat[4][4]);
/**
* Check if a point is inside of the stroke.
@@ -631,7 +627,7 @@ struct bGPDstroke *ED_gpencil_stroke_nearest_to_ends(struct bContext *C,
struct bGPDstroke *gps,
const float ctrl1[2],
const float ctrl2[2],
- const float radius,
+ float radius,
int *r_index);
/**
* Get extremes of stroke in 2D using current view.
@@ -649,12 +645,12 @@ struct bGPDstroke *ED_gpencil_stroke_join_and_trim(struct bGPdata *gpd,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
struct bGPDstroke *gps_dst,
- const int pt_index);
+ int pt_index);
/**
* Close if the distance between extremes is below threshold.
*/
-void ED_gpencil_stroke_close_by_distance(struct bGPDstroke *gps, const float threshold);
+void ED_gpencil_stroke_close_by_distance(struct bGPDstroke *gps, float threshold);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index 3308ae2c178..3c1b8e4ecc1 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -38,24 +38,24 @@ struct Main;
struct ReportList;
struct Scene;
struct SpaceImage;
+struct View2D;
struct bContext;
struct wmOperator;
struct wmWindowManager;
-struct View2D;
/* image_draw.c */
-float ED_space_image_zoom_level(const struct View2D *v2d, const int grid_dimension);
+float ED_space_image_zoom_level(const struct View2D *v2d, int grid_dimension);
void ED_space_image_grid_steps(struct SpaceImage *sima,
float grid_steps[SI_GRID_STEPS_LEN],
- const int grid_dimension);
+ int grid_dimension);
/**
* Calculate the increment snapping value for UV/image editor based on the zoom factor
* The code in here (except the offset part) is used in `grid_frag.glsl` (see `grid_res`) for
* drawing the grid overlay for the UV/Image editor.
*/
-float ED_space_image_increment_snap_value(const int grid_dimesnions,
+float ED_space_image_increment_snap_value(int grid_dimesnions,
const float grid_steps[SI_GRID_STEPS_LEN],
- const float zoom_factor);
+ float zoom_factor);
/* image_edit.c, exported for transform. */
@@ -198,7 +198,7 @@ typedef struct ImageFrameRange {
*/
ListBase ED_image_filesel_detect_sequences(struct Main *bmain,
struct wmOperator *op,
- const bool detect_udim);
+ bool detect_udim);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h
index bafe68bd28d..f006378658b 100644
--- a/source/blender/editors/include/ED_keyframes_edit.h
+++ b/source/blender/editors/include/ED_keyframes_edit.h
@@ -93,6 +93,13 @@ typedef enum eEditKeyframes_Snap {
SNAP_KEYS_TIME,
} eEditKeyframes_Snap;
+/* equalizing tools */
+typedef enum eEditKeyframes_Equalize {
+ EQUALIZE_HANDLES_LEFT = (1 << 0),
+ EQUALIZE_HANDLES_RIGHT = (1 << 1),
+ EQUALIZE_HANDLES_BOTH = (EQUALIZE_HANDLES_LEFT | EQUALIZE_HANDLES_RIGHT),
+} eEditKeyframes_Equalize;
+
/* mirroring tools */
typedef enum eEditKeyframes_Mirror {
MIRROR_KEYS_CURFRAME = 1,
@@ -259,6 +266,18 @@ short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked,
KeyframeEditFunc key_cb,
FcuEditFunc fcu_cb);
/**
+ * Sets selected keyframes' bezier handles to an equal length and optionally makes
+ * the keyframes' handles horizontal.
+ * \param handle_length: Desired handle length, must be positive.
+ * \param flatten: Makes the keyframes' handles the same value as the keyframe,
+ * flattening the curve at that point.
+ */
+void ANIM_fcurve_equalize_keyframes_loop(struct FCurve *fcu,
+ eEditKeyframes_Equalize mode,
+ float handle_length,
+ bool flatten);
+
+/**
* Function for working with any type (i.e. one of the known types) of animation channel.
*/
short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked,
@@ -327,13 +346,13 @@ KeyframeEditFunc ANIM_editkeyframes_easing(short mode);
/**
* Get a callback to populate the selection settings map
- * requires: ked->custom = char[] of length fcurve->totvert.
+ * requires: `ked->custom = char[]` of length `fcurve->totvert`.
*/
KeyframeEditFunc ANIM_editkeyframes_buildselmap(short mode);
/**
* Change the selection status of the keyframe based on the map entry for this vert
- * requires: ked->custom = char[] of length fcurve->totvert.
+ * requires: `ked->custom = char[]` of length `fcurve->totvert`.
*/
short bezt_selmap_flush(KeyframeEditData *ked, struct BezTriple *bezt);
@@ -380,10 +399,26 @@ 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;
+
+/**
+ * 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(struct FCurve *fcu);
void clean_fcurve(struct bAnimContext *ac,
struct bAnimListElem *ale,
float thresh,
bool cleardefault);
+void blend_to_neighbor_fcurve_segment(struct FCurve *fcu,
+ struct FCurveSegment *segment,
+ float factor);
+void breakdown_fcurve_segment(struct FCurve *fcu, struct FCurveSegment *segment, float factor);
bool decimate_fcurve(struct bAnimListElem *ale, float remove_ratio, float error_sq_max);
/**
* Use a weighted moving-means method to reduce intensity of fluctuations.
@@ -397,8 +432,8 @@ void ANIM_fcurves_copybuf_free(void);
short copy_animedit_keys(struct bAnimContext *ac, ListBase *anim_data);
short paste_animedit_keys(struct bAnimContext *ac,
ListBase *anim_data,
- const eKeyPasteOffset offset_mode,
- const eKeyMergeMode merge_mode,
+ eKeyPasteOffset offset_mode,
+ eKeyMergeMode merge_mode,
bool flip);
/* ************************************************ */
diff --git a/source/blender/editors/include/ED_keyframes_keylist.h b/source/blender/editors/include/ED_keyframes_keylist.h
index 4194444ca0f..36a30bd5ee6 100644
--- a/source/blender/editors/include/ED_keyframes_keylist.h
+++ b/source/blender/editors/include/ED_keyframes_keylist.h
@@ -140,12 +140,9 @@ typedef enum eKeyframeExtremeDrawOpts {
struct AnimKeylist *ED_keylist_create(void);
void ED_keylist_free(struct AnimKeylist *keylist);
void ED_keylist_prepare_for_direct_access(struct AnimKeylist *keylist);
-const struct ActKeyColumn *ED_keylist_find_exact(const struct AnimKeylist *keylist,
- const float cfra);
-const struct ActKeyColumn *ED_keylist_find_next(const struct AnimKeylist *keylist,
- const float cfra);
-const struct ActKeyColumn *ED_keylist_find_prev(const struct AnimKeylist *keylist,
- const float cfra);
+const struct ActKeyColumn *ED_keylist_find_exact(const struct AnimKeylist *keylist, float cfra);
+const struct ActKeyColumn *ED_keylist_find_next(const struct AnimKeylist *keylist, float cfra);
+const struct ActKeyColumn *ED_keylist_find_prev(const struct AnimKeylist *keylist, float cfra);
const struct ActKeyColumn *ED_keylist_find_any_between(const struct AnimKeylist *keylist,
const Range2f frame_range);
bool ED_keylist_is_empty(const struct AnimKeylist *keylist);
@@ -160,41 +157,39 @@ int64_t ED_keylist_array_len(const struct AnimKeylist *keylist);
void fcurve_to_keylist(struct AnimData *adt,
struct FCurve *fcu,
struct AnimKeylist *keylist,
- const int saction_flag);
+ int saction_flag);
/* Action Group */
void agroup_to_keylist(struct AnimData *adt,
struct bActionGroup *agrp,
struct AnimKeylist *keylist,
- const int saction_flag);
+ int saction_flag);
/* Action */
void action_to_keylist(struct AnimData *adt,
struct bAction *act,
struct AnimKeylist *keylist,
- const int saction_flag);
+ int saction_flag);
/* Object */
void ob_to_keylist(struct bDopeSheet *ads,
struct Object *ob,
struct AnimKeylist *keylist,
- const int saction_flag);
+ int saction_flag);
/* Cache File */
void cachefile_to_keylist(struct bDopeSheet *ads,
struct CacheFile *cache_file,
struct AnimKeylist *keylist,
- const int saction_flag);
+ int saction_flag);
/* Scene */
void scene_to_keylist(struct bDopeSheet *ads,
struct Scene *sce,
struct AnimKeylist *keylist,
- const int saction_flag);
+ int saction_flag);
/* DopeSheet Summary */
-void summary_to_keylist(struct bAnimContext *ac,
- struct AnimKeylist *keylist,
- const int saction_flag);
+void summary_to_keylist(struct bAnimContext *ac, struct AnimKeylist *keylist, int saction_flag);
/* Grease Pencil datablock summary */
void gpencil_to_keylist(struct bDopeSheet *ads,
struct bGPdata *gpd,
struct AnimKeylist *keylist,
- const bool active);
+ bool active);
/* Grease Pencil Layer */
void gpl_to_keylist(struct bDopeSheet *ads, struct bGPDlayer *gpl, struct AnimKeylist *keylist);
/* Mask */
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index d539c7b688c..8d89555c732 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -62,7 +62,7 @@ struct NlaKeyframingContext;
* \param use_autokey_mode: include settings from key-framing mode in the result
* (i.e. replace only).
*/
-eInsertKeyFlags ANIM_get_keyframing_flags(struct Scene *scene, const bool use_autokey_mode);
+eInsertKeyFlags ANIM_get_keyframing_flags(struct Scene *scene, bool use_autokey_mode);
/* -------- */
@@ -81,15 +81,13 @@ struct FCurve *ED_action_fcurve_ensure(struct Main *bmain,
const char group[],
struct PointerRNA *ptr,
const char rna_path[],
- const int array_index);
+ int array_index);
/**
* Find the F-Curve from the Active Action,
* for the given Animation Data block. This assumes that all the destinations are valid.
*/
-struct FCurve *ED_action_fcurve_find(struct bAction *act,
- const char rna_path[],
- const int array_index);
+struct FCurve *ED_action_fcurve_find(struct bAction *act, const char rna_path[], int array_index);
/* -------- */
@@ -449,11 +447,11 @@ typedef enum eDriverFCurveCreationMode {
*/
struct FCurve *verify_driver_fcurve(struct ID *id,
const char rna_path[],
- const int array_index,
+ int array_index,
eDriverFCurveCreationMode creation_mode);
struct FCurve *alloc_driver_fcurve(const char rna_path[],
- const int array_index,
+ int array_index,
eDriverFCurveCreationMode creation_mode);
/* -------- */
diff --git a/source/blender/editors/include/ED_lattice.h b/source/blender/editors/include/ED_lattice.h
index dc800d78007..3d779fd14ef 100644
--- a/source/blender/editors/include/ED_lattice.h
+++ b/source/blender/editors/include/ED_lattice.h
@@ -43,7 +43,7 @@ bool ED_lattice_flags_set(struct Object *obedit, int flag);
bool ED_lattice_select_pick(
struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
-bool ED_lattice_deselect_all_multi_ex(struct Base **bases, const uint bases_len);
+bool ED_lattice_deselect_all_multi_ex(struct Base **bases, uint bases_len);
bool ED_lattice_deselect_all_multi(struct bContext *C);
/* editlattice_undo.c */
diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h
index 3aab6882dc2..1a4c36acff9 100644
--- a/source/blender/editors/include/ED_mask.h
+++ b/source/blender/editors/include/ED_mask.h
@@ -79,7 +79,7 @@ bool ED_mask_selected_minmax(const struct bContext *C,
/* mask_draw.c */
-void ED_mask_draw(const struct bContext *C, const char draw_flag, const char draw_type);
+void ED_mask_draw(const struct bContext *C, char draw_flag, char draw_type);
/**
* Sets up the opengl context.
* width, height are to match the values from #ED_mask_get_size().
@@ -87,26 +87,25 @@ void ED_mask_draw(const struct bContext *C, const char draw_flag, const char dra
void ED_mask_draw_region(struct Depsgraph *depsgraph,
struct Mask *mask,
struct ARegion *region,
- const char draw_flag,
- const char draw_type,
- const eMaskOverlayMode overlay_mode,
- const int width_i,
- const int height_i,
- const float aspx,
- const float aspy,
- const bool do_scale_applied,
- const bool do_draw_cb,
+ char draw_flag,
+ char draw_type,
+ eMaskOverlayMode overlay_mode,
+ int width_i,
+ int height_i,
+ float aspx,
+ float aspy,
+ bool do_scale_applied,
+ bool do_draw_cb,
float stabmat[4][4],
const struct bContext *C);
-void ED_mask_draw_frames(
- struct Mask *mask, struct ARegion *region, const int cfra, const int sfra, const int efra);
+void ED_mask_draw_frames(struct Mask *mask, struct ARegion *region, int cfra, int sfra, int efra);
/* mask_shapekey.c */
-void ED_mask_layer_shape_auto_key(struct MaskLayer *mask_layer, const int frame);
-bool ED_mask_layer_shape_auto_key_all(struct Mask *mask, const int frame);
-bool ED_mask_layer_shape_auto_key_select(struct Mask *mask, const int frame);
+void ED_mask_layer_shape_auto_key(struct MaskLayer *mask_layer, int frame);
+bool ED_mask_layer_shape_auto_key_all(struct Mask *mask, int frame);
+bool ED_mask_layer_shape_auto_key_select(struct Mask *mask, int frame);
/* ----------- Mask AnimEdit API ------------------ */
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 35838f4ce48..0721aa21a16 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -60,30 +60,30 @@ struct wmOperator;
/* editmesh_utils.c */
/**
- * \param em: Editmesh.
- * \param use_self: Allow a vertex to point to its self (middle verts).
+ * \param em: Edit-mesh used for generating mirror data.
+ * \param use_self: Allow a vertex to point to itself (middle verts).
* \param use_select: Restrict to selected verts.
* \param respecthide: Skip hidden vertices.
* \param use_topology: Use topology mirror.
* \param maxdist: Distance for close point test.
- * \param r_index: Optional array to write into, as an alternative to a customdata layer
+ * \param r_index: Optional array to write into, as an alternative to a custom-data layer
* (length of total verts).
*/
void EDBM_verts_mirror_cache_begin_ex(struct BMEditMesh *em,
- const int axis,
- const bool use_self,
- const bool use_select,
- const bool respecthide,
- const bool use_topology,
+ int axis,
+ bool use_self,
+ bool use_select,
+ bool respecthide,
+ bool use_topology,
float maxdist,
int *r_index);
void EDBM_verts_mirror_cache_begin(struct BMEditMesh *em,
- const int axis,
- const bool use_self,
- const bool use_select,
- const bool respecthide,
- const bool use_topology);
-void EDBM_verts_mirror_apply(struct BMEditMesh *em, const int sel_from, const int sel_to);
+ int axis,
+ bool use_self,
+ bool use_select,
+ bool respecthide,
+ bool use_topology);
+void EDBM_verts_mirror_apply(struct BMEditMesh *em, int sel_from, int sel_to);
struct BMVert *EDBM_verts_mirror_get(struct BMEditMesh *em, struct BMVert *v);
struct BMEdge *EDBM_verts_mirror_get_edge(struct BMEditMesh *em, struct BMEdge *e);
struct BMFace *EDBM_verts_mirror_get_face(struct BMEditMesh *em, struct BMFace *f);
@@ -96,7 +96,7 @@ void EDBM_mesh_normals_update(struct BMEditMesh *em);
void EDBM_mesh_clear(struct BMEditMesh *em);
void EDBM_selectmode_to_scene(struct bContext *C);
-void EDBM_mesh_make(struct Object *ob, const int select_mode, const bool add_key_index);
+void EDBM_mesh_make(struct Object *ob, int select_mode, bool add_key_index);
/**
* Should only be called on the active edit-mesh, otherwise call #BKE_editmesh_free_data.
*/
@@ -115,10 +115,10 @@ void EDBM_mesh_load(struct Main *bmain, struct Object *ob);
* edges select/deselect faces and vertices, and in face select mode faces select/deselect
* edges and vertices.
*/
-void EDBM_select_more(struct BMEditMesh *em, const bool use_face_step);
-void EDBM_select_less(struct BMEditMesh *em, const bool use_face_step);
+void EDBM_select_more(struct BMEditMesh *em, bool use_face_step);
+void EDBM_select_less(struct BMEditMesh *em, bool use_face_step);
-void EDBM_selectmode_flush_ex(struct BMEditMesh *em, const short selectmode);
+void EDBM_selectmode_flush_ex(struct BMEditMesh *em, short selectmode);
void EDBM_selectmode_flush(struct BMEditMesh *em);
void EDBM_deselect_flush(struct BMEditMesh *em);
@@ -145,17 +145,17 @@ void EDBM_update(struct Mesh *me, const struct EDBMUpdate_Params *params);
/**
* Bad level call from Python API.
*/
-void EDBM_update_extern(struct Mesh *me, const bool do_tessellation, const bool is_destructive);
+void EDBM_update_extern(struct Mesh *me, bool do_tessellation, bool is_destructive);
/**
* A specialized vert map used by stitch operator.
*/
struct UvElementMap *BM_uv_element_map_create(struct BMesh *bm,
const struct Scene *scene,
- const bool face_selected,
- const bool uv_selected,
- const bool use_winding,
- const bool do_islands);
+ bool face_selected,
+ bool uv_selected,
+ bool use_winding,
+ bool do_islands);
void BM_uv_element_map_free(struct UvElementMap *element_map);
struct UvElement *BM_uv_element_get(struct UvElementMap *map,
struct BMFace *efa,
@@ -169,21 +169,17 @@ bool EDBM_uv_check(struct BMEditMesh *em);
* last_sel, use em->act_face otherwise get the last selected face in the editselections
* at the moment, last_sel is mainly useful for making sure the space image doesn't flicker.
*/
-struct BMFace *EDBM_uv_active_face_get(struct BMEditMesh *em,
- const bool sloppy,
- const bool selected);
+struct BMFace *EDBM_uv_active_face_get(struct BMEditMesh *em, bool sloppy, bool selected);
void BM_uv_vert_map_free(struct UvVertMap *vmap);
struct UvMapVert *BM_uv_vert_map_at_index(struct UvVertMap *vmap, unsigned int v);
/**
* Return a new #UvVertMap from the edit-mesh.
*/
-struct UvVertMap *BM_uv_vert_map_create(struct BMesh *bm,
- const bool use_select,
- const bool use_winding);
+struct UvVertMap *BM_uv_vert_map_create(struct BMesh *bm, bool use_select, bool use_winding);
-void EDBM_flag_enable_all(struct BMEditMesh *em, const char hflag);
-void EDBM_flag_disable_all(struct BMEditMesh *em, const char hflag);
+void EDBM_flag_enable_all(struct BMEditMesh *em, char hflag);
+void EDBM_flag_disable_all(struct BMEditMesh *em, char hflag);
bool BMBVH_EdgeVisible(struct BMBVHTree *tree,
struct BMEdge *e,
@@ -200,13 +196,9 @@ void EDBM_project_snap_verts(struct bContext *C,
/* editmesh_automerge.c */
-void EDBM_automerge(struct Object *ob, bool update, const char hflag, const float dist);
-void EDBM_automerge_and_split(struct Object *ob,
- const bool split_edges,
- const bool split_faces,
- const bool update,
- const char hflag,
- const float dist);
+void EDBM_automerge(struct Object *ob, bool update, char hflag, float dist);
+void EDBM_automerge_and_split(
+ struct Object *ob, bool split_edges, bool split_faces, bool update, char hflag, float dist);
/* editmesh_undo.c */
@@ -217,8 +209,8 @@ void ED_mesh_undosys_type(struct UndoType *ut);
void EDBM_select_mirrored(struct BMEditMesh *em,
const struct Mesh *me,
- const int axis,
- const bool extend,
+ int axis,
+ bool extend,
int *r_totmirr,
int *r_totfail);
@@ -235,7 +227,7 @@ void EDBM_select_mirrored(struct BMEditMesh *em,
*/
struct BMVert *EDBM_vert_find_nearest_ex(struct ViewContext *vc,
float *dist_px_manhattan_p,
- const bool use_select_bias,
+ bool use_select_bias,
bool use_cycle,
struct Base **bases,
uint bases_len,
@@ -245,7 +237,7 @@ struct BMVert *EDBM_vert_find_nearest(struct ViewContext *vc, float *dist_px_man
struct BMEdge *EDBM_edge_find_nearest_ex(struct ViewContext *vc,
float *dist_px_manhattan,
float *r_dist_center,
- const bool use_select_bias,
+ bool use_select_bias,
bool use_cycle,
struct BMEdge **r_eed_zbuf,
struct Base **bases,
@@ -263,8 +255,8 @@ struct BMEdge *EDBM_edge_find_nearest(struct ViewContext *vc, float *dist_px_man
struct BMFace *EDBM_face_find_nearest_ex(struct ViewContext *vc,
float *dist_px_manhattan,
float *r_dist_center,
- const bool use_zbuf_single_px,
- const bool use_select_bias,
+ bool use_zbuf_single_px,
+ bool use_select_bias,
bool use_cycle,
struct BMFace **r_efa_zbuf,
struct Base **bases,
@@ -274,7 +266,7 @@ struct BMFace *EDBM_face_find_nearest(struct ViewContext *vc, float *dist_px_man
bool EDBM_unified_findnearest(struct ViewContext *vc,
struct Base **bases,
- const uint bases_len,
+ uint bases_len,
int *r_base_index,
struct BMVert **r_eve,
struct BMEdge **r_eed,
@@ -282,7 +274,7 @@ bool EDBM_unified_findnearest(struct ViewContext *vc,
bool EDBM_unified_findnearest_from_raycast(struct ViewContext *vc,
struct Base **bases,
- const uint bases_len,
+ uint bases_len,
bool use_boundary_vertices,
bool use_boundary_edges,
int *r_base_index_vert,
@@ -314,22 +306,17 @@ void EDBM_selectmode_set(struct BMEditMesh *em);
* - face -> vert
* - edge -> vert
*/
-void EDBM_selectmode_convert(struct BMEditMesh *em,
- const short selectmode_old,
- const short selectmode_new);
+void EDBM_selectmode_convert(struct BMEditMesh *em, short selectmode_old, short selectmode_new);
/**
* User access this.
*/
-bool EDBM_selectmode_set_multi(struct bContext *C, const short selectmode);
+bool EDBM_selectmode_set_multi(struct bContext *C, short selectmode);
/**
* User facing function, does notification.
*/
-bool EDBM_selectmode_toggle_multi(struct bContext *C,
- const short selectmode_new,
- const int action,
- const bool use_extend,
- const bool use_expand);
+bool EDBM_selectmode_toggle_multi(
+ struct bContext *C, short selectmode_new, int action, bool use_extend, bool use_expand);
/**
* Use to disable a select-mode if its enabled, Using another mode as a fallback
@@ -339,10 +326,10 @@ bool EDBM_selectmode_toggle_multi(struct bContext *C,
*/
bool EDBM_selectmode_disable(struct Scene *scene,
struct BMEditMesh *em,
- const short selectmode_disable,
- const short selectmode_fallback);
+ short selectmode_disable,
+ short selectmode_fallback);
-bool EDBM_deselect_by_material(struct BMEditMesh *em, const short index, const bool select);
+bool EDBM_deselect_by_material(struct BMEditMesh *em, short index, bool select);
void EDBM_select_toggle_all(struct BMEditMesh *em);
@@ -350,16 +337,16 @@ void EDBM_select_swap(struct BMEditMesh *em); /* exported for UV */
bool EDBM_select_interior_faces(struct BMEditMesh *em);
void em_setup_viewcontext(struct bContext *C, struct ViewContext *vc); /* rename? */
-bool EDBM_mesh_deselect_all_multi_ex(struct Base **bases, const uint bases_len);
+bool EDBM_mesh_deselect_all_multi_ex(struct Base **bases, uint bases_len);
bool EDBM_mesh_deselect_all_multi(struct bContext *C);
bool EDBM_selectmode_disable_multi_ex(struct Scene *scene,
struct Base **bases,
- const uint bases_len,
- const short selectmode_disable,
- const short selectmode_fallback);
+ uint bases_len,
+ short selectmode_disable,
+ short selectmode_fallback);
bool EDBM_selectmode_disable_multi(struct bContext *C,
- const short selectmode_disable,
- const short selectmode_fallback);
+ short selectmode_disable,
+ short selectmode_fallback);
/* editmesh_preselect_edgering.c */
struct EditMesh_PreSelEdgeRing;
@@ -429,11 +416,11 @@ bool paintface_deselect_all_visible(struct bContext *C,
void paintface_select_linked(struct bContext *C,
struct Object *ob,
const int mval[2],
- const bool select);
+ bool select);
bool paintface_minmax(struct Object *ob, float r_min[3], float r_max[3]);
-void paintface_hide(struct bContext *C, struct Object *ob, const bool unselected);
-void paintface_reveal(struct bContext *C, struct Object *ob, const bool select);
+void paintface_hide(struct bContext *C, struct Object *ob, bool unselected);
+void paintface_reveal(struct bContext *C, struct Object *ob, bool select);
/**
* \note if the caller passes false to flush_flags,
@@ -463,7 +450,7 @@ bool ED_mesh_mirrtopo_recalc_check(struct BMEditMesh *em,
void ED_mesh_mirrtopo_init(struct BMEditMesh *em,
struct Mesh *me,
MirrTopoStore_t *mesh_topo_store,
- const bool skip_em_vert_array_init);
+ bool skip_em_vert_array_init);
void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store);
/* object_vgroup.c */
@@ -476,7 +463,7 @@ void ED_vgroup_select_by_name(struct Object *ob, const char *name);
/**
* Removes out of range #MDeformWeights
*/
-void ED_vgroup_data_clamp_range(struct ID *id, const int total);
+void ED_vgroup_data_clamp_range(struct ID *id, int total);
/**
* Matching index only.
*/
@@ -484,7 +471,7 @@ bool ED_vgroup_array_copy(struct Object *ob, struct Object *ob_from);
bool ED_vgroup_parray_alloc(struct ID *id,
struct MDeformVert ***dvert_arr,
int *dvert_tot,
- const bool use_vert_sel);
+ bool use_vert_sel);
/**
* For use with tools that use ED_vgroup_parray_alloc with \a use_vert_sel == true.
* This finds the unselected mirror deform verts and copies the weights to them from the selected.
@@ -494,9 +481,9 @@ bool ED_vgroup_parray_alloc(struct ID *id,
*/
void ED_vgroup_parray_mirror_sync(struct Object *ob,
struct MDeformVert **dvert_array,
- const int dvert_tot,
+ int dvert_tot,
const bool *vgroup_validmap,
- const int vgroup_tot);
+ int vgroup_tot);
/**
* Fill in the pointers for mirror verts (as if all mirror verts were selected too).
*
@@ -504,27 +491,27 @@ void ED_vgroup_parray_mirror_sync(struct Object *ob,
*/
void ED_vgroup_parray_mirror_assign(struct Object *ob,
struct MDeformVert **dvert_array,
- const int dvert_tot);
+ int dvert_tot);
void ED_vgroup_parray_remove_zero(struct MDeformVert **dvert_array,
- const int dvert_tot,
+ int dvert_tot,
const bool *vgroup_validmap,
- const int vgroup_tot,
- const float epsilon,
- const bool keep_single);
+ int vgroup_tot,
+ float epsilon,
+ bool keep_single);
void ED_vgroup_parray_to_weight_array(const struct MDeformVert **dvert_array,
- const int dvert_tot,
+ int dvert_tot,
float *dvert_weights,
- const int def_nr);
+ int def_nr);
void ED_vgroup_parray_from_weight_array(struct MDeformVert **dvert_array,
- const int dvert_tot,
+ int dvert_tot,
const float *dvert_weights,
- const int def_nr,
- const bool remove_zero);
+ int def_nr,
+ bool remove_zero);
void ED_vgroup_mirror(struct Object *ob,
- const bool mirror_weights,
- const bool flip_vgroups,
- const bool all_vgroups,
- const bool use_topology,
+ bool mirror_weights,
+ bool flip_vgroups,
+ bool all_vgroups,
+ bool use_topology,
int *r_totmirr,
int *r_totfail);
@@ -560,36 +547,27 @@ void ED_mesh_geometry_clear(struct Mesh *mesh);
void ED_mesh_update(struct Mesh *mesh, struct bContext *C, bool calc_edges, bool calc_edges_loose);
void ED_mesh_uv_texture_ensure(struct Mesh *me, const char *name);
-int ED_mesh_uv_texture_add(struct Mesh *me,
- const char *name,
- const bool active_set,
- const bool do_init,
- struct ReportList *reports);
-bool ED_mesh_uv_texture_remove_index(struct Mesh *me, const int n);
+int ED_mesh_uv_texture_add(
+ struct Mesh *me, const char *name, bool active_set, bool do_init, struct ReportList *reports);
+bool ED_mesh_uv_texture_remove_index(struct Mesh *me, int n);
bool ED_mesh_uv_texture_remove_active(struct Mesh *me);
bool ED_mesh_uv_texture_remove_named(struct Mesh *me, const char *name);
void ED_mesh_uv_loop_reset(struct bContext *C, struct Mesh *me);
/**
* Without a #bContext, called when UV-editing.
*/
-void ED_mesh_uv_loop_reset_ex(struct Mesh *me, const int layernum);
+void ED_mesh_uv_loop_reset_ex(struct Mesh *me, int layernum);
bool ED_mesh_color_ensure(struct Mesh *me, const char *name);
-int ED_mesh_color_add(struct Mesh *me,
- const char *name,
- const bool active_set,
- const bool do_init,
- struct ReportList *reports);
-bool ED_mesh_color_remove_index(struct Mesh *me, const int n);
+int ED_mesh_color_add(
+ struct Mesh *me, const char *name, bool active_set, bool do_init, struct ReportList *reports);
+bool ED_mesh_color_remove_index(struct Mesh *me, int n);
bool ED_mesh_color_remove_active(struct Mesh *me);
bool ED_mesh_color_remove_named(struct Mesh *me, const char *name);
bool ED_mesh_sculpt_color_ensure(struct Mesh *me, const char *name);
-int ED_mesh_sculpt_color_add(struct Mesh *me,
- const char *name,
- const bool active_set,
- const bool do_init,
- struct ReportList *reports);
-bool ED_mesh_sculpt_color_remove_index(struct Mesh *me, const int n);
+int ED_mesh_sculpt_color_add(
+ struct Mesh *me, const char *name, bool active_set, bool do_init, struct ReportList *reports);
+bool ED_mesh_sculpt_color_remove_index(struct Mesh *me, int n);
bool ED_mesh_sculpt_color_remove_active(struct Mesh *me);
bool ED_mesh_sculpt_color_remove_named(struct Mesh *me, const char *name);
@@ -654,16 +632,13 @@ void ED_mesh_mirror_topo_table_end(struct Object *ob);
* Retrieves mirrored cache vert, or NULL if there isn't one.
* \note calling this without ensuring the mirror cache state is bad.
*/
-int mesh_get_x_mirror_vert(struct Object *ob,
- struct Mesh *me_eval,
- int index,
- const bool use_topology);
+int mesh_get_x_mirror_vert(struct Object *ob, struct Mesh *me_eval, int index, bool use_topology);
struct BMVert *editbmesh_get_x_mirror_vert(struct Object *ob,
struct BMEditMesh *em,
struct BMVert *eve,
const float co[3],
int index,
- const bool use_topology);
+ bool use_topology);
/**
* This is a Mesh-based copy of #mesh_get_x_mirror_faces().
*/
@@ -672,7 +647,7 @@ int *mesh_get_x_mirror_faces(struct Object *ob, struct BMEditMesh *em, struct Me
/**
* Wrapper for object-mode/edit-mode.
*
- * call #BM_mesh_elem_table_ensure first for editmesh.
+ * call #BM_mesh_elem_table_ensure first for edit-mesh.
*/
int ED_mesh_mirror_get_vert(struct Object *ob, int index);
@@ -702,12 +677,10 @@ struct MDeformVert *ED_mesh_active_dvert_get_ob(struct Object *ob, int *r_index)
struct MDeformVert *ED_mesh_active_dvert_get_only(struct Object *ob);
void EDBM_mesh_stats_multi(struct Object **objects,
- const uint objects_len,
+ uint objects_len,
int totelem[3],
int totelem_sel[3]);
-void EDBM_mesh_elem_index_ensure_multi(struct Object **objects,
- const uint objects_len,
- const char htype);
+void EDBM_mesh_elem_index_ensure_multi(struct Object **objects, uint objects_len, char htype);
#define ED_MESH_PICK_DEFAULT_VERT_DIST 25
#define ED_MESH_PICK_DEFAULT_FACE_DIST 1
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index 5bac452c7c9..181b6848ac7 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -100,12 +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.
- */
-void ED_node_sort(struct bNodeTree *ntree);
+
float ED_node_grid_size(void);
/* node_relationships.c */
@@ -142,8 +137,6 @@ void ED_node_composit_default(const struct bContext *C, struct Scene *scene);
* Called from shading buttons or header.
*/
void ED_node_texture_default(const struct bContext *C, struct Tex *tex);
-bool ED_node_select_check(const ListBase *lb);
-void ED_node_select_all(ListBase *lb, int action);
void ED_node_post_apply_transform(struct bContext *C, struct bNodeTree *ntree);
void ED_node_set_active(struct Main *bmain,
struct SpaceNode *snode,
@@ -152,6 +145,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/include/ED_numinput.h b/source/blender/editors/include/ED_numinput.h
index 84fa4488374..9fd77fa858e 100644
--- a/source/blender/editors/include/ED_numinput.h
+++ b/source/blender/editors/include/ED_numinput.h
@@ -114,7 +114,7 @@ bool user_string_to_number(bContext *C,
const struct UnitSettings *unit,
int type,
double *r_value,
- const bool use_single_line_error,
+ bool use_single_line_error,
char **r_error);
/** \} */
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 576c6f51362..805b48d9195 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -82,12 +82,12 @@ Object **ED_object_array_in_mode_or_selected(struct bContext *C,
/* object_utils.c */
bool ED_object_calc_active_center_for_editmode(struct Object *obedit,
- const bool select_only,
+ bool select_only,
float r_center[3]);
bool ED_object_calc_active_center_for_posemode(struct Object *ob,
- const bool select_only,
+ bool select_only,
float r_center[3]);
-bool ED_object_calc_active_center(struct Object *ob, const bool select_only, float r_center[3]);
+bool ED_object_calc_active_center(struct Object *ob, bool select_only, float r_center[3]);
/* Object Data Container helper API. */
struct XFormObjectData_Container;
@@ -189,10 +189,10 @@ bool ED_object_parent_set(struct ReportList *reports,
struct Object *const ob,
struct Object *const par,
int partype,
- const bool xmirror,
- const bool keep_transform,
+ bool xmirror,
+ bool keep_transform,
const int vert_par[3]);
-void ED_object_parent_clear(struct Object *ob, const int type);
+void ED_object_parent_clear(struct Object *ob, int type);
/**
* Simple API for object selection, rather than just using the flag
@@ -243,12 +243,9 @@ struct Base *ED_object_add_duplicate(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
struct Base *base,
- const eDupli_ID_Flags dupflag);
+ eDupli_ID_Flags dupflag);
-void ED_object_parent(struct Object *ob,
- struct Object *parent,
- const int type,
- const char *substr);
+void ED_object_parent(struct Object *ob, struct Object *parent, int type, const char *substr);
char *ED_object_ot_drop_named_material_tooltip(struct bContext *C,
struct PointerRNA *properties,
const int mval[2]);
@@ -323,7 +320,7 @@ void ED_object_sculptmode_enter_ex(struct Main *bmain,
struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
- const bool force_dyntopo,
+ bool force_dyntopo,
struct ReportList *reports);
void ED_object_sculptmode_enter(struct bContext *C,
struct Depsgraph *depsgraph,
@@ -335,8 +332,8 @@ void ED_object_sculptmode_exit_ex(struct Main *bmain,
void ED_object_sculptmode_exit(struct bContext *C, struct Depsgraph *depsgraph);
void ED_object_location_from_view(struct bContext *C, float loc[3]);
-void ED_object_rotation_from_quat(float rot[3], const float quat[4], const char align_axis);
-void ED_object_rotation_from_view(struct bContext *C, float rot[3], const char align_axis);
+void ED_object_rotation_from_quat(float rot[3], const float quat[4], char align_axis);
+void ED_object_rotation_from_view(struct bContext *C, float rot[3], char align_axis);
void ED_object_base_init_transform_on_add(struct Object *object,
const float loc[3],
const float rot[3]);
@@ -363,7 +360,7 @@ void ED_object_add_generic_props(struct wmOperatorType *ot, bool do_editmode);
void ED_object_add_mesh_props(struct wmOperatorType *ot);
bool ED_object_add_generic_get_opts(struct bContext *C,
struct wmOperator *op,
- const char view_align_axis,
+ char view_align_axis,
float r_loc[3],
float r_rot[3],
float r_scale[3],
@@ -378,20 +375,20 @@ bool ED_object_add_generic_get_opts(struct bContext *C,
* \note Do not call undo push in this function (users of this function have to).
*/
struct Object *ED_object_add_type_with_obdata(struct bContext *C,
- const int type,
+ int type,
const char *name,
const float loc[3],
const float rot[3],
- const bool enter_editmode,
- const ushort local_view_bits,
+ bool enter_editmode,
+ ushort local_view_bits,
struct ID *obdata);
struct Object *ED_object_add_type(struct bContext *C,
- const int type,
+ int type,
const char *name,
const float loc[3],
const float rot[3],
- const bool enter_editmode,
- const unsigned short local_view_bits)
+ bool enter_editmode,
+ unsigned short local_view_bits)
ATTR_NONNULL(1) ATTR_RETURNS_NONNULL;
/**
@@ -468,9 +465,7 @@ void ED_object_constraint_dependency_tag_update(struct Main *bmain,
struct Object *ob,
struct bConstraint *con);
-bool ED_object_constraint_move_to_index(struct Object *ob,
- struct bConstraint *con,
- const int index);
+bool ED_object_constraint_move_to_index(struct Object *ob, struct bConstraint *con, int index);
void ED_object_constraint_link(struct Main *bmain,
struct Object *ob_dst,
struct ListBase *dst,
@@ -514,7 +509,7 @@ bool ED_object_mode_generic_has_data(struct Depsgraph *depsgraph, const struct O
void ED_object_posemode_set_for_weight_paint(struct bContext *C,
struct Main *bmain,
struct Object *ob,
- const bool is_mode_set);
+ bool is_mode_set);
/* object_modifier.c */
@@ -550,7 +545,7 @@ bool ED_object_modifier_move_up(struct ReportList *reports,
bool ED_object_modifier_move_to_index(struct ReportList *reports,
struct Object *ob,
struct ModifierData *md,
- const int index);
+ int index);
bool ED_object_modifier_convert(struct ReportList *reports,
struct Main *bmain,
@@ -588,7 +583,7 @@ void ED_object_modifier_copy_to_object(struct bContext *C,
*/
bool ED_object_iter_other(struct Main *bmain,
struct Object *orig_ob,
- const bool include_orig,
+ bool include_orig,
bool (*callback)(struct Object *ob, void *callback_data),
void *callback_data);
@@ -619,7 +614,7 @@ bool ED_object_gpencil_modifier_move_up(struct ReportList *reports,
bool ED_object_gpencil_modifier_move_to_index(struct ReportList *reports,
struct Object *ob,
struct GpencilModifierData *md,
- const int index);
+ int index);
bool ED_object_gpencil_modifier_apply(struct Main *bmain,
struct ReportList *reports,
struct Depsgraph *depsgraph,
@@ -653,7 +648,7 @@ int ED_object_shaderfx_move_up(struct ReportList *reports,
bool ED_object_shaderfx_move_to_index(struct ReportList *reports,
struct Object *ob,
struct ShaderFxData *fx,
- const int index);
+ int index);
void ED_object_shaderfx_link(struct Object *dst, struct Object *src);
void ED_object_shaderfx_copy(struct Object *dst, struct ShaderFxData *fx);
@@ -665,7 +660,7 @@ const struct EnumPropertyItem *ED_object_vgroup_selection_itemf_helper(
struct PointerRNA *ptr,
struct PropertyRNA *prop,
bool *r_free,
- const unsigned int selection_mask);
+ unsigned int selection_mask);
void ED_object_check_force_modifiers(struct Main *bmain,
struct Scene *scene,
@@ -683,7 +678,7 @@ struct Base *ED_object_find_first_by_data_id(struct ViewLayer *view_layer, struc
*
* \returns false if not found in current view layer
*/
-bool ED_object_jump_to_object(struct bContext *C, struct Object *ob, const bool reveal_hidden);
+bool ED_object_jump_to_object(struct bContext *C, struct Object *ob, bool reveal_hidden);
/**
* Select and make the target object and bone active.
* Switches to Pose mode if in Object mode so the selection is visible.
@@ -694,7 +689,7 @@ bool ED_object_jump_to_object(struct bContext *C, struct Object *ob, const bool
bool ED_object_jump_to_bone(struct bContext *C,
struct Object *ob,
const char *bone_name,
- const bool reveal_hidden);
+ bool reveal_hidden);
/* object_facemap_ops.c */
diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h
index ce25943b40a..9671f5b2b09 100644
--- a/source/blender/editors/include/ED_particle.h
+++ b/source/blender/editors/include/ED_particle.h
@@ -72,16 +72,13 @@ void PE_update_object(struct Depsgraph *depsgraph,
bool PE_mouse_particles(
struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
-bool PE_box_select(struct bContext *C, const struct rcti *rect, const int sel_op);
+bool PE_box_select(struct bContext *C, const struct rcti *rect, int sel_op);
bool PE_circle_select(struct bContext *C,
struct wmGenericUserData *wm_userdata,
- const int sel_op,
+ int sel_op,
const int mval[2],
float rad);
-int PE_lasso_select(struct bContext *C,
- const int mcoords[][2],
- const int mcoords_len,
- const int sel_op);
+int PE_lasso_select(struct bContext *C, const int mcoords[][2], int mcoords_len, int sel_op);
bool PE_deselect_all_visible_ex(struct PTCacheEdit *edit);
bool PE_deselect_all_visible(struct bContext *C);
diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h
index 50d7bfc3960..dabf8fb838b 100644
--- a/source/blender/editors/include/ED_render.h
+++ b/source/blender/editors/include/ED_render.h
@@ -23,6 +23,7 @@
#pragma once
+#include "DNA_ID_enums.h"
#include "DNA_vec_types.h"
#ifdef __cplusplus
@@ -41,7 +42,6 @@ struct bContext;
struct bScreen;
struct wmWindow;
struct wmWindowManager;
-enum eIconSizes;
/* render_ops.c */
@@ -49,7 +49,7 @@ void ED_operatortypes_render(void);
/* render_update.c */
-void ED_render_engine_changed(struct Main *bmain, const bool update_scene_data);
+void ED_render_engine_changed(struct Main *bmain, bool update_scene_data);
void ED_render_engine_area_exit(struct Main *bmain, struct ScrArea *area);
void ED_render_view_layer_changed(struct Main *bmain, struct bScreen *screen);
@@ -60,14 +60,14 @@ void ED_render_id_flush_update(const struct DEGEditorUpdateContext *update_ctx,
* Update all 3D viewport render and draw engines on changes to the scene.
* This is called by the dependency graph when it detects changes.
*/
-void ED_render_scene_update(const struct DEGEditorUpdateContext *update_ctx, const bool updated);
+void ED_render_scene_update(const struct DEGEditorUpdateContext *update_ctx, bool updated);
/**
* Update 3D viewport render or draw engine on changes to the scene or view settings.
*/
void ED_render_view3d_update(struct Depsgraph *depsgraph,
struct wmWindow *window,
struct ScrArea *area,
- const bool updated);
+ bool updated);
struct Scene *ED_render_job_get_scene(const struct bContext *C);
struct Scene *ED_render_job_get_current_scene(const struct bContext *C);
@@ -77,14 +77,12 @@ struct Scene *ED_render_job_get_current_scene(const struct bContext *C);
* pr_method:
* - PR_BUTS_RENDER: preview is rendered for buttons window
* - PR_ICON_RENDER: preview is rendered for icons. hopefully fast enough for at least 32x32
- * - PR_NODE_RENDER: preview is rendered for node editor
* - PR_ICON_DEFERRED: No render, we just ensure deferred icon data gets generated.
*/
typedef enum ePreviewRenderMethod {
PR_BUTS_RENDER = 0,
PR_ICON_RENDER = 1,
- PR_NODE_RENDER = 2,
- PR_ICON_DEFERRED = 3,
+ PR_ICON_DEFERRED = 2,
} ePreviewRenderMethod;
void ED_preview_ensure_dbase(void);
@@ -102,7 +100,7 @@ void ED_preview_shader_job(const struct bContext *C,
struct MTex *slot,
int sizex,
int sizey,
- int method);
+ ePreviewRenderMethod method);
void ED_preview_icon_render(const struct bContext *C,
struct Scene *scene,
struct ID *id,
@@ -115,7 +113,7 @@ void ED_preview_icon_job(const struct bContext *C,
unsigned int *rect,
int sizex,
int sizey,
- const bool delay);
+ bool delay);
void ED_preview_restart_queue_free(void);
void ED_preview_restart_queue_add(struct ID *id, enum eIconSizes size);
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index c65ef3e397d..651ae1de8be 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -160,11 +160,11 @@ void ED_region_visibility_change_update_animated(struct bContext *C,
void ED_region_info_draw(struct ARegion *region,
const char *text,
float fill_color[4],
- const bool full_redraw);
+ bool full_redraw);
void ED_region_info_draw_multiline(ARegion *region,
const char *text_array[],
float fill_color[4],
- const bool full_redraw);
+ bool full_redraw);
void ED_region_image_metadata_panel_draw(struct ImBuf *ibuf, struct uiLayout *layout);
void ED_region_grid_draw(struct ARegion *region, float zoomx, float zoomy, float x0, float y0);
float ED_region_blend_alpha(struct ARegion *region);
@@ -238,7 +238,7 @@ void ED_area_status_text(ScrArea *area, const char *str);
/**
* \param skip_region_exit: Skip calling area exit callback. Set for opening temp spaces.
*/
-void ED_area_newspace(struct bContext *C, ScrArea *area, int type, const bool skip_region_exit);
+void ED_area_newspace(struct bContext *C, ScrArea *area, int type, bool skip_region_exit);
void ED_area_prevspace(struct bContext *C, ScrArea *area);
void ED_area_swapspace(struct bContext *C, ScrArea *sa1, ScrArea *sa2);
int ED_area_headersize(void);
@@ -316,7 +316,7 @@ bool ED_screen_change(struct bContext *C, struct bScreen *screen);
void ED_screen_scene_change(struct bContext *C,
struct wmWindow *win,
struct Scene *scene,
- const bool refresh_toolsystem);
+ bool refresh_toolsystem);
/**
* Called in wm_event_system.c. sets state vars in screen, cursors.
* event type is mouse move.
@@ -360,7 +360,7 @@ bScreen *ED_screen_state_maximized_create(struct bContext *C);
struct ScrArea *ED_screen_state_toggle(struct bContext *C,
struct wmWindow *win,
struct ScrArea *area,
- const short state);
+ short state);
/**
* Wrapper to open a temporary space either as fullscreen space, or as separate window, as defined
* by \a display_type.
@@ -397,7 +397,7 @@ Scene *ED_screen_scene_find_with_window(const struct bScreen *screen,
struct wmWindow **r_window);
ScrArea *ED_screen_area_find_with_spacedata(const bScreen *screen,
const struct SpaceLink *sl,
- const bool only_visible);
+ bool only_visible);
struct wmWindow *ED_screen_window_find(const struct bScreen *screen,
const struct wmWindowManager *wm);
/**
@@ -473,9 +473,8 @@ struct WorkSpaceLayout *ED_workspace_layout_duplicate(struct Main *bmain,
bool ED_workspace_layout_delete(struct WorkSpace *workspace,
struct WorkSpaceLayout *layout_old,
struct bContext *C) ATTR_NONNULL();
-bool ED_workspace_layout_cycle(struct WorkSpace *workspace,
- const short direction,
- struct bContext *C) ATTR_NONNULL();
+bool ED_workspace_layout_cycle(struct WorkSpace *workspace, short direction, struct bContext *C)
+ ATTR_NONNULL();
void ED_workspace_status_text(struct bContext *C, const char *str);
@@ -644,12 +643,9 @@ void ED_screen_user_menu_register(void);
/* Cache display helpers */
void ED_region_cache_draw_background(struct ARegion *region);
-void ED_region_cache_draw_curfra_label(const int framenr, const float x, const float y);
-void ED_region_cache_draw_cached_segments(struct ARegion *region,
- const int num_segments,
- const int *points,
- const int sfra,
- const int efra);
+void ED_region_cache_draw_curfra_label(int framenr, float x, float y);
+void ED_region_cache_draw_cached_segments(
+ struct ARegion *region, int num_segments, const int *points, int sfra, int efra);
/* area_utils.c */
@@ -664,19 +660,15 @@ void ED_region_generic_tools_region_message_subscribe(
int ED_region_generic_tools_region_snap_size(const struct ARegion *region, int size, int axis);
/* area_query.c */
-bool ED_region_overlap_isect_x(const ARegion *region, const int event_x);
-bool ED_region_overlap_isect_y(const ARegion *region, const int event_y);
+bool ED_region_overlap_isect_x(const ARegion *region, int event_x);
+bool ED_region_overlap_isect_y(const ARegion *region, int event_y);
bool ED_region_overlap_isect_xy(const ARegion *region, const int event_xy[2]);
bool ED_region_overlap_isect_any_xy(const ScrArea *area, const int event_xy[2]);
-bool ED_region_overlap_isect_x_with_margin(const ARegion *region,
- const int event_x,
- const int margin);
-bool ED_region_overlap_isect_y_with_margin(const ARegion *region,
- const int event_y,
- const int margin);
+bool ED_region_overlap_isect_x_with_margin(const ARegion *region, int event_x, int margin);
+bool ED_region_overlap_isect_y_with_margin(const ARegion *region, int event_y, int margin);
bool ED_region_overlap_isect_xy_with_margin(const ARegion *region,
const int event_xy[2],
- const int margin);
+ int margin);
bool ED_region_panel_category_gutter_calc_rect(const ARegion *region, rcti *r_region_gutter);
bool ED_region_panel_category_gutter_isect_xy(const ARegion *region, const int event_xy[2]);
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index 0cdd8873cb2..7c1124d705f 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -60,7 +60,7 @@ void ED_sculpt_undo_geometry_end(struct Object *ob);
/* Face sets. */
int ED_sculpt_face_sets_find_next_available_id(struct Mesh *mesh);
-void ED_sculpt_face_sets_initialize_none_to_id(struct Mesh *mesh, const int new_id);
+void ED_sculpt_face_sets_initialize_none_to_id(struct Mesh *mesh, int new_id);
int ED_sculpt_face_sets_active_update_and_get(struct bContext *C,
struct Object *ob,
diff --git a/source/blender/editors/include/ED_select_utils.h b/source/blender/editors/include/ED_select_utils.h
index 4656099799b..295268c7719 100644
--- a/source/blender/editors/include/ED_select_utils.h
+++ b/source/blender/editors/include/ED_select_utils.h
@@ -64,27 +64,25 @@ enum {
* Use when we've de-selected all first for 'SEL_OP_SET'.
* 1: select, 0: deselect, -1: pass.
*/
-int ED_select_op_action(const eSelectOp sel_op, const bool is_select, const bool is_inside);
+int ED_select_op_action(eSelectOp sel_op, bool is_select, bool is_inside);
/**
* Use when we've de-selected all items first (for modes that need it).
*
* \note In some cases changing selection needs to perform other checks,
* so it's more straightforward to deselect all, then select.
*/
-int ED_select_op_action_deselected(const eSelectOp sel_op,
- const bool is_select,
- const bool is_inside);
+int ED_select_op_action_deselected(eSelectOp sel_op, bool is_select, bool is_inside);
-int ED_select_similar_compare_float(const float delta, const float thresh, const int compare);
+int ED_select_similar_compare_float(float delta, float thresh, int compare);
bool ED_select_similar_compare_float_tree(const struct KDTree_1d *tree,
- const float length,
- const float thresh,
- const int compare);
+ float length,
+ float thresh,
+ int compare);
/**
* Utility to use for selection operations that run multiple times (circle select).
*/
-eSelectOp ED_select_op_modal(const eSelectOp sel_op, const bool is_first);
+eSelectOp ED_select_op_modal(eSelectOp sel_op, bool is_first);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/ED_space_api.h b/source/blender/editors/include/ED_space_api.h
index f4a69737da1..fb76b36baef 100644
--- a/source/blender/editors/include/ED_space_api.h
+++ b/source/blender/editors/include/ED_space_api.h
@@ -86,7 +86,7 @@ void *ED_region_draw_cb_activate(struct ARegionType *art,
int type);
void ED_region_draw_cb_draw(const struct bContext *C, struct ARegion *region, int type);
void ED_region_surface_draw_cb_draw(struct ARegionType *art, int type);
-void ED_region_draw_cb_exit(struct ARegionType *art, void *handle);
+bool ED_region_draw_cb_exit(struct ARegionType *art, void *handle);
void ED_region_draw_cb_remove_by_type(struct ARegionType *art,
void *draw_fn,
void (*free)(void *));
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index f0d6072fdbc..573f9b4939b 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -54,7 +54,8 @@ typedef enum {
TFM_TILT,
TFM_TRACKBALL,
TFM_PUSHPULL,
- TFM_CREASE,
+ TFM_EDGE_CREASE,
+ TFM_VERT_CREASE,
TFM_MIRROR,
TFM_BONESIZE,
TFM_BONE_ENVELOPE,
@@ -104,16 +105,16 @@ void BIF_removeTransformOrientationIndex(struct bContext *C, int index);
bool BIF_createTransformOrientation(struct bContext *C,
struct ReportList *reports,
const char *name,
- const bool use_view,
- const bool activate,
- const bool overwrite);
+ bool use_view,
+ bool activate,
+ bool overwrite);
void BIF_selectTransformOrientation(struct bContext *C, struct TransformOrientation *target);
void ED_getTransformOrientationMatrix(struct ViewLayer *view_layer,
const struct View3D *v3d,
struct Object *ob,
struct Object *obedit,
- const short around,
+ short around,
float r_orientation_mat[3][3]);
int BIF_countTransformOrientation(const struct bContext *C);
@@ -161,8 +162,8 @@ short ED_transform_calc_orientation_from_type_ex(const struct Scene *scene,
const struct RegionView3D *rv3d,
struct Object *ob,
struct Object *obedit,
- const short orientation_index,
- const int pivot_point,
+ short orientation_index,
+ int pivot_point,
float r_mat[3][3]);
/* transform gizmos */
@@ -188,7 +189,7 @@ void ED_widgetgroup_gizmo2d_rotate_callbacks_set(struct wmGizmoGroupType *gzgt);
struct TransformBounds {
float center[3]; /* Center for transform widget. */
- float min[3], max[3]; /* Boundbox of selection for transform widget. */
+ float min[3], max[3]; /* Bounding-box of selection for transform widget. */
/* Normalized axis */
float axis[3][3];
diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h
index 6f25a63188d..fd65d8f3663 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -138,7 +138,7 @@ short ED_transform_snap_object_project_view3d_ex(struct SnapObjectContext *sctx,
struct Depsgraph *depsgraph,
const ARegion *region,
const View3D *v3d,
- const unsigned short snap_to,
+ unsigned short snap_to,
const struct SnapObjectParams *params,
const float mval[2],
const float prev_co[3],
@@ -166,7 +166,7 @@ short ED_transform_snap_object_project_view3d(struct SnapObjectContext *sctx,
struct Depsgraph *depsgraph,
const ARegion *region,
const View3D *v3d,
- const unsigned short snap_to,
+ unsigned short snap_to,
const struct SnapObjectParams *params,
const float mval[2],
const float prev_co[3],
diff --git a/source/blender/editors/include/ED_transverts.h b/source/blender/editors/include/ED_transverts.h
index 28955da6ef1..cbcf28d53d5 100644
--- a/source/blender/editors/include/ED_transverts.h
+++ b/source/blender/editors/include/ED_transverts.h
@@ -42,7 +42,7 @@ typedef struct TransVertStore {
int mode;
} TransVertStore;
-void ED_transverts_create_from_obedit(TransVertStore *tvs, struct Object *obedit, const int mode);
+void ED_transverts_create_from_obedit(TransVertStore *tvs, struct Object *obedit, int mode);
void ED_transverts_update_obedit(TransVertStore *tvs, struct Object *obedit);
void ED_transverts_free(TransVertStore *tvs);
bool ED_transverts_check_obedit(Object *obedit);
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index 69378d436ab..4e794838b2f 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -33,6 +33,7 @@ extern "C" {
struct GPUBatch;
struct Main;
struct bContext;
+struct IDRemapper;
/* ed_util.c */
@@ -60,10 +61,13 @@ bool ED_editors_flush_edits(struct Main *bmain);
*
* \param new_id: may be NULL to unlink \a old_id.
*/
+void ED_spacedata_id_remap_single(struct ScrArea *area,
+ struct SpaceLink *sl,
+ struct ID *old_id,
+ struct ID *new_id);
void ED_spacedata_id_remap(struct ScrArea *area,
struct SpaceLink *sl,
- struct ID *old_id,
- struct ID *new_id);
+ const struct IDRemapper *mappings);
void ED_operatortypes_edutils(void);
@@ -102,13 +106,13 @@ void ED_slider_destroy(struct bContext *C, struct tSlider *slider);
*/
void ED_slider_status_string_get(const struct tSlider *slider,
char *status_string,
- const size_t size_of_status_string);
+ size_t size_of_status_string);
float ED_slider_factor_get(struct tSlider *slider);
void ED_slider_factor_set(struct tSlider *slider, float factor);
bool ED_slider_allow_overshoot_get(struct tSlider *slider);
-void ED_slider_allow_overshoot_set(struct tSlider *slider, const bool value);
+void ED_slider_allow_overshoot_set(struct tSlider *slider, bool value);
/* ************** XXX OLD CRUFT WARNING ************* */
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index d5303904842..0af98fc367f 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -100,93 +100,87 @@ bool ED_uvedit_test(struct Object *obedit);
bool uvedit_face_visible_test_ex(const struct ToolSettings *ts, struct BMFace *efa);
bool uvedit_face_select_test_ex(const struct ToolSettings *ts,
struct BMFace *efa,
- const int cd_loop_uv_offset);
+ int cd_loop_uv_offset);
bool uvedit_edge_select_test_ex(const struct ToolSettings *ts,
struct BMLoop *l,
- const int cd_loop_uv_offset);
+ int cd_loop_uv_offset);
bool uvedit_uv_select_test_ex(const struct ToolSettings *ts,
struct BMLoop *l,
- const int cd_loop_uv_offset);
+ int cd_loop_uv_offset);
bool uvedit_face_visible_test(const struct Scene *scene, struct BMFace *efa);
-bool uvedit_face_select_test(const struct Scene *scene,
- struct BMFace *efa,
- const int cd_loop_uv_offset);
-bool uvedit_edge_select_test(const struct Scene *scene,
- struct BMLoop *l,
- const int cd_loop_uv_offset);
-bool uvedit_uv_select_test(const struct Scene *scene,
- struct BMLoop *l,
- const int cd_loop_uv_offset);
+bool uvedit_face_select_test(const struct Scene *scene, struct BMFace *efa, int cd_loop_uv_offset);
+bool uvedit_edge_select_test(const struct Scene *scene, struct BMLoop *l, int cd_loop_uv_offset);
+bool uvedit_uv_select_test(const struct Scene *scene, struct BMLoop *l, int cd_loop_uv_offset);
/* uv face */
void uvedit_face_select_set_with_sticky(const struct SpaceImage *sima,
const struct Scene *scene,
struct BMEditMesh *em,
struct BMFace *efa,
- const bool select,
- const bool do_history,
- const int cd_loop_uv_offset);
+ bool select,
+ bool do_history,
+ int cd_loop_uv_offset);
void uvedit_face_select_set(const struct Scene *scene,
struct BMEditMesh *em,
struct BMFace *efa,
- const bool select,
- const bool do_history,
- const int cd_loop_uv_offset);
+ bool select,
+ bool do_history,
+ int cd_loop_uv_offset);
void uvedit_face_select_enable(const struct Scene *scene,
struct BMEditMesh *em,
struct BMFace *efa,
- const bool do_history,
- const int cd_loop_uv_offset);
+ bool do_history,
+ int cd_loop_uv_offset);
void uvedit_face_select_disable(const struct Scene *scene,
struct BMEditMesh *em,
struct BMFace *efa,
- const int cd_loop_uv_offset);
+ int cd_loop_uv_offset);
/* uv edge */
void uvedit_edge_select_set_with_sticky(const struct SpaceImage *sima,
const struct Scene *scene,
struct BMEditMesh *em,
struct BMLoop *l,
- const bool select,
- const bool do_history,
- const uint cd_loop_uv_offset);
+ bool select,
+ bool do_history,
+ uint cd_loop_uv_offset);
void uvedit_edge_select_set(const struct Scene *scene,
struct BMEditMesh *em,
struct BMLoop *l,
- const bool select,
- const bool do_history,
- const int cd_loop_uv_offset);
+ bool select,
+ bool do_history,
+ int cd_loop_uv_offset);
void uvedit_edge_select_enable(const struct Scene *scene,
struct BMEditMesh *em,
struct BMLoop *l,
- const bool do_history,
- const int cd_loop_uv_offset);
+ bool do_history,
+ int cd_loop_uv_offset);
void uvedit_edge_select_disable(const struct Scene *scene,
struct BMEditMesh *em,
struct BMLoop *l,
- const int cd_loop_uv_offset);
+ int cd_loop_uv_offset);
/* uv vert */
void uvedit_uv_select_set_with_sticky(const struct SpaceImage *sima,
const struct Scene *scene,
struct BMEditMesh *em,
struct BMLoop *l,
- const bool select,
- const bool do_history,
- const uint cd_loop_uv_offset);
+ bool select,
+ bool do_history,
+ uint cd_loop_uv_offset);
void uvedit_uv_select_set(const struct Scene *scene,
struct BMEditMesh *em,
struct BMLoop *l,
- const bool select,
- const bool do_history,
- const int cd_loop_uv_offset);
+ bool select,
+ bool do_history,
+ int cd_loop_uv_offset);
void uvedit_uv_select_enable(const struct Scene *scene,
struct BMEditMesh *em,
struct BMLoop *l,
- const bool do_history,
- const int cd_loop_uv_offset);
+ bool do_history,
+ int cd_loop_uv_offset);
void uvedit_uv_select_disable(const struct Scene *scene,
struct BMEditMesh *em,
struct BMLoop *l,
- const int cd_loop_uv_offset);
+ int cd_loop_uv_offset);
bool ED_uvedit_nearest_uv(const struct Scene *scene,
struct Object *obedit,
@@ -195,7 +189,7 @@ bool ED_uvedit_nearest_uv(const struct Scene *scene,
float r_uv[2]);
bool ED_uvedit_nearest_uv_multi(const struct Scene *scene,
struct Object **objects,
- const uint objects_len,
+ uint objects_len,
const float co[2],
float *dist_sq,
float r_uv[2]);
@@ -228,7 +222,7 @@ struct BMLoop *ED_uvedit_active_edge_loop_get(struct BMesh *bm);
char ED_uvedit_select_mode_get(const struct Scene *scene);
void ED_uvedit_select_sync_flush(const struct ToolSettings *ts,
struct BMEditMesh *em,
- const bool select);
+ bool select);
/* uvedit_unwrap_ops.c */
@@ -278,7 +272,7 @@ bool uv_coords_isect_udim(const struct Image *image,
const float coords[2]);
void ED_uvedit_pack_islands_multi(const struct Scene *scene,
Object **objects,
- const uint objects_len,
+ uint objects_len,
const struct UVMapUDIM_Params *udim_params,
const struct UVPackIsland_Params *params);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 6c986d8efe1..0398c209c68 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -114,17 +114,17 @@ bool ED_view3d_has_workbench_in_texture_color(const struct Scene *scene,
*/
void ED_view3d_cursor3d_position(struct bContext *C,
const int mval[2],
- const bool use_depth,
+ bool use_depth,
float r_cursor_co[3]);
void ED_view3d_cursor3d_position_rotation(struct bContext *C,
const int mval[2],
- const bool use_depth,
+ bool use_depth,
enum eV3DCursorOrient orientation,
float r_cursor_co[3],
float r_cursor_quat[4]);
void ED_view3d_cursor3d_update(struct bContext *C,
const int mval[2],
- const bool use_depth,
+ bool use_depth,
enum eV3DCursorOrient orientation);
struct Camera *ED_view3d_camera_data_get(struct View3D *v3d, struct RegionView3D *rv3d);
@@ -137,7 +137,7 @@ struct Camera *ED_view3d_camera_data_get(struct View3D *v3d, struct RegionView3D
* \param quat: The view rotation, quaternion normally from #RegionView3D.viewquat.
* \param dist: The view distance from ofs, normally from #RegionView3D.dist.
*/
-void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist);
+void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], float dist);
/**
* Set the view transformation from a 4x4 matrix.
*
@@ -171,7 +171,7 @@ void ED_view3d_to_object(const struct Depsgraph *depsgraph,
struct Object *ob,
const float ofs[3],
const float quat[4],
- const float dist);
+ float dist);
bool ED_view3d_camera_to_view_selected(struct Main *bmain,
struct Depsgraph *depsgraph,
@@ -213,7 +213,7 @@ bool ED_view3d_depth_read_cached_normal(const struct ARegion *region,
float r_normal[3]);
bool ED_view3d_depth_unproject_v3(const struct ARegion *region,
const int mval[2],
- const double depth,
+ double depth,
float r_location_world[3]);
/* Projection */
@@ -280,7 +280,7 @@ typedef enum {
/* view3d_snap.c */
bool ED_view3d_snap_selected_to_location(struct bContext *C,
const float snap_target_global[3],
- const int pivot_point);
+ int pivot_point);
/* view3d_cursor_snap.c */
#define USE_SNAP_DETECT_FROM_KEYMAP_HACK
@@ -343,8 +343,8 @@ void ED_view3d_cursor_snap_deactive(V3DSnapCursorState *state);
void ED_view3d_cursor_snap_prevpoint_set(V3DSnapCursorState *state, const float prev_point[3]);
V3DSnapCursorData *ED_view3d_cursor_snap_data_get(V3DSnapCursorState *state,
const struct bContext *C,
- const int x,
- const int y);
+ int x,
+ int y);
struct SnapObjectContext *ED_view3d_cursor_snap_context_ensure(struct Scene *scene);
void ED_view3d_cursor_snap_draw_util(struct RegionView3D *rv3d,
const float loc_prev[3],
@@ -352,7 +352,7 @@ void ED_view3d_cursor_snap_draw_util(struct RegionView3D *rv3d,
const float normal[3],
const uchar color_line[4],
const uchar color_point[4],
- const short snap_elem_type);
+ short snap_elem_type);
/* view3d_iterators.c */
@@ -362,12 +362,12 @@ void meshobject_foreachScreenVert(
struct ViewContext *vc,
void (*func)(void *userData, struct MVert *eve, const float screen_co[2], int index),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
void mesh_foreachScreenVert(
struct ViewContext *vc,
void (*func)(void *userData, struct BMVert *eve, const float screen_co[2], int index),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
void mesh_foreachScreenEdge(struct ViewContext *vc,
void (*func)(void *userData,
struct BMEdge *eed,
@@ -375,7 +375,7 @@ void mesh_foreachScreenEdge(struct ViewContext *vc,
const float screen_co_b[2],
int index),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
/**
* A version of #mesh_foreachScreenEdge that clips the segment when
@@ -388,13 +388,13 @@ void mesh_foreachScreenEdge_clip_bb_segment(struct ViewContext *vc,
const float screen_co_b[2],
int index),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
void mesh_foreachScreenFace(
struct ViewContext *vc,
void (*func)(void *userData, struct BMFace *efa, const float screen_co[2], int index),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
void nurbs_foreachScreenVert(struct ViewContext *vc,
void (*func)(void *userData,
struct Nurb *nu,
@@ -404,7 +404,7 @@ void nurbs_foreachScreenVert(struct ViewContext *vc,
bool handle_visible,
const float screen_co[2]),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
/**
* #ED_view3d_init_mats_rv3d must be called first.
*/
@@ -413,13 +413,13 @@ void mball_foreachScreenElem(struct ViewContext *vc,
struct MetaElem *ml,
const float screen_co[2]),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
void lattice_foreachScreenVert(struct ViewContext *vc,
void (*func)(void *userData,
struct BPoint *bp,
const float screen_co[2]),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
/**
* #ED_view3d_init_mats_rv3d must be called first.
*/
@@ -429,7 +429,7 @@ void armature_foreachScreenBone(struct ViewContext *vc,
const float screen_co_a[2],
const float screen_co_b[2]),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
/**
* ED_view3d_init_mats_rv3d must be called first.
@@ -440,7 +440,7 @@ void pose_foreachScreenBone(struct ViewContext *vc,
const float screen_co_a[2],
const float screen_co_b[2]),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
/* *** end iterators *** */
/* view3d_project.c */
@@ -465,58 +465,58 @@ eV3DProjStatus ED_view3d_project_base(const struct ARegion *region, struct Base
/* *** short *** */
eV3DProjStatus ED_view3d_project_short_ex(const struct ARegion *region,
float perspmat[4][4],
- const bool is_local,
+ bool is_local,
const float co[3],
short r_co[2],
- const eV3DProjTest flag);
+ eV3DProjTest flag);
/* --- short --- */
eV3DProjStatus ED_view3d_project_short_global(const struct ARegion *region,
const float co[3],
short r_co[2],
- const eV3DProjTest flag);
+ eV3DProjTest flag);
/* object space, use ED_view3d_init_mats_rv3d before calling */
eV3DProjStatus ED_view3d_project_short_object(const struct ARegion *region,
const float co[3],
short r_co[2],
- const eV3DProjTest flag);
+ eV3DProjTest flag);
/* *** int *** */
eV3DProjStatus ED_view3d_project_int_ex(const struct ARegion *region,
float perspmat[4][4],
- const bool is_local,
+ bool is_local,
const float co[3],
int r_co[2],
- const eV3DProjTest flag);
+ eV3DProjTest flag);
/* --- int --- */
eV3DProjStatus ED_view3d_project_int_global(const struct ARegion *region,
const float co[3],
int r_co[2],
- const eV3DProjTest flag);
+ eV3DProjTest flag);
/* object space, use ED_view3d_init_mats_rv3d before calling */
eV3DProjStatus ED_view3d_project_int_object(const struct ARegion *region,
const float co[3],
int r_co[2],
- const eV3DProjTest flag);
+ eV3DProjTest flag);
/* *** float *** */
eV3DProjStatus ED_view3d_project_float_ex(const struct ARegion *region,
float perspmat[4][4],
- const bool is_local,
+ bool is_local,
const float co[3],
float r_co[2],
- const eV3DProjTest flag);
+ eV3DProjTest flag);
/* --- float --- */
eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *region,
const float co[3],
float r_co[2],
- const eV3DProjTest flag);
+ eV3DProjTest flag);
/**
* Object space, use #ED_view3d_init_mats_rv3d before calling.
*/
eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *region,
const float co[3],
float r_co[2],
- const eV3DProjTest flag);
+ eV3DProjTest flag);
float ED_view3d_pixel_size(const struct RegionView3D *rv3d, const float co[3]);
float ED_view3d_pixel_size_no_ui_scale(const struct RegionView3D *rv3d, const float co[3]);
@@ -550,7 +550,7 @@ bool ED_view3d_win_to_ray_clipped(struct Depsgraph *depsgraph,
const float mval[2],
float r_ray_start[3],
float r_ray_normal[3],
- const bool do_clip_planes);
+ bool do_clip_planes);
/**
* Calculate a 3d viewpoint and direction vector from 2d window coordinates.
* This ray_start is located at the viewpoint, ray_normal is the direction towards `mval`.
@@ -620,7 +620,7 @@ void ED_view3d_win_to_3d_int(const struct View3D *v3d,
bool ED_view3d_win_to_3d_on_plane(const struct ARegion *region,
const float plane[4],
const float mval[2],
- const bool do_clip,
+ bool do_clip,
float r_out[3]);
/**
* A wrapper for #ED_view3d_win_to_3d_on_plane that projects onto \a plane_fallback
@@ -632,13 +632,13 @@ bool ED_view3d_win_to_3d_on_plane(const struct ARegion *region,
bool ED_view3d_win_to_3d_on_plane_with_fallback(const struct ARegion *region,
const float plane[4],
const float mval[2],
- const bool do_clip,
+ bool do_clip,
const float plane_fallback[4],
float r_out[3]);
bool ED_view3d_win_to_3d_on_plane_int(const struct ARegion *region,
const float plane[4],
const int mval[2],
- const bool do_clip,
+ bool do_clip,
float r_out[3]);
/**
* Calculate a 3d difference vector from 2d window offset.
@@ -651,7 +651,7 @@ bool ED_view3d_win_to_3d_on_plane_int(const struct ARegion *region,
void ED_view3d_win_to_delta(const struct ARegion *region,
const float mval[2],
float out[3],
- const float zfac);
+ float zfac);
/**
* Calculate a 3d origin from 2d window coordinates.
* \note Orthographic views have a less obvious origin,
@@ -697,7 +697,7 @@ bool ED_view3d_win_to_segment_clipped(struct Depsgraph *depsgraph,
const float mval[2],
float r_ray_start[3],
float r_ray_end[3],
- const bool do_clip_planes);
+ bool do_clip_planes);
void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d,
const struct Object *ob,
float r_pmat[4][4]);
@@ -729,7 +729,7 @@ bool ED_view3d_clip_range_get(struct Depsgraph *depsgraph,
const struct RegionView3D *rv3d,
float *r_clipsta,
float *r_clipend,
- const bool use_ortho_factor);
+ bool use_ortho_factor);
bool ED_view3d_viewplane_get(struct Depsgraph *depsgraph,
const struct View3D *v3d,
const struct RegionView3D *rv3d,
@@ -743,7 +743,7 @@ bool ED_view3d_viewplane_get(struct Depsgraph *depsgraph,
/**
* Use instead of: `GPU_polygon_offset(rv3d->dist, ...)` see bug T37727.
*/
-void ED_view3d_polygon_offset(const struct RegionView3D *rv3d, const float dist);
+void ED_view3d_polygon_offset(const struct RegionView3D *rv3d, float dist);
void ED_view3d_calc_camera_border(const struct Scene *scene,
struct Depsgraph *depsgraph,
@@ -751,7 +751,7 @@ void ED_view3d_calc_camera_border(const struct Scene *scene,
const struct View3D *v3d,
const struct RegionView3D *rv3d,
struct rctf *r_viewborder,
- const bool no_shift);
+ bool no_shift);
void ED_view3d_calc_camera_border_size(const struct Scene *scene,
struct Depsgraph *depsgraph,
const struct ARegion *region,
@@ -766,7 +766,7 @@ bool ED_view3d_calc_render_border(const struct Scene *scene,
void ED_view3d_clipping_calc_from_boundbox(float clip[4][4],
const struct BoundBox *clipbb,
- const bool is_flip);
+ bool is_flip);
void ED_view3d_clipping_calc(struct BoundBox *bb,
float planes[4][4],
const struct ARegion *region,
@@ -796,12 +796,10 @@ void ED_view3d_clipping_local(struct RegionView3D *rv3d, const float mat[4][4]);
*
* \note Callers should check #RV3D_CLIPPING_ENABLED first.
*/
-bool ED_view3d_clipping_test(const struct RegionView3D *rv3d,
- const float co[3],
- const bool is_local);
+bool ED_view3d_clipping_test(const struct RegionView3D *rv3d, const float co[3], bool is_local);
-float ED_view3d_radius_to_dist_persp(const float angle, const float radius);
-float ED_view3d_radius_to_dist_ortho(const float lens, const float radius);
+float ED_view3d_radius_to_dist_persp(float angle, float radius);
+float ED_view3d_radius_to_dist_ortho(float lens, float radius);
/**
* Return a new #RegionView3D.dist value to fit the \a radius.
*
@@ -830,9 +828,9 @@ float ED_view3d_radius_to_dist_ortho(const float lens, const float radius);
float ED_view3d_radius_to_dist(const struct View3D *v3d,
const struct ARegion *region,
const struct Depsgraph *depsgraph,
- const char persp,
- const bool use_aspect,
- const float radius);
+ char persp,
+ bool use_aspect,
+ float radius);
/**
* Back-buffer select and draw support.
@@ -842,7 +840,7 @@ void ED_view3d_backbuf_depth_validate(struct ViewContext *vc);
* allow for small values [0.5 - 2.5],
* and large values, FLT_MAX by clamping by the area size
*/
-int ED_view3d_backbuf_sample_size_clamp(struct ARegion *region, const float dist);
+int ED_view3d_backbuf_sample_size_clamp(struct ARegion *region, float dist);
void ED_view3d_select_id_validate(struct ViewContext *vc);
@@ -859,7 +857,7 @@ bool ED_view3d_autodist(struct Depsgraph *depsgraph,
struct View3D *v3d,
const int mval[2],
float mouse_worldloc[3],
- const bool alphaoverride,
+ bool alphaoverride,
const float fallback_depth_pt[3]);
/**
@@ -919,7 +917,7 @@ int view3d_opengl_select_ex(struct ViewContext *vc,
const struct rcti *input,
eV3DSelectMode select_mode,
eV3DSelectObjectFilter select_filter,
- const bool do_material_slot_selection);
+ bool do_material_slot_selection);
int view3d_opengl_select(struct ViewContext *vc,
unsigned int *buffer,
unsigned int bufsize,
@@ -1004,7 +1002,7 @@ void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, struct RV3DMatrixSto
void ED_draw_object_facemap(struct Depsgraph *depsgraph,
struct Object *ob,
const float col[4],
- const int facemap);
+ int facemap);
struct RenderEngineType *ED_view3d_engine_type(const struct Scene *scene, int drawtype);
@@ -1046,9 +1044,9 @@ void ED_view3d_update_viewmat(struct Depsgraph *depsgraph,
const float winmat[4][4],
const struct rcti *rect,
bool offscreen);
-bool ED_view3d_quat_from_axis_view(const char view, const char view_axis_roll, float r_quat[4]);
+bool ED_view3d_quat_from_axis_view(char view, char view_axis_roll, float r_quat[4]);
bool ED_view3d_quat_to_axis_view(const float viewquat[4],
- const float epsilon,
+ float epsilon,
char *r_view,
char *r_view_axis_rotation);
@@ -1079,7 +1077,7 @@ bool ED_view3d_offset_lock_check(const struct View3D *v3d, const struct RegionVi
void ED_view3d_persp_switch_from_camera(const struct Depsgraph *depsgraph,
struct View3D *v3d,
struct RegionView3D *rv3d,
- const char persp);
+ char persp);
/**
* Action to take when rotating the view,
* handle auto-perspective and logic for switching out of views.
@@ -1105,7 +1103,7 @@ bool ED_view3d_camera_lock_check(const struct View3D *v3d, const struct RegionVi
void ED_view3d_camera_lock_init_ex(const struct Depsgraph *depsgraph,
struct View3D *v3d,
struct RegionView3D *rv3d,
- const bool calc_dist);
+ bool calc_dist);
void ED_view3d_camera_lock_init(const struct Depsgraph *depsgraph,
struct View3D *v3d,
struct RegionView3D *rv3d);
@@ -1123,8 +1121,8 @@ bool ED_view3d_camera_lock_sync(const struct Depsgraph *depsgraph,
bool ED_view3d_camera_autokey(const struct Scene *scene,
struct ID *id_key,
struct bContext *C,
- const bool do_rotate,
- const bool do_translate);
+ bool do_rotate,
+ bool do_translate);
/**
* Call after modifying a locked view.
*
@@ -1134,8 +1132,8 @@ bool ED_view3d_camera_autokey(const struct Scene *scene,
bool ED_view3d_camera_lock_autokey(struct View3D *v3d,
struct RegionView3D *rv3d,
struct bContext *C,
- const bool do_rotate,
- const bool do_translate);
+ bool do_rotate,
+ bool do_translate);
void ED_view3d_lock_clear(struct View3D *v3d);
@@ -1154,15 +1152,13 @@ void ED_view3d_lock_clear(struct View3D *v3d);
* \param fallback_dist: The distance to use if the object is too near or in front of \a ofs.
* \returns A newly calculated distance or the fallback.
*/
-float ED_view3d_offset_distance(const float mat[4][4],
- const float ofs[3],
- const float fallback_dist);
+float ED_view3d_offset_distance(const float mat[4][4], const float ofs[3], float fallback_dist);
/**
* Set the dist without moving the view (compensate with #RegionView3D.ofs)
*
* \note take care that #RegionView3d.viewinv is up to date, #ED_view3d_update_viewmat first.
*/
-void ED_view3d_distance_set(struct RegionView3D *rv3d, const float dist);
+void ED_view3d_distance_set(struct RegionView3D *rv3d, float dist);
/**
* Change the distance & offset to match the depth of \a dist_co along the view axis.
*
@@ -1172,7 +1168,7 @@ void ED_view3d_distance_set(struct RegionView3D *rv3d, const float dist);
*/
bool ED_view3d_distance_set_from_location(struct RegionView3D *rv3d,
const float dist_co[3],
- const float dist_min);
+ float dist_min);
/**
* Could move this elsewhere, but tied into #ED_view3d_grid_scale
@@ -1223,8 +1219,8 @@ void ED_view3d_draw_bgpic_test(const struct Scene *scene,
struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
- const bool do_foreground,
- const bool do_camera_frame);
+ bool do_foreground,
+ bool do_camera_frame);
/* view3d_gizmo_preselect_type.c */
@@ -1247,12 +1243,10 @@ void ED_view3d_buttons_region_layout_ex(const struct bContext *C,
* Try to keep the same UUID previously used to allow users to quickly toggle back and forth.
*/
bool ED_view3d_local_collections_set(struct Main *bmain, struct View3D *v3d);
-void ED_view3d_local_collections_reset(struct bContext *C, const bool reset_all);
+void ED_view3d_local_collections_reset(struct bContext *C, bool reset_all);
#ifdef WITH_XR_OPENXR
-void ED_view3d_xr_mirror_update(const struct ScrArea *area,
- const struct View3D *v3d,
- const bool enable);
+void ED_view3d_xr_mirror_update(const struct ScrArea *area, const struct View3D *v3d, bool enable);
void ED_view3d_xr_shading_update(struct wmWindowManager *wm,
const View3D *v3d,
const struct Scene *scene);
diff --git a/source/blender/editors/include/ED_view3d_offscreen.h b/source/blender/editors/include/ED_view3d_offscreen.h
index 1da0a282697..ae2329c457b 100644
--- a/source/blender/editors/include/ED_view3d_offscreen.h
+++ b/source/blender/editors/include/ED_view3d_offscreen.h
@@ -53,8 +53,8 @@ void ED_view3d_draw_offscreen(struct Depsgraph *depsgraph,
bool is_image_render,
bool draw_background,
const char *viewname,
- const bool do_color_management,
- const bool restore_rv3d_mats,
+ bool do_color_management,
+ bool restore_rv3d_mats,
struct GPUOffScreen *ofs,
struct GPUViewport *viewport);
/**
@@ -76,7 +76,7 @@ void ED_view3d_draw_offscreen_simple(struct Depsgraph *depsgraph,
bool is_image_render,
bool draw_background,
const char *viewname,
- const bool do_color_management,
+ bool do_color_management,
struct GPUOffScreen *ofs,
struct GPUViewport *viewport);
@@ -96,7 +96,7 @@ struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Depsgraph *depsgraph,
eImBufFlags imbuf_flag,
int alpha_mode,
const char *viewname,
- const bool restore_rv3d_mats,
+ bool restore_rv3d_mats,
struct GPUOffScreen *ofs,
char err_out[256]);
/**
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index ba83b259267..3796fa51499 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -494,9 +494,9 @@ void UI_draw_widget_scroll(struct uiWidgetColors *wcol,
float UI_text_clip_middle_ex(const struct uiFontStyle *fstyle,
char *str,
float okwidth,
- const float minwidth,
- const size_t max_len,
- const char rpart_sep);
+ float minwidth,
+ size_t max_len,
+ char rpart_sep);
/**
* Callbacks
@@ -531,11 +531,8 @@ typedef struct ARegion *(*uiButSearchCreateFn)(struct bContext *C,
* to display the full list of options. The value will be false after the button's text is edited
* (for every call except the first).
*/
-typedef void (*uiButSearchUpdateFn)(const struct bContext *C,
- void *arg,
- const char *str,
- uiSearchItems *items,
- const bool is_first);
+typedef void (*uiButSearchUpdateFn)(
+ const struct bContext *C, void *arg, const char *str, uiSearchItems *items, bool is_first);
typedef bool (*uiButSearchContextMenuFn)(struct bContext *C,
void *arg,
void *active,
@@ -621,7 +618,7 @@ bool UI_but_is_tool(const uiBut *but);
bool UI_but_is_utf8(const uiBut *but);
#define UI_but_is_decorator(but) ((but)->type == UI_BTYPE_DECORATOR)
-bool UI_block_is_empty_ex(const uiBlock *block, const bool skip_title);
+bool UI_block_is_empty_ex(const uiBlock *block, bool skip_title);
bool UI_block_is_empty(const uiBlock *block);
bool UI_block_can_add_separator(const uiBlock *block);
@@ -662,7 +659,7 @@ int UI_popup_menu_invoke(struct bContext *C, const char *idname, struct ReportLi
* Allow setting menu return value from externals.
* E.g. WM might need to do this for exiting files correctly.
*/
-void UI_popup_menu_retval_set(const uiBlock *block, const int retval, const bool enable);
+void UI_popup_menu_retval_set(const uiBlock *block, int retval, bool enable);
/**
* Setting the button makes the popup open from the button instead of the cursor.
*/
@@ -866,7 +863,7 @@ void UI_but_drag_set_id(uiBut *but, struct ID *id);
* Set an image to display while dragging. This works for any drag type (`WM_DRAG_XXX`).
* Not to be confused with #UI_but_drag_set_image(), which sets up dragging of an image.
*/
-void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, const float scale);
+void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, float scale);
/**
* \param asset: May be passed from a temporary variable, drag data only stores a copy of this.
*/
@@ -879,14 +876,14 @@ void UI_but_drag_set_asset(uiBut *but,
struct ImBuf *imb,
float scale);
void UI_but_drag_set_rna(uiBut *but, struct PointerRNA *ptr);
-void UI_but_drag_set_path(uiBut *but, const char *path, const bool use_free);
+void UI_but_drag_set_path(uiBut *but, const char *path, bool use_free);
void UI_but_drag_set_name(uiBut *but, const char *name);
/**
* Value from button itself.
*/
void UI_but_drag_set_value(uiBut *but);
void UI_but_drag_set_image(
- uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale, const bool use_free);
+ uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale, bool use_free);
uiBut *UI_but_active_drop_name_button(const struct bContext *C);
/**
@@ -918,7 +915,7 @@ bool UI_but_active_only_ex(const struct bContext *C,
struct ARegion *region,
uiBlock *block,
uiBut *but,
- const bool remove_on_failure);
+ bool remove_on_failure);
bool UI_but_active_only(const struct bContext *C,
struct ARegion *region,
uiBlock *block,
@@ -982,21 +979,6 @@ uiBut *uiDefButF(uiBlock *block,
float a1,
float a2,
const char *tip);
-uiBut *uiDefButBitF(uiBlock *block,
- int type,
- int bit,
- int retval,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
uiBut *uiDefButI(uiBlock *block,
int type,
int retval,
@@ -1154,35 +1136,6 @@ uiBut *uiDefIconBut(uiBlock *block,
float a1,
float a2,
const char *tip);
-uiBut *uiDefIconButF(uiBlock *block,
- int type,
- int retval,
- int icon,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
-uiBut *uiDefIconButBitF(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
uiBut *uiDefIconButI(uiBlock *block,
int type,
int retval,
@@ -1241,20 +1194,6 @@ uiBut *uiDefIconButBitS(uiBlock *block,
float a1,
float a2,
const char *tip);
-uiBut *uiDefIconButC(uiBlock *block,
- int type,
- int retval,
- int icon,
- int x,
- int y,
- short width,
- short height,
- char *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
uiBut *uiDefIconButBitC(uiBlock *block,
int type,
int bit,
@@ -1356,22 +1295,6 @@ uiBut *uiDefIconTextButF(uiBlock *block,
float a1,
float a2,
const char *tip);
-uiBut *uiDefIconTextButBitF(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
uiBut *uiDefIconTextButI(uiBlock *block,
int type,
int retval,
@@ -1387,84 +1310,6 @@ uiBut *uiDefIconTextButI(uiBlock *block,
float a1,
float a2,
const char *tip);
-uiBut *uiDefIconTextButBitI(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- int *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
-uiBut *uiDefIconTextButS(uiBlock *block,
- int type,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- short *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
-uiBut *uiDefIconTextButBitS(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- short *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
-uiBut *uiDefIconTextButC(uiBlock *block,
- int type,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- char *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
-uiBut *uiDefIconTextButBitC(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- char *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
uiBut *uiDefIconTextButR(uiBlock *block,
int type,
int retval,
@@ -1525,7 +1370,7 @@ uiBut *uiDefIconTextButO_ptr(uiBlock *block,
/* for passing inputs to ButO buttons */
struct PointerRNA *UI_but_operator_ptr_get(uiBut *but);
-void UI_but_unit_type_set(uiBut *but, const int unit_type);
+void UI_but_unit_type_set(uiBut *but, int unit_type);
int UI_but_unit_type_get(const uiBut *but);
typedef enum uiStringInfoType {
@@ -1793,7 +1638,7 @@ eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout,
void *user_data,
struct PropertyRNA *prop_activate_init,
eButLabelAlign label_align,
- const bool compact);
+ bool compact);
/**
* Public function exported for functions that use #UI_BTYPE_SEARCH_MENU.
@@ -1813,7 +1658,7 @@ bool UI_search_item_add(uiSearchItems *items,
void *poin,
int iconid,
int state,
- const uint8_t name_prefix_offset);
+ uint8_t name_prefix_offset);
/**
* \note The item-pointer (referred to below) is a per search item user pointer
@@ -1834,7 +1679,7 @@ void UI_but_func_search_set(uiBut *but,
uiButSearchCreateFn search_create_fn,
uiButSearchUpdateFn search_update_fn,
void *arg,
- const bool free_arg,
+ bool free_arg,
uiFreeArgFunc search_arg_free_fn,
uiButHandleFunc search_exec_fn,
void *active);
@@ -1845,7 +1690,7 @@ void UI_but_func_search_set_tooltip(uiBut *but, uiButSearchTooltipFn tooltip_fn)
* showing the icon and highlighted text after the last instance of this string.
*/
void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string);
-void UI_but_func_search_set_results_are_suggestions(uiBut *but, const bool value);
+void UI_but_func_search_set_results_are_suggestions(uiBut *but, bool value);
/**
* Height in pixels, it's using hard-coded values still.
@@ -2070,7 +1915,7 @@ void UI_region_handlers_add(struct ListBase *handlers);
void UI_popup_handlers_add(struct bContext *C,
struct ListBase *handlers,
uiPopupBlockHandle *popup,
- const char flag);
+ char flag);
void UI_popup_handlers_remove(struct ListBase *handlers, uiPopupBlockHandle *popup);
void UI_popup_handlers_remove_all(struct bContext *C, struct ListBase *handlers);
@@ -2196,6 +2041,7 @@ uiLayout *UI_block_layout(uiBlock *block,
const struct uiStyle *style);
void UI_block_layout_set_current(uiBlock *block, uiLayout *layout);
void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y);
+bool UI_block_layout_needs_resolving(const uiBlock *block);
/**
* Used for property search when the layout process needs to be cancelled in order to avoid
* computing the locations for buttons, but the layout items created while adding the buttons
@@ -2319,7 +2165,7 @@ void uiTemplateID(uiLayout *layout,
const char *openop,
const char *unlinkop,
int filter,
- const bool live_icon,
+ bool live_icon,
const char *text);
void uiTemplateIDBrowse(uiLayout *layout,
struct bContext *C,
@@ -2340,7 +2186,7 @@ void uiTemplateIDPreview(uiLayout *layout,
int rows,
int cols,
int filter,
- const bool hide_buttons);
+ bool hide_buttons);
/**
* Version of #uiTemplateID using tabs.
*/
@@ -2384,8 +2230,8 @@ void uiTemplateSearchPreview(uiLayout *layout,
const char *searchpropname,
const char *newop,
const char *unlinkop,
- const int rows,
- const int cols);
+ int rows,
+ int cols);
/**
* This is creating/editing RNA-Paths
*
@@ -2544,11 +2390,49 @@ void uiTemplateComponentMenu(uiLayout *layout,
const char *propname,
const char *name);
void uiTemplateNodeSocket(uiLayout *layout, struct bContext *C, float color[4]);
+
+/**
+ * Draw the main CacheFile properties and operators (file path, scale, etc.), that is those which
+ * do not have their own dedicated template functions.
+ */
void uiTemplateCacheFile(uiLayout *layout,
const struct bContext *C,
struct PointerRNA *ptr,
const char *propname);
+/**
+ * Lookup the CacheFile PointerRNA of the given pointer and return it in the output parameter.
+ * Returns true if `ptr` has a RNACacheFile, false otherwise. If false, the output parameter is not
+ * initialized.
+ */
+bool uiTemplateCacheFilePointer(struct PointerRNA *ptr,
+ const char *propname,
+ struct PointerRNA *r_file_ptr);
+
+/**
+ * Draw the velocity related properties of the CacheFile.
+ */
+void uiTemplateCacheFileVelocity(uiLayout *layout, struct PointerRNA *fileptr);
+
+/**
+ * Draw the render procedural related properties of the CacheFile.
+ */
+void uiTemplateCacheFileProcedural(uiLayout *layout,
+ const struct bContext *C,
+ struct PointerRNA *fileptr);
+
+/**
+ * Draw the time related properties of the CacheFile.
+ */
+void uiTemplateCacheFileTimeSettings(uiLayout *layout, struct PointerRNA *fileptr);
+
+/**
+ * Draw the override layers related properties of the CacheFile.
+ */
+void uiTemplateCacheFileLayers(uiLayout *layout,
+ const struct bContext *C,
+ struct PointerRNA *fileptr);
+
/* Default UIList class name, keep in sync with its declaration in bl_ui/__init__.py */
#define UI_UL_DEFAULT_CLASS_NAME "UI_UL_list"
enum uiTemplateListFlags {
@@ -2661,7 +2545,7 @@ void uiTemplateAssetView(struct uiLayout *layout,
struct PointerRNA *active_dataptr,
const char *active_propname,
const struct AssetFilterSettings *filter_settings,
- const int display_flags,
+ int display_flags,
const char *activate_opname,
struct PointerRNA *r_activate_op_properties,
const char *drag_opname,
@@ -2870,8 +2754,7 @@ typedef struct uiPropertySplitWrapper {
uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout);
void uiItemL(uiLayout *layout, const char *name, int icon); /* label */
-void uiItemL_ex(
- uiLayout *layout, const char *name, int icon, const bool highlight, const bool redalert);
+void uiItemL_ex(uiLayout *layout, const char *name, int icon, bool highlight, bool redalert);
/**
* Helper to add a label and creates a property split layout if needed.
*/
@@ -2982,7 +2865,7 @@ const char *UI_layout_introspect(uiLayout *layout);
* Helper to add a big icon and create a split layout for alert popups.
* Returns the layout to place further items into the alert box.
*/
-uiLayout *uiItemsAlertBox(uiBlock *block, const int size, const eAlertIcon icon);
+uiLayout *uiItemsAlertBox(uiBlock *block, int size, eAlertIcon icon);
/* UI Operators */
typedef struct uiDragColorHandle {
@@ -3007,6 +2890,13 @@ bool UI_context_copy_to_selected_list(struct bContext *C,
struct ListBase *r_lb,
bool *r_use_path_from_id,
char **r_path);
+bool UI_context_copy_to_selected_check(struct PointerRNA *ptr,
+ struct PointerRNA *ptr_link,
+ struct PropertyRNA *prop,
+ const char *path,
+ bool use_path_from_id,
+ struct PointerRNA *r_ptr,
+ struct PropertyRNA **r_prop);
/* Helpers for Operators */
uiBut *UI_context_active_but_get(const struct bContext *C);
@@ -3074,15 +2964,17 @@ void UI_fontstyle_set(const struct uiFontStyle *fs);
void UI_fontstyle_draw_ex(const struct uiFontStyle *fs,
const struct rcti *rect,
const char *str,
+ size_t str_len,
const uchar col[4],
const struct uiFontStyleDraw_Params *fs_params,
- size_t len,
int *r_xofs,
int *r_yofs,
struct ResultBLF *r_info);
+
void UI_fontstyle_draw(const struct uiFontStyle *fs,
const struct rcti *rect,
const char *str,
+ size_t str_len,
const uchar col[4],
const struct uiFontStyleDraw_Params *fs_params);
/**
@@ -3124,7 +3016,7 @@ int UI_fontstyle_string_width(const struct uiFontStyle *fs,
*/
int UI_fontstyle_string_width_with_block_aspect(const struct uiFontStyle *fs,
const char *str,
- const float aspect) ATTR_WARN_UNUSED_RESULT
+ float aspect) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2);
int UI_fontstyle_height_max(const struct uiFontStyle *fs);
diff --git a/source/blender/editors/include/UI_interface.hh b/source/blender/editors/include/UI_interface.hh
index d18ec009108..8d1ca54b7a1 100644
--- a/source/blender/editors/include/UI_interface.hh
+++ b/source/blender/editors/include/UI_interface.hh
@@ -31,8 +31,8 @@ namespace blender::nodes::geometry_nodes_eval_log {
struct GeometryAttributeInfo;
}
-struct uiBlock;
struct StructRNA;
+struct uiBlock;
struct uiSearchItems;
namespace blender::ui {
@@ -59,10 +59,10 @@ void template_breadcrumbs(uiLayout &layout, Span<ContextPathItem> context_path);
void attribute_search_add_items(
StringRefNull str,
- const bool is_output,
+ bool is_output,
Span<const nodes::geometry_nodes_eval_log::GeometryAttributeInfo *> infos,
uiSearchItems *items,
- const bool is_first);
+ bool is_first);
} // namespace blender::ui
diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h
index 242b8504ae1..1009ae5cd3f 100644
--- a/source/blender/editors/include/UI_interface_icons.h
+++ b/source/blender/editors/include/UI_interface_icons.h
@@ -82,13 +82,27 @@ int UI_icon_get_height(int icon_id);
bool UI_icon_get_theme_color(int icon_id, unsigned char color[4]);
/**
+ * Render a #PreviewImage for the data block.
+ *
* Note that if an ID doesn't support jobs for preview creation, \a use_job will be ignored.
*/
void UI_icon_render_id(const struct bContext *C,
struct Scene *scene,
struct ID *id,
- const enum eIconSizes size,
- const bool use_job);
+ enum eIconSizes size,
+ bool use_job);
+
+/**
+ * Render the data block into the provided #PreviewImage.
+ */
+void UI_icon_render_id_ex(const struct bContext *C,
+ struct Scene *scene,
+ struct ID *id_to_render,
+ const enum eIconSizes size,
+ const bool use_job,
+ struct PreviewImage *r_preview_image);
+
+
/**
* Render size for preview images and icons
*/
@@ -108,7 +122,7 @@ void UI_icon_draw_ex(float x,
float alpha,
float desaturate,
const uchar mono_color[4],
- const bool mono_border);
+ bool mono_border);
void UI_icons_free(void);
void UI_icons_free_drawinfo(void *drawinfo);
@@ -121,13 +135,10 @@ int UI_iconfile_get_index(const char *filename);
struct PreviewImage *UI_icon_to_preview(int icon_id);
-int UI_icon_from_rnaptr(const struct bContext *C,
- struct PointerRNA *ptr,
- int rnaicon,
- const bool big);
-int UI_icon_from_idcode(const int idcode);
+int UI_icon_from_rnaptr(const struct bContext *C, struct PointerRNA *ptr, int rnaicon, bool big);
+int UI_icon_from_idcode(int idcode);
int UI_icon_from_library(const struct ID *id);
-int UI_icon_from_object_mode(const int mode);
+int UI_icon_from_object_mode(int mode);
int UI_icon_color_from_collection(const struct Collection *collection);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index 98e141c65b5..40e4d8cee9c 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -502,7 +502,7 @@ int UI_ThemeMenuShadowWidth(void);
*/
const unsigned char *UI_ThemeGetColorPtr(struct bTheme *btheme, int spacetype, int colorid);
-void UI_make_axis_color(const unsigned char src_col[3], unsigned char dst_col[3], const char axis);
+void UI_make_axis_color(const unsigned char src_col[3], unsigned char dst_col[3], char axis);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/UI_tree_view.hh b/source/blender/editors/include/UI_tree_view.hh
index 8208f8daf5d..8dee88defb3 100644
--- a/source/blender/editors/include/UI_tree_view.hh
+++ b/source/blender/editors/include/UI_tree_view.hh
@@ -40,8 +40,8 @@ struct uiBlock;
struct uiBut;
struct uiButTreeRow;
struct uiLayout;
-struct wmEvent;
struct wmDrag;
+struct wmEvent;
namespace blender::ui {
diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h
index 37246c2fe8f..a3f39e1286e 100644
--- a/source/blender/editors/include/UI_view2d.h
+++ b/source/blender/editors/include/UI_view2d.h
@@ -175,7 +175,7 @@ void UI_view2d_view_ortho(const struct View2D *v2d);
* \param xaxis: if non-zero, only use cur x-axis,
* otherwise use cur-yaxis (mostly this will be used for x).
*/
-void UI_view2d_view_orthoSpecial(struct ARegion *region, struct View2D *v2d, const bool xaxis);
+void UI_view2d_view_orthoSpecial(struct ARegion *region, struct View2D *v2d, bool xaxis);
/**
* Restore view matrices after drawing.
*/
@@ -435,7 +435,7 @@ void ED_keymap_view2d(struct wmKeyConfig *keyconf);
void UI_view2d_smooth_view(struct bContext *C,
struct ARegion *region,
const struct rctf *cur,
- const int smooth_viewtx);
+ int smooth_viewtx);
#define UI_MARKER_MARGIN_Y (42 * UI_DPI_FAC)
#define UI_TIME_SCRUB_MARGIN_Y (23 * UI_DPI_FAC)
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index bc3075f9de8..95c9f7cc8b2 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -24,8 +24,8 @@ set(INC
../../blentranslation
../../depsgraph
../../draw
- ../../gpu
../../functions
+ ../../gpu
../../imbuf
../../makesdna
../../makesrna
@@ -71,8 +71,8 @@ set(SRC
interface_regions.c
interface_style.c
interface_template_asset_view.cc
- interface_template_list.cc
interface_template_attribute_search.cc
+ interface_template_list.cc
interface_template_search_menu.cc
interface_template_search_operator.c
interface_templates.c
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index df508b87ce4..636281ba373 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -661,8 +661,43 @@ static float ui_but_get_float_precision(uiBut *but)
return but->a2;
}
+static float ui_but_get_float_step_size(uiBut *but)
+{
+ if (but->type == UI_BTYPE_NUM) {
+ return ((uiButNumber *)but)->step_size;
+ }
+
+ return but->a1;
+}
+
+static bool ui_but_hide_fraction(uiBut *but, double value)
+{
+ /* Hide the fraction if both the value and the step are exact integers. */
+ if (floor(value) == value) {
+ const float step = ui_but_get_float_step_size(but) * UI_PRECISION_FLOAT_SCALE;
+
+ if (floorf(step) == step) {
+ /* Don't hide if it has any unit except frame count. */
+ switch (UI_but_unit_type_get(but)) {
+ case PROP_UNIT_NONE:
+ case PROP_UNIT_TIME:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+ }
+
+ return false;
+}
+
static int ui_but_calc_float_precision(uiBut *but, double value)
{
+ if (ui_but_hide_fraction(but, value)) {
+ return 0;
+ }
+
int prec = (int)ui_but_get_float_precision(but);
/* first check for various special cases:
@@ -2813,8 +2848,14 @@ void ui_but_string_get_ex(uiBut *but,
}
if (ui_but_is_float(but)) {
- int prec = (float_precision == -1) ? ui_but_calc_float_precision(but, value) :
- float_precision;
+ int prec = float_precision;
+
+ if (float_precision == -1) {
+ prec = ui_but_calc_float_precision(but, value);
+ }
+ else if (!use_exp_float && ui_but_hide_fraction(but, value)) {
+ prec = 0;
+ }
if (ui_but_is_unit(but)) {
ui_get_but_string_unit(but, str, maxlen, value, false, prec);
@@ -4859,7 +4900,7 @@ int UI_autocomplete_end(AutoComplete *autocpl, char *autoname)
BLI_strncpy(autoname, autocpl->truncate, autocpl->maxlen);
}
else {
- if (autoname != autocpl->startname) { /* don't copy a string over its self */
+ if (autoname != autocpl->startname) { /* don't copy a string over itself */
BLI_strncpy(autoname, autocpl->startname, autocpl->maxlen);
}
}
@@ -4943,38 +4984,6 @@ uiBut *uiDefButF(uiBlock *block,
a2,
tip);
}
-uiBut *uiDefButBitF(uiBlock *block,
- int type,
- int bit,
- int retval,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefButBit(block,
- type | UI_BUT_POIN_FLOAT,
- bit,
- retval,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
uiBut *uiDefButI(uiBlock *block,
int type,
int retval,
@@ -5295,68 +5304,6 @@ static uiBut *uiDefIconButBit(uiBlock *block,
tip);
}
-uiBut *uiDefIconButF(uiBlock *block,
- int type,
- int retval,
- int icon,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconBut(block,
- type | UI_BUT_POIN_FLOAT,
- retval,
- icon,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
-uiBut *uiDefIconButBitF(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconButBit(block,
- type | UI_BUT_POIN_FLOAT,
- bit,
- retval,
- icon,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
uiBut *uiDefIconButI(uiBlock *block,
int type,
int retval,
@@ -5481,36 +5428,6 @@ uiBut *uiDefIconButBitS(uiBlock *block,
a2,
tip);
}
-uiBut *uiDefIconButC(uiBlock *block,
- int type,
- int retval,
- int icon,
- int x,
- int y,
- short width,
- short height,
- char *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconBut(block,
- type | UI_BUT_POIN_CHAR,
- retval,
- icon,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
uiBut *uiDefIconButBitC(uiBlock *block,
int type,
int bit,
@@ -5640,44 +5557,6 @@ uiBut *uiDefIconTextBut(uiBlock *block,
but->drawflag |= UI_BUT_ICON_LEFT;
return but;
}
-static uiBut *uiDefIconTextButBit(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- void *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- const int bitIdx = findBitIndex(bit);
- if (bitIdx == -1) {
- return NULL;
- }
- return uiDefIconTextBut(block,
- type | UI_BUT_POIN_BIT | bitIdx,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
-
uiBut *uiDefIconTextButF(uiBlock *block,
int type,
int retval,
@@ -5710,40 +5589,6 @@ uiBut *uiDefIconTextButF(uiBlock *block,
a2,
tip);
}
-uiBut *uiDefIconTextButBitF(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconTextButBit(block,
- type | UI_BUT_POIN_FLOAT,
- bit,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
uiBut *uiDefIconTextButI(uiBlock *block,
int type,
int retval,
@@ -5776,172 +5621,6 @@ uiBut *uiDefIconTextButI(uiBlock *block,
a2,
tip);
}
-uiBut *uiDefIconTextButBitI(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- int *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconTextButBit(block,
- type | UI_BUT_POIN_INT,
- bit,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
-uiBut *uiDefIconTextButS(uiBlock *block,
- int type,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- short *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconTextBut(block,
- type | UI_BUT_POIN_SHORT,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
-uiBut *uiDefIconTextButBitS(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- short *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconTextButBit(block,
- type | UI_BUT_POIN_SHORT,
- bit,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
-uiBut *uiDefIconTextButC(uiBlock *block,
- int type,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- char *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconTextBut(block,
- type | UI_BUT_POIN_CHAR,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
-uiBut *uiDefIconTextButBitC(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- char *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconTextButBit(block,
- type | UI_BUT_POIN_CHAR,
- bit,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
uiBut *uiDefIconTextButR(uiBlock *block,
int type,
int retval,
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 285c82b0fb3..f7492e56b62 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -57,6 +57,7 @@
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
#include "GPU_matrix.h"
+#include "GPU_shader_shared.h"
#include "GPU_state.h"
#include "UI_interface.h"
@@ -324,17 +325,17 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(region),
}
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- immDrawPixelsTex(&state,
- (float)rect->xmin,
- (float)rect->ymin,
- ibuf->x,
- ibuf->y,
- GPU_RGBA8,
- false,
- ibuf->rect,
- 1.0f,
- 1.0f,
- col);
+ immDrawPixelsTexTiled(&state,
+ (float)rect->xmin,
+ (float)rect->ymin,
+ ibuf->x,
+ ibuf->y,
+ GPU_RGBA8,
+ false,
+ ibuf->rect,
+ 1.0f,
+ 1.0f,
+ col);
GPU_blend(GPU_BLEND_NONE);
@@ -1384,10 +1385,16 @@ void ui_draw_but_UNITVEC(uiBut *but,
GPU_matrix_scale_1f(size);
GPUBatch *sphere = GPU_batch_preset_sphere(2);
+ struct SimpleLightingData simple_lighting_data;
+ copy_v4_fl4(simple_lighting_data.color, diffuse[0], diffuse[1], diffuse[2], 1.0f);
+ copy_v3_v3(simple_lighting_data.light, light);
+ GPUUniformBuf *ubo = GPU_uniformbuf_create_ex(
+ sizeof(struct SimpleLightingData), &simple_lighting_data, __func__);
+
GPU_batch_program_set_builtin(sphere, GPU_SHADER_SIMPLE_LIGHTING);
- GPU_batch_uniform_4f(sphere, "color", diffuse[0], diffuse[1], diffuse[2], 1.0f);
- GPU_batch_uniform_3fv(sphere, "light", light);
+ GPU_batch_uniformbuf_bind(sphere, "simple_lighting_data", ubo);
GPU_batch_draw(sphere);
+ GPU_uniformbuf_free(ubo);
/* Restore. */
GPU_face_culling(GPU_CULL_NONE);
@@ -2128,17 +2135,17 @@ void ui_draw_but_TRACKPREVIEW(ARegion *UNUSED(region),
}
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- immDrawPixelsTex(&state,
- rect.xmin,
- rect.ymin + 1,
- drawibuf->x,
- drawibuf->y,
- GPU_RGBA8,
- true,
- drawibuf->rect,
- 1.0f,
- 1.0f,
- NULL);
+ immDrawPixelsTexTiled(&state,
+ rect.xmin,
+ rect.ymin + 1,
+ drawibuf->x,
+ drawibuf->y,
+ GPU_RGBA8,
+ true,
+ drawibuf->rect,
+ 1.0f,
+ 1.0f,
+ NULL);
/* draw cross for pixel position */
GPU_matrix_translate_2f(rect.xmin + scopes->track_pos[0], rect.ymin + scopes->track_pos[1]);
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index 27fa2e5a22f..fd03cc5e12c 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -146,8 +146,8 @@ void eyedropper_draw_cursor_text_region(const int x, const int y, const char *na
uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event)
{
bScreen *screen = CTX_wm_screen(C);
- ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy[0], event->xy[1]);
- const ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_ANY, event->xy[0], event->xy[1]);
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy);
+ const ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_ANY, event->xy);
uiBut *but = ui_but_find_mouse_over(region, event);
@@ -163,13 +163,13 @@ void datadropper_win_area_find(
bScreen *screen = CTX_wm_screen(C);
*r_win = CTX_wm_window(C);
- *r_area = BKE_screen_find_area_xy(screen, -1, mval[0], mval[1]);
+ *r_area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mval);
if (*r_area == NULL) {
wmWindowManager *wm = CTX_wm_manager(C);
*r_win = WM_window_find_under_cursor(wm, NULL, *r_win, mval, r_mval);
if (*r_win) {
screen = WM_window_get_active_screen(*r_win);
- *r_area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, r_mval[0], r_mval[1]);
+ *r_area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, r_mval);
}
}
else if (mval != r_mval) {
diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c
index 0ac6ea4021b..05840175fab 100644
--- a/source/blender/editors/interface/interface_eyedropper_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_color.c
@@ -42,6 +42,8 @@
#include "BKE_node.h"
#include "BKE_screen.h"
+#include "NOD_composite.h"
+
#include "RNA_access.h"
#include "UI_interface.h"
@@ -263,32 +265,32 @@ static bool eyedropper_cryptomatte_sample_fl(
}
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
- if (!sa || !ELEM(sa->spacetype, SPACE_IMAGE, SPACE_NODE, SPACE_CLIP)) {
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, (const int[2]){mx, my});
+ if (!area || !ELEM(area->spacetype, SPACE_IMAGE, SPACE_NODE, SPACE_CLIP)) {
return false;
}
- ARegion *region = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my});
if (!region) {
return false;
}
int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
float fpos[2] = {-1.0f, -1.0};
- switch (sa->spacetype) {
+ switch (area->spacetype) {
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
ED_space_image_get_position(sima, region, mval, fpos);
break;
}
case SPACE_NODE: {
Main *bmain = CTX_data_main(C);
- SpaceNode *snode = sa->spacedata.first;
+ SpaceNode *snode = area->spacedata.first;
ED_space_node_get_position(bmain, snode, region, mval, fpos);
break;
}
case SPACE_CLIP: {
- SpaceClip *sc = sa->spacedata.first;
+ SpaceClip *sc = area->spacedata.first;
ED_space_clip_get_position(sc, region, mval, fpos);
break;
}
@@ -337,7 +339,7 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
if (area) {
if (area->spacetype == SPACE_IMAGE) {
- ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval[0], mval[1]);
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval);
if (region) {
SpaceImage *sima = area->spacedata.first;
int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin};
@@ -348,7 +350,7 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
}
}
else if (area->spacetype == SPACE_NODE) {
- ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval[0], mval[1]);
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval);
if (region) {
SpaceNode *snode = area->spacedata.first;
int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin};
@@ -359,7 +361,7 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
}
}
else if (area->spacetype == SPACE_CLIP) {
- ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval[0], mval[1]);
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval);
if (region) {
SpaceClip *sc = area->spacedata.first;
int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin};
diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c
index 261aa997d06..cf53ef0ec75 100644
--- a/source/blender/editors/interface/interface_eyedropper_datablock.c
+++ b/source/blender/editors/interface/interface_eyedropper_datablock.c
@@ -162,7 +162,7 @@ static void datadropper_id_sample_pt(
if (area) {
if (ELEM(area->spacetype, SPACE_VIEW3D, SPACE_OUTLINER)) {
- ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my);
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my});
if (region) {
const int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
Base *base;
diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c
index 4172c474f4a..8c6b0ac9cfe 100644
--- a/source/blender/editors/interface/interface_eyedropper_depth.c
+++ b/source/blender/editors/interface/interface_eyedropper_depth.c
@@ -157,7 +157,7 @@ static void depthdropper_depth_sample_pt(
{
/* we could use some clever */
bScreen *screen = CTX_wm_screen(C);
- ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, (const int[2]){mx, my});
Scene *scene = CTX_data_scene(C);
ScrArea *area_prev = CTX_wm_area(C);
@@ -167,7 +167,7 @@ static void depthdropper_depth_sample_pt(
if (area) {
if (area->spacetype == SPACE_VIEW3D) {
- ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my);
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my});
if (region) {
struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
View3D *v3d = area->spacedata.first;
diff --git a/source/blender/editors/interface/interface_eyedropper_driver.c b/source/blender/editors/interface/interface_eyedropper_driver.c
index ccf0e727da8..6fe930b74d2 100644
--- a/source/blender/editors/interface/interface_eyedropper_driver.c
+++ b/source/blender/editors/interface/interface_eyedropper_driver.c
@@ -107,7 +107,7 @@ static void driverdropper_sample(bContext *C, wmOperator *op, const wmEvent *eve
char *target_path = RNA_path_from_ID_to_property(target_ptr, target_prop);
/* ... and destination */
- char *dst_path = BKE_animdata_driver_path_hack(C, &ddr->ptr, ddr->prop, NULL);
+ char *dst_path = RNA_path_from_ID_to_property(&ddr->ptr, ddr->prop);
/* Now create driver(s) */
if (target_path && dst_path) {
diff --git a/source/blender/editors/interface/interface_eyedropper_intern.h b/source/blender/editors/interface/interface_eyedropper_intern.h
index 17bb78a7861..ec448ef9b9f 100644
--- a/source/blender/editors/interface/interface_eyedropper_intern.h
+++ b/source/blender/editors/interface/interface_eyedropper_intern.h
@@ -25,7 +25,7 @@
/* interface_eyedropper.c */
void eyedropper_draw_cursor_text_window(const struct wmWindow *window, const char *name);
-void eyedropper_draw_cursor_text_region(const int x, const int y, const char *name);
+void eyedropper_draw_cursor_text_region(int x, int y, const char *name);
/**
* Utility to retrieve a button representing a RNA property that is currently under the cursor.
*
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index f947572f41b..905fd452b6c 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -1787,7 +1787,7 @@ static bool ui_but_is_drag_toggle(const uiBut *but)
static bool ui_selectcontext_begin(bContext *C, uiBut *but, uiSelectContextStore *selctx_data)
{
- PointerRNA lptr, idptr;
+ PointerRNA lptr;
PropertyRNA *lprop;
bool success = false;
@@ -1821,68 +1821,48 @@ static bool ui_selectcontext_begin(bContext *C, uiBut *but, uiSelectContextStore
if (i >= selctx_data->elems_len) {
break;
}
+
+ if (!UI_context_copy_to_selected_check(
+ &ptr, &link->ptr, prop, path, use_path_from_id, &lptr, &lprop)) {
+ selctx_data->elems_len -= 1;
+ i -= 1;
+ continue;
+ }
+
uiSelectContextElem *other = &selctx_data->elems[i];
- /* TODO: de-duplicate copy_to_selected_button. */
- if (link->ptr.data != ptr.data) {
- if (use_path_from_id) {
- /* Path relative to ID. */
- lprop = NULL;
- RNA_id_pointer_create(link->ptr.owner_id, &idptr);
- RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
- }
- else if (path) {
- /* Path relative to elements from list. */
- lprop = NULL;
- RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop);
+ other->ptr = lptr;
+ if (is_array) {
+ if (rna_type == PROP_FLOAT) {
+ other->val_f = RNA_property_float_get_index(&lptr, lprop, index);
}
- else {
- lptr = link->ptr;
- lprop = prop;
+ else if (rna_type == PROP_INT) {
+ other->val_i = RNA_property_int_get_index(&lptr, lprop, index);
}
-
- /* lptr might not be the same as link->ptr! */
- if ((lptr.data != ptr.data) && (lprop == prop) && RNA_property_editable(&lptr, lprop)) {
- other->ptr = lptr;
- if (is_array) {
- if (rna_type == PROP_FLOAT) {
- other->val_f = RNA_property_float_get_index(&lptr, lprop, index);
- }
- else if (rna_type == PROP_INT) {
- other->val_i = RNA_property_int_get_index(&lptr, lprop, index);
- }
- /* ignored for now */
+ /* ignored for now */
# if 0
- else if (rna_type == PROP_BOOLEAN) {
- other->val_b = RNA_property_boolean_get_index(&lptr, lprop, index);
- }
-# endif
+ else if (rna_type == PROP_BOOLEAN) {
+ other->val_b = RNA_property_boolean_get_index(&lptr, lprop, index);
}
- else {
- if (rna_type == PROP_FLOAT) {
- other->val_f = RNA_property_float_get(&lptr, lprop);
- }
- else if (rna_type == PROP_INT) {
- other->val_i = RNA_property_int_get(&lptr, lprop);
- }
- /* ignored for now */
-# if 0
- else if (rna_type == PROP_BOOLEAN) {
- other->val_b = RNA_property_boolean_get(&lptr, lprop);
- }
- else if (rna_type == PROP_ENUM) {
- other->val_i = RNA_property_enum_get(&lptr, lprop);
- }
# endif
- }
-
- continue;
+ }
+ else {
+ if (rna_type == PROP_FLOAT) {
+ other->val_f = RNA_property_float_get(&lptr, lprop);
+ }
+ else if (rna_type == PROP_INT) {
+ other->val_i = RNA_property_int_get(&lptr, lprop);
}
+ /* ignored for now */
+# if 0
+ else if (rna_type == PROP_BOOLEAN) {
+ other->val_b = RNA_property_boolean_get(&lptr, lprop);
+ }
+ else if (rna_type == PROP_ENUM) {
+ other->val_i = RNA_property_enum_get(&lptr, lprop);
+ }
+# endif
}
-
- selctx_data->elems_len -= 1;
- i -= 1;
}
-
success = (selctx_data->elems_len != 0);
}
}
@@ -3515,8 +3495,17 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
ui_but_update(but);
- /* Popup blocks don't support moving after creation, so don't change the view for them. */
- if (!data->searchbox) {
+ /* Make sure the edited button is in view. */
+ if (data->searchbox) {
+ /* Popup blocks don't support moving after creation, so don't change the view for them. */
+ }
+ else if (UI_block_layout_needs_resolving(but->block)) {
+ /* Layout isn't resolved yet (may happen when activating while drawing through
+ * #UI_but_active_only()), so can't move it into view yet. This causes
+ * #ui_but_update_view_for_active() to run after the layout is resolved. */
+ but->changed = true;
+ }
+ else {
UI_but_ensure_in_view(C, data->region, but);
}
@@ -3773,7 +3762,12 @@ static void ui_do_but_textedit(
case EVT_VKEY:
case EVT_XKEY:
case EVT_CKEY:
- if (IS_EVENT_MOD(event, ctrl, oskey)) {
+#if defined(__APPLE__)
+ if ((event->oskey && !IS_EVENT_MOD(event, shift, alt, ctrl)) ||
+ (event->ctrl && !IS_EVENT_MOD(event, shift, alt, oskey))) {
+#else
+ if (event->ctrl && !IS_EVENT_MOD(event, shift, alt, oskey)) {
+#endif
if (event->type == EVT_VKEY) {
changed = ui_textedit_copypaste(but, data, UI_TEXTEDIT_PASTE);
}
@@ -5490,7 +5484,7 @@ static int ui_do_but_NUM(
log10f(number_but->step_size));
}
else {
- value_step = (double)number_but->step_size * UI_PRECISION_FLOAT_SCALE;
+ value_step = (double)(number_but->step_size * UI_PRECISION_FLOAT_SCALE);
}
BLI_assert(value_step > 0.0f);
const double value_test = (but->drawflag & UI_BUT_ACTIVE_LEFT) ?
@@ -7938,7 +7932,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
const bool do_copy = event->type == EVT_CKEY && is_press_ctrl_but_no_shift;
const bool do_paste = event->type == EVT_VKEY && is_press_ctrl_but_no_shift;
- /* Specific handling for listrows, we try to find their overlapping tex button. */
+ /* Specific handling for list-rows, we try to find their overlapping text button. */
if ((do_copy || do_paste) && but->type == UI_BTYPE_LISTROW) {
uiBut *labelbut = ui_but_list_row_text_activate(C, but, data, event, BUTTON_ACTIVATE_OVER);
if (labelbut) {
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index ca5d08ba40e..c0d6b8a1a6c 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -31,6 +31,7 @@
#include "GPU_batch_presets.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
+#include "GPU_shader_shared.h"
#include "GPU_state.h"
#include "GPU_texture.h"
@@ -1478,78 +1479,6 @@ PreviewImage *UI_icon_to_preview(int icon_id)
return NULL;
}
-/**
- * Version of #icon_draw_rect() that uses the GPU for scaling. This is only used for
- * #ICON_TYPE_IMBUF because it's a back-ported fix for performance issues, see T92922. Only
- * File/Asset Browser use #ICON_TYPE_IMBUF right now, which makes implications more predictable.
- *
- * TODO(Julian): This code is mostly duplicated. #icon_draw_rect() should be ported to use the GPU
- * instead (D13144).
- */
-static void icon_draw_rect_fast(float x,
- float y,
- int w,
- int h,
- float UNUSED(aspect),
- int rw,
- int rh,
- uint *rect,
- float alpha,
- const float desaturate)
-{
- int draw_w = w;
- int draw_h = h;
- int draw_x = x;
- /* We need to round y, to avoid the icon jittering in some cases. */
- int draw_y = round_fl_to_int(y);
-
- /* sanity check */
- if (w <= 0 || h <= 0 || w > 2000 || h > 2000) {
- printf("%s: icons are %i x %i pixels?\n", __func__, w, h);
- BLI_assert_msg(0, "invalid icon size");
- return;
- }
- /* modulate color */
- const float col[4] = {alpha, alpha, alpha, alpha};
-
- float scale_x = 1.0f;
- float scale_y = 1.0f;
- /* rect contains image in 'rendersize', we only scale if needed */
- if (rw != w || rh != h) {
- /* preserve aspect ratio and center */
- if (rw > rh) {
- draw_w = w;
- draw_h = (int)(((float)rh / (float)rw) * (float)w);
- draw_y += (h - draw_h) / 2;
- }
- else if (rw < rh) {
- draw_w = (int)(((float)rw / (float)rh) * (float)h);
- draw_h = h;
- draw_x += (w - draw_w) / 2;
- }
- scale_x = draw_w / (float)rw;
- scale_y = draw_h / (float)rh;
- /* If the image is squared, the `draw_*` initialization values are good. */
- }
-
- /* draw */
- eGPUBuiltinShader shader;
- if (desaturate != 0.0f) {
- shader = GPU_SHADER_2D_IMAGE_DESATURATE_COLOR;
- }
- else {
- shader = GPU_SHADER_2D_IMAGE_COLOR;
- }
- IMMDrawPixelsTexState state = immDrawPixelsTexSetup(shader);
-
- if (shader == GPU_SHADER_2D_IMAGE_DESATURATE_COLOR) {
- immUniform1f("factor", desaturate);
- }
-
- immDrawPixelsTexScaled(
- &state, draw_x, draw_y, rw, rh, GPU_RGBA8, true, rect, scale_x, scale_y, 1.0f, 1.0f, col);
-}
-
static void icon_draw_rect(float x,
float y,
int w,
@@ -1561,7 +1490,6 @@ static void icon_draw_rect(float x,
float alpha,
const float desaturate)
{
- ImBuf *ima = NULL;
int draw_w = w;
int draw_h = h;
int draw_x = x;
@@ -1577,6 +1505,8 @@ static void icon_draw_rect(float x,
/* modulate color */
const float col[4] = {alpha, alpha, alpha, alpha};
+ float scale_x = 1.0f;
+ float scale_y = 1.0f;
/* rect contains image in 'rendersize', we only scale if needed */
if (rw != w || rh != h) {
/* preserve aspect ratio and center */
@@ -1590,13 +1520,9 @@ static void icon_draw_rect(float x,
draw_h = h;
draw_x += (w - draw_w) / 2;
}
+ scale_x = draw_w / (float)rw;
+ scale_y = draw_h / (float)rh;
/* If the image is squared, the `draw_*` initialization values are good. */
-
- /* first allocate imbuf for scaling and copy preview into it */
- ima = IMB_allocImBuf(rw, rh, 32, IB_rect);
- memcpy(ima->rect, rect, rw * rh * sizeof(uint));
- IMB_scaleImBuf(ima, draw_w, draw_h); /* scale it */
- rect = ima->rect;
}
/* draw */
@@ -1613,12 +1539,8 @@ static void icon_draw_rect(float x,
immUniform1f("factor", desaturate);
}
- immDrawPixelsTex(
- &state, draw_x, draw_y, draw_w, draw_h, GPU_RGBA8, false, rect, 1.0f, 1.0f, col);
-
- if (ima) {
- IMB_freeImBuf(ima);
- }
+ immDrawPixelsTexScaledFullSize(
+ &state, draw_x, draw_y, rw, rh, GPU_RGBA8, true, rect, scale_x, scale_y, 1.0f, 1.0f, col);
}
/* High enough to make a difference, low enough so that
@@ -1661,18 +1583,21 @@ static void icon_draw_cache_texture_flush_ex(GPUTexture *texture,
GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR);
GPU_shader_bind(shader);
- const int img_binding = GPU_shader_get_texture_binding(shader, "image");
- const int data_loc = GPU_shader_get_uniform(shader, "calls_data");
+ const int data_loc = GPU_shader_get_uniform_block(shader, "multi_rect_data");
+ GPUUniformBuf *ubo = GPU_uniformbuf_create_ex(
+ sizeof(struct MultiRectCallData), texture_draw_calls->drawcall_cache, __func__);
+ GPU_uniformbuf_bind(ubo, data_loc);
+ const int img_binding = GPU_shader_get_texture_binding(shader, "image");
GPU_texture_bind_ex(texture, GPU_SAMPLER_ICON, img_binding, false);
- GPU_shader_uniform_vector(
- shader, data_loc, 4, ICON_DRAW_CACHE_SIZE * 3, (float *)texture_draw_calls->drawcall_cache);
GPUBatch *quad = GPU_batch_preset_quad();
GPU_batch_set_shader(quad, shader);
GPU_batch_draw_instanced(quad, texture_draw_calls->calls);
GPU_texture_unbind(texture);
+ GPU_uniformbuf_unbind(ubo);
+ GPU_uniformbuf_free(ubo);
texture_draw_calls->calls = 0;
}
@@ -1874,9 +1799,7 @@ static void icon_draw_size(float x,
ImBuf *ibuf = icon->obj;
GPU_blend(GPU_BLEND_ALPHA_PREMULT);
- /* These icons are only used by the File/Asset Browser currently. Without this `_fast()`
- * version, there may be performance issues, see T92922. */
- icon_draw_rect_fast(x, y, w, h, aspect, ibuf->x, ibuf->y, ibuf->rect, alpha, desaturate);
+ icon_draw_rect(x, y, w, h, aspect, ibuf->x, ibuf->y, ibuf->rect, alpha, desaturate);
GPU_blend(GPU_BLEND_ALPHA);
}
else if (di->type == ICON_TYPE_VECTOR) {
@@ -2026,6 +1949,16 @@ static void ui_id_preview_image_render_size(
}
}
+void UI_icon_render_id_ex(const bContext *C,
+ Scene *scene,
+ ID *id_to_render,
+ const enum eIconSizes size,
+ const bool use_job,
+ PreviewImage *r_preview_image)
+{
+ ui_id_preview_image_render_size(C, scene, id_to_render, r_preview_image, size, use_job);
+}
+
void UI_icon_render_id(
const bContext *C, Scene *scene, ID *id, const enum eIconSizes size, const bool use_job)
{
@@ -2034,19 +1967,21 @@ void UI_icon_render_id(
return;
}
+ ID *id_to_render = id;
+
/* For objects, first try if a preview can created via the object data. */
if (GS(id->name) == ID_OB) {
Object *ob = (Object *)id;
if (ED_preview_id_is_supported(ob->data)) {
- id = ob->data;
+ id_to_render = ob->data;
}
}
- if (!ED_preview_id_is_supported(id)) {
+ if (!ED_preview_id_is_supported(id_to_render)) {
return;
}
- ui_id_preview_image_render_size(C, scene, id, pi, size, use_job);
+ UI_icon_render_id_ex(C, scene, id_to_render, size, use_job, pi);
}
static void ui_id_icon_render(const bContext *C, ID *id, bool use_jobs)
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index dc8744aaae9..2d1138b46a7 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -671,7 +671,7 @@ extern void ui_but_v3_get(uiBut *but, float vec[3]);
extern void ui_but_v3_set(uiBut *but, const float vec[3]);
extern void ui_hsvcircle_vals_from_pos(
- const rcti *rect, const float mx, const float my, float *r_val_rad, float *r_val_dist);
+ const rcti *rect, float mx, float my, float *r_val_rad, float *r_val_dist);
/**
* Cursor in HSV circle, in float units -1 to 1, to map on radius.
*/
@@ -688,11 +688,11 @@ extern void ui_hsvcube_pos_from_vals(
*/
extern void ui_but_string_get_ex(uiBut *but,
char *str,
- const size_t maxlen,
- const int float_precision,
- const bool use_exp_float,
+ size_t maxlen,
+ int float_precision,
+ bool use_exp_float,
bool *r_use_exp_float) ATTR_NONNULL(1, 2);
-extern void ui_but_string_get(uiBut *but, char *str, const size_t maxlen) ATTR_NONNULL();
+extern void ui_but_string_get(uiBut *but, char *str, size_t maxlen) ATTR_NONNULL();
/**
* A version of #ui_but_string_get_ex for dynamic buffer sizes
* (where #ui_but_string_get_max_length returns 0).
@@ -722,7 +722,7 @@ extern void ui_but_active_string_clear_and_exit(struct bContext *C, uiBut *but)
extern void ui_but_set_string_interactive(struct bContext *C, uiBut *but, const char *value);
extern uiBut *ui_but_drag_multi_edit_get(uiBut *but);
-void ui_def_but_icon(uiBut *but, const int icon, const int flag);
+void ui_def_but_icon(uiBut *but, int icon, int flag);
/**
* Avoid using this where possible since it's better not to ask for an icon in the first place.
*/
@@ -905,7 +905,7 @@ int ui_searchbox_find_index(struct ARegion *region, const char *name);
/**
* Region is the search box itself.
*/
-void ui_searchbox_update(struct bContext *C, struct ARegion *region, uiBut *but, const bool reset);
+void ui_searchbox_update(struct bContext *C, struct ARegion *region, uiBut *but, bool reset);
int ui_searchbox_autocomplete(struct bContext *C, struct ARegion *region, uiBut *but, char *str);
bool ui_searchbox_event(struct bContext *C,
struct ARegion *region,
@@ -1000,9 +1000,9 @@ extern int ui_handler_panel_region(struct bContext *C,
extern void ui_draw_aligned_panel(const struct uiStyle *style,
const uiBlock *block,
const rcti *rect,
- const bool show_pin,
- const bool show_background,
- const bool region_search_filter_active);
+ bool show_pin,
+ bool show_background,
+ bool region_search_filter_active);
void ui_panel_tag_search_filter_match(struct Panel *panel);
/* interface_draw.c */
@@ -1013,10 +1013,7 @@ extern void ui_draw_dropshadow(
/**
* Draws in resolution of 48x4 colors.
*/
-void ui_draw_gradient(const rcti *rect,
- const float hsv[3],
- const eButGradientType type,
- const float alpha);
+void ui_draw_gradient(const rcti *rect, const float hsv[3], eButGradientType type, float alpha);
/* based on UI_draw_roundbox_gl_mode,
* check on making a version which allows us to skip some sides */
@@ -1040,7 +1037,7 @@ void ui_draw_but_COLORBAND(uiBut *but, const struct uiWidgetColors *wcol, const
void ui_draw_but_UNITVEC(uiBut *but,
const struct uiWidgetColors *wcol,
const rcti *rect,
- const float radius);
+ float radius);
void ui_draw_but_CURVE(struct ARegion *region,
uiBut *but,
const struct uiWidgetColors *wcol,
@@ -1118,7 +1115,7 @@ extern void ui_but_active_free(const struct bContext *C, uiBut *but);
*/
extern void ui_but_update_view_for_active(const struct bContext *C, const uiBlock *block);
extern int ui_but_menu_direction(uiBut *but);
-extern void ui_but_text_password_hide(char password_str[128], uiBut *but, const bool restore);
+extern void ui_but_text_password_hide(char password_str[128], uiBut *but, bool restore);
/**
* Finds the pressed button in an aligned row (typically an expanded enum).
*
@@ -1131,7 +1128,7 @@ float ui_block_calc_pie_segment(struct uiBlock *block, const float event_xy[2]);
/* XXX, this code will shorten any allocated string to 'UI_MAX_NAME_STR'
* since this is really long its unlikely to be an issue,
* but this could be supported */
-void ui_but_add_shortcut(uiBut *but, const char *shortcut_str, const bool do_strip);
+void ui_but_add_shortcut(uiBut *but, const char *shortcut_str, bool do_strip);
void ui_but_clipboard_free(void);
bool ui_but_rna_equals(const uiBut *a, const uiBut *b);
bool ui_but_rna_equals_ex(const uiBut *but,
@@ -1272,8 +1269,8 @@ void uiStyleInit(void);
/* interface_icons.c */
-void ui_icon_ensure_deferred(const struct bContext *C, const int icon_id, const bool big);
-int ui_id_icon_get(const struct bContext *C, struct ID *id, const bool big);
+void ui_icon_ensure_deferred(const struct bContext *C, int icon_id, bool big);
+int ui_id_icon_get(const struct bContext *C, struct ID *id, bool big);
/* interface_icons_event.c */
@@ -1365,7 +1362,7 @@ bool ui_but_is_toggle(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
* \note ctrl is kind of a hack currently,
* so that non-embossed UI_BTYPE_TEXT button behaves as a label when ctrl is not pressed.
*/
-bool ui_but_is_interactive(const uiBut *but, const bool labeledit) ATTR_WARN_UNUSED_RESULT;
+bool ui_but_is_interactive(const uiBut *but, bool labeledit) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_popover_once_compat(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_has_array_value(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
int ui_but_icon(const uiBut *but);
@@ -1388,7 +1385,7 @@ uiBut *ui_list_find_from_row(const struct ARegion *region,
uiBut *ui_list_row_find_mouse_over(const struct ARegion *region, const int xy[2])
ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
uiBut *ui_list_row_find_from_index(const struct ARegion *region,
- const int index,
+ int index,
uiBut *listbox) ATTR_WARN_UNUSED_RESULT;
uiBut *ui_tree_row_find_mouse_over(const struct ARegion *region, const int xy[2])
ATTR_NONNULL(1, 2);
@@ -1400,7 +1397,7 @@ typedef bool (*uiButFindPollFn)(const uiBut *but, const void *customdata);
*/
uiBut *ui_but_find_mouse_over_ex(const struct ARegion *region,
const int xy[2],
- const bool labeledit,
+ bool labeledit,
const uiButFindPollFn find_poll,
const void *find_custom_data)
ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
@@ -1512,11 +1509,8 @@ typedef struct uiRNACollectionSearch {
/* Block has to be stored for freeing butstore (uiBut.block doesn't work with undo). */
uiBlock *butstore_block;
} uiRNACollectionSearch;
-void ui_rna_collection_search_update_fn(const struct bContext *C,
- void *arg,
- const char *str,
- uiSearchItems *items,
- const bool is_first);
+void ui_rna_collection_search_update_fn(
+ const struct bContext *C, void *arg, const char *str, uiSearchItems *items, bool is_first);
/* interface_ops.c */
@@ -1534,6 +1528,9 @@ uiTreeViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_bl
uiButTreeRow *ui_block_view_find_treerow_in_old_block(const uiBlock *new_block,
const uiTreeViewItemHandle *new_item_handle);
+/* interface_templates.c */
+struct uiListType *UI_UL_cache_file_layers(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index cbdb284c66b..98fcb36b778 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -5661,6 +5661,11 @@ void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y)
}
}
+bool UI_block_layout_needs_resolving(const uiBlock *block)
+{
+ return !BLI_listbase_is_empty(&block->layouts);
+}
+
void uiLayoutSetContextPointer(uiLayout *layout, const char *name, PointerRNA *ptr)
{
uiBlock *block = layout->root->block;
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 0000c850a10..f7424066ad8 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -26,7 +26,8 @@
#include "MEM_guardedalloc.h"
#include "DNA_armature_types.h"
-#include "DNA_object_types.h" /* for OB_DATA_SUPPORT_ID */
+#include "DNA_modifier_types.h" /* for handling geometry nodes properties */
+#include "DNA_object_types.h" /* for OB_DATA_SUPPORT_ID */
#include "DNA_screen_types.h"
#include "DNA_text_types.h"
@@ -985,6 +986,97 @@ bool UI_context_copy_to_selected_list(bContext *C,
return true;
}
+bool UI_context_copy_to_selected_check(PointerRNA *ptr,
+ PointerRNA *ptr_link,
+ PropertyRNA *prop,
+ const char *path,
+ bool use_path_from_id,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop)
+{
+ PointerRNA idptr;
+ PropertyRNA *lprop;
+ PointerRNA lptr;
+
+ if (ptr_link->data == ptr->data) {
+ return false;
+ }
+
+ if (use_path_from_id) {
+ /* Path relative to ID. */
+ lprop = NULL;
+ RNA_id_pointer_create(ptr_link->owner_id, &idptr);
+ RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
+ }
+ else if (path) {
+ /* Path relative to elements from list. */
+ lprop = NULL;
+ RNA_path_resolve_property(ptr_link, path, &lptr, &lprop);
+ }
+ else {
+ lptr = *ptr_link;
+ lprop = prop;
+ }
+
+ if (lptr.data == ptr->data) {
+ /* temp_ptr might not be the same as ptr_link! */
+ 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. */
+ if (lprop == NULL) {
+ return false;
+ }
+
+ if (RNA_property_type(lprop) != RNA_property_type(prop)) {
+ 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).
+ *
+ * Be permissive on ID properties in the following cases:
+ * - #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])
+ */
+ bool ignore_prop_eq = RNA_property_is_idprop(lprop) && RNA_property_is_idprop(prop);
+ if (RNA_struct_is_a(lptr.type, &RNA_NodesModifier) &&
+ RNA_struct_is_a(ptr->type, &RNA_NodesModifier)) {
+ ignore_prop_eq = false;
+
+ NodesModifierData *nmd_link = (NodesModifierData *)lptr.data;
+ NodesModifierData *nmd_src = (NodesModifierData *)ptr->data;
+ if (nmd_link->node_group == nmd_src->node_group) {
+ ignore_prop_eq = true;
+ }
+ }
+
+ if ((lprop != prop) && !ignore_prop_eq) {
+ return false;
+ }
+
+ if (!RNA_property_editable(&lptr, lprop)) {
+ return false;
+ }
+
+ if (r_ptr) {
+ *r_ptr = lptr;
+ }
+ if (r_prop) {
+ *r_prop = lprop;
+ }
+
+ return true;
+}
+
/**
* Called from both exec & poll.
*
@@ -995,7 +1087,7 @@ bool UI_context_copy_to_selected_list(bContext *C,
static bool copy_to_selected_button(bContext *C, bool all, bool poll)
{
Main *bmain = CTX_data_main(C);
- PointerRNA ptr, lptr, idptr;
+ PointerRNA ptr, lptr;
PropertyRNA *prop, *lprop;
bool success = false;
int index;
@@ -1025,32 +1117,8 @@ static bool copy_to_selected_button(bContext *C, bool all, bool poll)
continue;
}
- if (use_path_from_id) {
- /* Path relative to ID. */
- lprop = NULL;
- RNA_id_pointer_create(link->ptr.owner_id, &idptr);
- RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
- }
- else if (path) {
- /* Path relative to elements from list. */
- lprop = NULL;
- RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop);
- }
- else {
- lptr = link->ptr;
- lprop = prop;
- }
-
- if (lptr.data == ptr.data) {
- /* lptr might not be the same as link->ptr! */
- continue;
- }
-
- if (lprop != prop) {
- continue;
- }
-
- if (!RNA_property_editable(&lptr, lprop)) {
+ if (!UI_context_copy_to_selected_check(
+ &ptr, &link->ptr, prop, path, use_path_from_id, &lptr, &lprop)) {
continue;
}
@@ -1685,9 +1753,7 @@ static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *ev
bScreen *screen = CTX_wm_screen(C);
const bool skip_depressed = RNA_boolean_get(op->ptr, "skip_depressed");
ARegion *region_prev = CTX_wm_region(C);
- ARegion *region = screen ? BKE_screen_find_region_xy(
- screen, RGN_TYPE_ANY, event->xy[0], event->xy[1]) :
- NULL;
+ ARegion *region = screen ? BKE_screen_find_region_xy(screen, RGN_TYPE_ANY, event->xy) : NULL;
if (region == NULL) {
region = region_prev;
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index bc1d3387ad7..135cef5fe53 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -1146,6 +1146,7 @@ static void panel_draw_aligned_widgets(const uiStyle *style,
UI_fontstyle_draw(fontstyle,
&title_rect,
panel->drawname,
+ sizeof(panel->drawname),
title_color,
&(struct uiFontStyleDraw_Params){
.align = UI_STYLE_TEXT_LEFT,
diff --git a/source/blender/editors/interface/interface_region_search.cc b/source/blender/editors/interface/interface_region_search.cc
index f4c99fb3c16..e27dd2a7981 100644
--- a/source/blender/editors/interface/interface_region_search.cc
+++ b/source/blender/editors/interface/interface_region_search.cc
@@ -725,7 +725,7 @@ static ARegion *ui_searchbox_create_generic_ex(bContext *C,
region->type = &type;
/* create searchbox data */
- uiSearchboxData *data = (uiSearchboxData *)MEM_callocN(sizeof(uiSearchboxData), __func__);
+ uiSearchboxData *data = MEM_cnew<uiSearchboxData>(__func__);
/* set font, get bb */
data->fstyle = style->widget; /* copy struct */
@@ -1021,7 +1021,7 @@ void ui_but_search_refresh(uiButSearch *search_but)
return;
}
- uiSearchItems *items = (uiSearchItems *)MEM_callocN(sizeof(uiSearchItems), __func__);
+ uiSearchItems *items = MEM_cnew<uiSearchItems>(__func__);
/* setup search struct */
items->maxitem = 10;
diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c
index e146443faaa..fe58a6a05ae 100644
--- a/source/blender/editors/interface/interface_region_tooltip.c
+++ b/source/blender/editors/interface/interface_region_tooltip.c
@@ -74,6 +74,8 @@
#define UI_TIP_PADDING (int)(UI_TIP_PAD_FAC * UI_UNIT_Y)
#define UI_TIP_MAXWIDTH 600
+#define UI_TIP_STR_MAX 1024
+
typedef struct uiTooltipFormat {
enum {
UI_TIP_STYLE_NORMAL = 0,
@@ -214,7 +216,7 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region
/* draw header and active data (is done here to be able to change color) */
rgb_float_to_uchar(drawcol, tip_colors[UI_TIP_LC_MAIN]);
UI_fontstyle_set(&data->fstyle);
- UI_fontstyle_draw(&data->fstyle, &bbox, field->text, drawcol, &fs_params);
+ UI_fontstyle_draw(&data->fstyle, &bbox, field->text, UI_TIP_STR_MAX, drawcol, &fs_params);
/* offset to the end of the last line */
if (field->text_suffix) {
@@ -224,7 +226,8 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region
bbox.ymax -= yofs;
rgb_float_to_uchar(drawcol, tip_colors[UI_TIP_LC_ACTIVE]);
- UI_fontstyle_draw(&data->fstyle, &bbox, field->text_suffix, drawcol, &fs_params);
+ UI_fontstyle_draw(
+ &data->fstyle, &bbox, field->text_suffix, UI_TIP_STR_MAX, drawcol, &fs_params);
/* undo offset */
bbox.xmin -= xofs;
@@ -243,7 +246,7 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region
/* XXX, needed because we don't have mono in 'U.uifonts' */
BLF_size(fstyle_mono.uifont_id, fstyle_mono.points * U.pixelsize, U.dpi);
rgb_float_to_uchar(drawcol, tip_colors[field->format.color_id]);
- UI_fontstyle_draw(&fstyle_mono, &bbox, field->text, drawcol, &fs_params);
+ UI_fontstyle_draw(&fstyle_mono, &bbox, field->text, UI_TIP_STR_MAX, drawcol, &fs_params);
}
else {
BLI_assert(field->format.style == UI_TIP_STYLE_NORMAL);
@@ -255,7 +258,7 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region
/* draw remaining data */
rgb_float_to_uchar(drawcol, tip_colors[field->format.color_id]);
UI_fontstyle_set(&data->fstyle);
- UI_fontstyle_draw(&data->fstyle, &bbox, field->text, drawcol, &fs_params);
+ UI_fontstyle_draw(&data->fstyle, &bbox, field->text, UI_TIP_STR_MAX, drawcol, &fs_params);
}
bbox.ymax -= data->lineh * field->geom.lines;
@@ -1215,12 +1218,12 @@ static ARegion *ui_tooltip_create_with_data(bContext *C,
BLI_assert(ELEM(field->format.style, UI_TIP_STYLE_NORMAL, UI_TIP_STYLE_HEADER));
font_id = data->fstyle.uifont_id;
}
- w = BLF_width_ex(font_id, field->text, BLF_DRAW_STR_DUMMY_MAX, &info);
+ w = BLF_width_ex(font_id, field->text, UI_TIP_STR_MAX, &info);
/* check for suffix (enum label) */
if (field->text_suffix && field->text_suffix[0]) {
x_pos = info.width;
- w = max_ii(w, x_pos + BLF_width(font_id, field->text_suffix, BLF_DRAW_STR_DUMMY_MAX));
+ w = max_ii(w, x_pos + BLF_width(font_id, field->text_suffix, UI_TIP_STR_MAX));
}
fontw = max_ii(fontw, w);
diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c
index 643fa128d08..44942d508ca 100644
--- a/source/blender/editors/interface/interface_style.c
+++ b/source/blender/editors/interface/interface_style.c
@@ -140,9 +140,9 @@ static uiFont *uifont_to_blfont(int id)
void UI_fontstyle_draw_ex(const uiFontStyle *fs,
const rcti *rect,
const char *str,
+ const size_t str_len,
const uchar col[4],
const struct uiFontStyleDraw_Params *fs_params,
- size_t len,
int *r_xofs,
int *r_yofs,
struct ResultBLF *r_info)
@@ -173,20 +173,20 @@ void UI_fontstyle_draw_ex(const uiFontStyle *fs,
BLF_enable(fs->uifont_id, font_flag);
if (fs_params->word_wrap == 1) {
- /* draw from boundbox top */
+ /* Draw from bound-box top. */
yofs = BLI_rcti_size_y(rect) - BLF_height_max(fs->uifont_id);
}
else {
- /* draw from boundbox center */
+ /* Draw from bound-box center. */
const float height = BLF_ascender(fs->uifont_id) + BLF_descender(fs->uifont_id);
yofs = ceil(0.5f * (BLI_rcti_size_y(rect) - height));
}
if (fs_params->align == UI_STYLE_TEXT_CENTER) {
- xofs = floor(0.5f * (BLI_rcti_size_x(rect) - BLF_width(fs->uifont_id, str, len)));
+ xofs = floor(0.5f * (BLI_rcti_size_x(rect) - BLF_width(fs->uifont_id, str, str_len)));
}
else if (fs_params->align == UI_STYLE_TEXT_RIGHT) {
- xofs = BLI_rcti_size_x(rect) - BLF_width(fs->uifont_id, str, len);
+ xofs = BLI_rcti_size_x(rect) - BLF_width(fs->uifont_id, str, str_len);
}
yofs = MAX2(0, yofs);
@@ -196,7 +196,7 @@ void UI_fontstyle_draw_ex(const uiFontStyle *fs,
BLF_position(fs->uifont_id, rect->xmin + xofs, rect->ymin + yofs, 0.0f);
BLF_color4ubv(fs->uifont_id, col);
- BLF_draw_ex(fs->uifont_id, str, len, r_info);
+ BLF_draw_ex(fs->uifont_id, str, str_len, r_info);
BLF_disable(fs->uifont_id, font_flag);
@@ -211,12 +211,11 @@ void UI_fontstyle_draw_ex(const uiFontStyle *fs,
void UI_fontstyle_draw(const uiFontStyle *fs,
const rcti *rect,
const char *str,
+ const size_t str_len,
const uchar col[4],
const struct uiFontStyleDraw_Params *fs_params)
{
- int xofs, yofs;
-
- UI_fontstyle_draw_ex(fs, rect, str, col, fs_params, BLF_DRAW_STR_DUMMY_MAX, &xofs, &yofs, NULL);
+ UI_fontstyle_draw_ex(fs, rect, str, str_len, col, fs_params, NULL, NULL, NULL);
}
void UI_fontstyle_draw_rotated(const uiFontStyle *fs,
@@ -427,11 +426,11 @@ void uiStyleInit(void)
}
if (U.font_path_ui[0]) {
- BLI_strncpy(font_first->filename, U.font_path_ui, sizeof(font_first->filename));
+ BLI_strncpy(font_first->filepath, U.font_path_ui, sizeof(font_first->filepath));
font_first->uifont_id = UIFONT_CUSTOM1;
}
else {
- BLI_strncpy(font_first->filename, "default", sizeof(font_first->filename));
+ BLI_strncpy(font_first->filepath, "default", sizeof(font_first->filepath));
font_first->uifont_id = UIFONT_DEFAULT;
}
@@ -442,7 +441,7 @@ void uiStyleInit(void)
font->blf_id = BLF_load_default(unique);
}
else {
- font->blf_id = BLF_load(font->filename);
+ font->blf_id = BLF_load(font->filepath);
if (font->blf_id == -1) {
font->blf_id = BLF_load_default(unique);
}
diff --git a/source/blender/editors/interface/interface_template_list.cc b/source/blender/editors/interface/interface_template_list.cc
index 13e539b5095..817599605a9 100644
--- a/source/blender/editors/interface/interface_template_list.cc
+++ b/source/blender/editors/interface/interface_template_list.cc
@@ -1322,6 +1322,7 @@ PointerRNA *UI_list_custom_drag_operator_set(uiList *ui_list,
void ED_uilisttypes_ui()
{
WM_uilisttype_add(UI_UL_asset_view());
+ WM_uilisttype_add(UI_UL_cache_file_layers());
}
/** \} */
diff --git a/source/blender/editors/interface/interface_template_search_menu.cc b/source/blender/editors/interface/interface_template_search_menu.cc
index 7a079e01e61..0ce3a0d8af1 100644
--- a/source/blender/editors/interface/interface_template_search_menu.cc
+++ b/source/blender/editors/interface/interface_template_search_menu.cc
@@ -465,6 +465,9 @@ static MenuSearch_Data *menu_items_from_ui_create(
const char *idname_array[] = {
/* While we could include this, it's just showing filenames to load. */
"TOPBAR_MT_file_open_recent",
+ /* Showing undo history is not helpful since users may accidentally undo
+ * an action they intend to run. */
+ "TOPBAR_MT_undo_history",
};
for (int i = 0; i < ARRAY_SIZE(idname_array); i++) {
MenuType *mt = WM_menutype_find(idname_array[i], false);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index b8026cbb40c..8330f8c0db7 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
@@ -6395,21 +6395,154 @@ void uiTemplateNodeSocket(uiLayout *layout, bContext *UNUSED(C), float color[4])
/** \name Cache File Template
* \{ */
-void uiTemplateCacheFile(uiLayout *layout,
- const bContext *C,
- PointerRNA *ptr,
- const char *propname)
+void uiTemplateCacheFileVelocity(uiLayout *layout, PointerRNA *fileptr)
{
- if (!ptr->data) {
- return;
+ /* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */
+ uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr);
+
+ uiItemR(layout, fileptr, "velocity_name", 0, NULL, ICON_NONE);
+ uiItemR(layout, fileptr, "velocity_unit", 0, NULL, ICON_NONE);
+}
+
+void uiTemplateCacheFileProcedural(uiLayout *layout, const bContext *C, PointerRNA *fileptr)
+{
+ /* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */
+ uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr);
+
+ uiLayout *row, *sub;
+
+ /* Only enable render procedural option if the active engine supports it. */
+ const struct RenderEngineType *engine_type = CTX_data_engine_type(C);
+
+ Scene *scene = CTX_data_scene(C);
+ const bool engine_supports_procedural = RE_engine_supports_alembic_procedural(engine_type,
+ scene);
+
+ if (!engine_supports_procedural) {
+ row = uiLayoutRow(layout, false);
+ /* For Cycles, verify that experimental features are enabled. */
+ if (BKE_scene_uses_cycles(scene) && !BKE_scene_uses_cycles_experimental_features(scene)) {
+ uiItemL(
+ row,
+ TIP_(
+ "The Cycles Alembic Procedural is only available with the experimental feature set"),
+ ICON_INFO);
+ }
+ else {
+ uiItemL(
+ row, TIP_("The active render engine does not have an Alembic Procedural"), ICON_INFO);
+ }
+ }
+
+ row = uiLayoutRow(layout, false);
+ uiLayoutSetActive(row, engine_supports_procedural);
+ uiItemR(row, fileptr, "use_render_procedural", 0, NULL, ICON_NONE);
+
+ const bool use_render_procedural = RNA_boolean_get(fileptr, "use_render_procedural");
+ const bool use_prefetch = RNA_boolean_get(fileptr, "use_prefetch");
+
+ row = uiLayoutRow(layout, false);
+ uiLayoutSetEnabled(row, use_render_procedural);
+ uiItemR(row, fileptr, "use_prefetch", 0, NULL, ICON_NONE);
+
+ sub = uiLayoutRow(layout, false);
+ uiLayoutSetEnabled(sub, use_prefetch && use_render_procedural);
+ uiItemR(sub, fileptr, "prefetch_cache_size", 0, NULL, ICON_NONE);
+}
+
+void uiTemplateCacheFileTimeSettings(uiLayout *layout, PointerRNA *fileptr)
+{
+ /* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */
+ uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr);
+
+ uiLayout *row, *sub, *subsub;
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, fileptr, "is_sequence", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRowWithHeading(layout, true, IFACE_("Override Frame"));
+ sub = uiLayoutRow(row, true);
+ uiLayoutSetPropDecorate(sub, false);
+ uiItemR(sub, fileptr, "override_frame", 0, "", ICON_NONE);
+ subsub = uiLayoutRow(sub, true);
+ uiLayoutSetActive(subsub, RNA_boolean_get(fileptr, "override_frame"));
+ uiItemR(subsub, fileptr, "frame", 0, "", ICON_NONE);
+ uiItemDecoratorR(row, fileptr, "frame", 0);
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, fileptr, "frame_offset", 0, NULL, ICON_NONE);
+ uiLayoutSetActive(row, !RNA_boolean_get(fileptr, "is_sequence"));
+}
+
+static void cache_file_layer_item(uiList *UNUSED(ui_list),
+ bContext *UNUSED(C),
+ uiLayout *layout,
+ PointerRNA *UNUSED(dataptr),
+ PointerRNA *itemptr,
+ int UNUSED(icon),
+ PointerRNA *UNUSED(active_dataptr),
+ const char *UNUSED(active_propname),
+ int UNUSED(index),
+ int UNUSED(flt_flag))
+{
+ uiLayout *row = uiLayoutRow(layout, true);
+ uiItemR(row, itemptr, "hide_layer", UI_ITEM_R_NO_BG, "", ICON_NONE);
+ uiItemR(row, itemptr, "filepath", UI_ITEM_R_NO_BG, "", ICON_NONE);
+}
+
+uiListType *UI_UL_cache_file_layers()
+{
+ uiListType *list_type = (uiListType *)MEM_callocN(sizeof(*list_type), __func__);
+
+ BLI_strncpy(list_type->idname, "UI_UL_cache_file_layers", sizeof(list_type->idname));
+ list_type->draw_item = cache_file_layer_item;
+
+ return list_type;
+}
+
+void uiTemplateCacheFileLayers(uiLayout *layout, const bContext *C, PointerRNA *fileptr)
+{
+ /* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */
+ uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr);
+
+ uiLayout *row = uiLayoutRow(layout, false);
+ uiLayout *col = uiLayoutColumn(row, true);
+
+ uiTemplateList(col,
+ (bContext *)C,
+ "UI_UL_cache_file_layers",
+ "cache_file_layers",
+ fileptr,
+ "layers",
+ fileptr,
+ "active_index",
+ "",
+ 1,
+ 5,
+ UILST_LAYOUT_DEFAULT,
+ 1,
+ UI_TEMPLATE_LIST_FLAG_NONE);
+
+ col = uiLayoutColumn(row, true);
+ uiItemO(col, "", ICON_ADD, "cachefile.layer_add");
+ uiItemO(col, "", ICON_REMOVE, "cachefile.layer_remove");
+
+ CacheFile *file = fileptr->data;
+ if (BLI_listbase_count(&file->layers) > 1) {
+ uiItemS_ex(col, 1.0f);
+ uiItemO(col, "", ICON_TRIA_UP, "cachefile.layer_move");
+ uiItemO(col, "", ICON_TRIA_DOWN, "cachefile.layer_move");
}
+}
+bool uiTemplateCacheFilePointer(PointerRNA *ptr, const char *propname, PointerRNA *r_file_ptr)
+{
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
if (!prop) {
printf(
"%s: property not found: %s.%s\n", __func__, RNA_struct_identifier(ptr->type), propname);
- return;
+ return false;
}
if (RNA_property_type(prop) != PROP_POINTER) {
@@ -6417,10 +6550,27 @@ void uiTemplateCacheFile(uiLayout *layout,
__func__,
RNA_struct_identifier(ptr->type),
propname);
+ return false;
+ }
+
+ *r_file_ptr = RNA_property_pointer_get(ptr, prop);
+ return true;
+}
+
+void uiTemplateCacheFile(uiLayout *layout,
+ const bContext *C,
+ PointerRNA *ptr,
+ const char *propname)
+{
+ if (!ptr->data) {
+ return;
+ }
+
+ PointerRNA fileptr;
+ if (!uiTemplateCacheFilePointer(ptr, propname, &fileptr)) {
return;
}
- PointerRNA fileptr = RNA_property_pointer_get(ptr, prop);
CacheFile *file = fileptr.data;
uiLayoutSetContextPointer(layout, "edit_cachefile", &fileptr);
@@ -6442,7 +6592,7 @@ void uiTemplateCacheFile(uiLayout *layout,
SpaceProperties *sbuts = CTX_wm_space_properties(C);
- uiLayout *row, *sub, *subsub;
+ uiLayout *row, *sub;
uiLayoutSetPropSep(layout, true);
@@ -6451,68 +6601,11 @@ void uiTemplateCacheFile(uiLayout *layout,
sub = uiLayoutRow(row, true);
uiItemO(sub, "", ICON_FILE_REFRESH, "cachefile.reload");
- row = uiLayoutRow(layout, false);
- uiItemR(row, &fileptr, "is_sequence", 0, NULL, ICON_NONE);
-
- /* Only enable render procedural option if the active engine supports it. */
- const struct RenderEngineType *engine_type = CTX_data_engine_type(C);
-
- Scene *scene = CTX_data_scene(C);
- const bool engine_supports_procedural = RE_engine_supports_alembic_procedural(engine_type,
- scene);
-
- if (!engine_supports_procedural) {
- row = uiLayoutRow(layout, false);
- /* For Cycles, verify that experimental features are enabled. */
- if (BKE_scene_uses_cycles(scene) && !BKE_scene_uses_cycles_experimental_features(scene)) {
- uiItemL(
- row,
- TIP_(
- "The Cycles Alembic Procedural is only available with the experimental feature set"),
- ICON_INFO);
- }
- else {
- uiItemL(
- row, TIP_("The active render engine does not have an Alembic Procedural"), ICON_INFO);
- }
- }
-
- row = uiLayoutRow(layout, false);
- uiLayoutSetActive(row, engine_supports_procedural);
- uiItemR(row, &fileptr, "use_render_procedural", 0, NULL, ICON_NONE);
-
- const bool use_render_procedural = RNA_boolean_get(&fileptr, "use_render_procedural");
- const bool use_prefetch = RNA_boolean_get(&fileptr, "use_prefetch");
-
- row = uiLayoutRow(layout, false);
- uiLayoutSetEnabled(row, use_render_procedural);
- uiItemR(row, &fileptr, "use_prefetch", 0, NULL, ICON_NONE);
-
- sub = uiLayoutRow(layout, false);
- uiLayoutSetEnabled(sub, use_prefetch && use_render_procedural);
- uiItemR(sub, &fileptr, "prefetch_cache_size", 0, NULL, ICON_NONE);
-
- row = uiLayoutRowWithHeading(layout, true, IFACE_("Override Frame"));
- sub = uiLayoutRow(row, true);
- uiLayoutSetPropDecorate(sub, false);
- uiItemR(sub, &fileptr, "override_frame", 0, "", ICON_NONE);
- subsub = uiLayoutRow(sub, true);
- uiLayoutSetActive(subsub, RNA_boolean_get(&fileptr, "override_frame"));
- uiItemR(subsub, &fileptr, "frame", 0, "", ICON_NONE);
- uiItemDecoratorR(row, &fileptr, "frame", 0);
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, &fileptr, "frame_offset", 0, NULL, ICON_NONE);
- uiLayoutSetActive(row, !RNA_boolean_get(&fileptr, "is_sequence"));
-
if (sbuts->mainb == BCONTEXT_CONSTRAINT) {
row = uiLayoutRow(layout, false);
uiItemR(row, &fileptr, "scale", 0, IFACE_("Manual Scale"), ICON_NONE);
}
- uiItemR(layout, &fileptr, "velocity_name", 0, NULL, ICON_NONE);
- uiItemR(layout, &fileptr, "velocity_unit", 0, NULL, ICON_NONE);
-
/* TODO: unused for now, so no need to expose. */
#if 0
row = uiLayoutRow(layout, false);
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/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index ad8c0842657..b44496731f7 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -2130,11 +2130,11 @@ static void widget_draw_text(const uiFontStyle *fstyle,
UI_fontstyle_draw_ex(fstyle,
rect,
drawstr + but->ofs,
+ drawlen,
wcol->text,
&(struct uiFontStyleDraw_Params){
.align = align,
},
- drawlen,
&font_xofs,
&font_yofs,
NULL);
@@ -2194,6 +2194,7 @@ static void widget_draw_text(const uiFontStyle *fstyle,
UI_fontstyle_draw(fstyle,
rect,
drawstr_right,
+ UI_MAX_DRAW_STR,
col,
&(struct uiFontStyleDraw_Params){
.align = UI_STYLE_TEXT_RIGHT,
@@ -5417,11 +5418,11 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
UI_fontstyle_draw_ex(fstyle,
rect,
drawstr,
+ sizeof(drawstr),
wt->wcol.text,
&(struct uiFontStyleDraw_Params){
.align = UI_STYLE_TEXT_LEFT,
},
- BLF_DRAW_STR_DUMMY_MAX,
&xofs,
&yofs,
&info);
@@ -5468,6 +5469,7 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
UI_fontstyle_draw(fstyle,
rect,
hint_drawstr,
+ sizeof(hint_drawstr),
wt->wcol.text,
&(struct uiFontStyleDraw_Params){
.align = UI_STYLE_TEXT_RIGHT,
@@ -5523,6 +5525,7 @@ void ui_draw_preview_item_stateless(const uiFontStyle *fstyle,
UI_fontstyle_draw(fstyle,
&trect,
drawstr,
+ sizeof(drawstr),
text_col,
&(struct uiFontStyleDraw_Params){
.align = text_align,
diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt
index 44b5f85050f..cb1c3cedf8e 100644
--- a/source/blender/editors/io/CMakeLists.txt
+++ b/source/blender/editors/io/CMakeLists.txt
@@ -26,6 +26,7 @@ set(INC
../../io/collada
../../io/gpencil
../../io/usd
+ ../../io/wavefront_obj
../../makesdna
../../makesrna
../../windowmanager
@@ -43,6 +44,7 @@ set(SRC
io_gpencil_export.c
io_gpencil_import.c
io_gpencil_utils.c
+ io_obj.c
io_ops.c
io_usd.c
@@ -50,6 +52,7 @@ set(SRC
io_cache.h
io_collada.h
io_gpencil.h
+ io_obj.h
io_ops.h
io_usd.h
)
@@ -57,6 +60,7 @@ set(SRC
set(LIB
bf_blenkernel
bf_blenlib
+ bf_wavefront_obj
)
if(WITH_OPENCOLLADA)
diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c
index bf20c1f6438..4f71a804986 100644
--- a/source/blender/editors/io/io_cache.c
+++ b/source/blender/editors/io/io_cache.c
@@ -26,6 +26,7 @@
#include "DNA_cachefile_types.h"
#include "DNA_space_types.h"
+#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
@@ -36,6 +37,7 @@
#include "BKE_report.h"
#include "RNA_access.h"
+#include "RNA_define.h"
#include "DEG_depsgraph.h"
@@ -46,6 +48,12 @@
#include "io_cache.h"
+static void reload_cachefile(bContext *C, CacheFile *cache_file)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ BKE_cachefile_reload(depsgraph, cache_file);
+}
+
static void cachefile_init(bContext *C, wmOperator *op)
{
PropertyPointerRNA *pprop;
@@ -146,8 +154,7 @@ static int cachefile_reload_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- BKE_cachefile_reload(depsgraph, cache_file);
+ reload_cachefile(C, cache_file);
return OPERATOR_FINISHED;
}
@@ -164,3 +171,160 @@ void CACHEFILE_OT_reload(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+/* ***************************** Add Layer Operator **************************** */
+
+static int cachefile_layer_open_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ char filepath[FILE_MAX];
+ Main *bmain = CTX_data_main(C);
+
+ BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath));
+ BLI_path_extension_replace(filepath, sizeof(filepath), ".abc");
+ RNA_string_set(op->ptr, "filepath", filepath);
+ }
+
+ /* There is no more CacheFile set when returning from the file selector, so store it here. */
+ op->customdata = CTX_data_edit_cachefile(C);
+
+ WM_event_add_fileselect(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+
+ UNUSED_VARS(event);
+}
+
+static int cachefile_layer_add_exec(bContext *C, wmOperator *op)
+{
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ BKE_report(op->reports, RPT_ERROR, "No filename given");
+ return OPERATOR_CANCELLED;
+ }
+
+ CacheFile *cache_file = op->customdata;
+
+ if (!cache_file) {
+ return OPERATOR_CANCELLED;
+ }
+
+ char filename[FILE_MAX];
+ RNA_string_get(op->ptr, "filepath", filename);
+
+ CacheFileLayer *layer = BKE_cachefile_add_layer(cache_file, filename);
+
+ if (!layer) {
+ WM_report(RPT_ERROR, "Could not add a layer to the cache file");
+ return OPERATOR_CANCELLED;
+ }
+
+ reload_cachefile(C, cache_file);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void CACHEFILE_OT_layer_add(wmOperatorType *ot)
+{
+ ot->name = "Add layer";
+ ot->description = "Add an override layer to the archive";
+ ot->idname = "CACHEFILE_OT_layer_add";
+
+ /* api callbacks */
+ ot->invoke = cachefile_layer_open_invoke;
+ ot->exec = cachefile_layer_add_exec;
+
+ WM_operator_properties_filesel(ot,
+ FILE_TYPE_ALEMBIC | FILE_TYPE_FOLDER,
+ FILE_BLENDER,
+ FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
+ FILE_DEFAULTDISPLAY,
+ FILE_SORT_DEFAULT);
+}
+
+/* ***************************** Remove Layer Operator **************************** */
+
+static int cachefile_layer_remove_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ CacheFile *cache_file = CTX_data_edit_cachefile(C);
+
+ if (!cache_file) {
+ return OPERATOR_CANCELLED;
+ }
+
+ CacheFileLayer *layer = BKE_cachefile_get_active_layer(cache_file);
+ BKE_cachefile_remove_layer(cache_file, layer);
+
+ reload_cachefile(C, cache_file);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void CACHEFILE_OT_layer_remove(wmOperatorType *ot)
+{
+ ot->name = "Add layer";
+ ot->description = "Remove an override layer to the archive";
+ ot->idname = "CACHEFILE_OT_layer_remove";
+
+ /* api callbacks */
+ ot->exec = cachefile_layer_remove_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ***************************** Move Layer Operator **************************** */
+
+static int cachefile_layer_move_exec(bContext *C, wmOperator *op)
+{
+ CacheFile *cache_file = CTX_data_edit_cachefile(C);
+
+ if (!cache_file) {
+ return OPERATOR_CANCELLED;
+ }
+
+ CacheFileLayer *layer = BKE_cachefile_get_active_layer(cache_file);
+
+ if (!layer) {
+ return OPERATOR_CANCELLED;
+ }
+
+ const int dir = RNA_enum_get(op->ptr, "direction");
+
+ if (BLI_listbase_link_move(&cache_file->layers, layer, dir)) {
+ cache_file->active_layer = BLI_findindex(&cache_file->layers, layer) + 1;
+ /* Only reload if something moved, might be expensive. */
+ reload_cachefile(C, cache_file);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void CACHEFILE_OT_layer_move(wmOperatorType *ot)
+{
+ static const EnumPropertyItem layer_slot_move[] = {
+ {-1, "UP", 0, "Up", ""},
+ {1, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ ot->name = "Move layer";
+ ot->description =
+ "Move layer in the list, layers further down the list will overwrite data from the layers "
+ "higher up";
+ ot->idname = "CACHEFILE_OT_layer_move";
+
+ /* api callbacks */
+ ot->exec = cachefile_layer_move_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna,
+ "direction",
+ layer_slot_move,
+ 0,
+ "Direction",
+ "Direction to move the active vertex group towards");
+}
diff --git a/source/blender/editors/io/io_cache.h b/source/blender/editors/io/io_cache.h
index be6e31842af..297e065434f 100644
--- a/source/blender/editors/io/io_cache.h
+++ b/source/blender/editors/io/io_cache.h
@@ -27,3 +27,7 @@ struct wmOperatorType;
void CACHEFILE_OT_open(struct wmOperatorType *ot);
void CACHEFILE_OT_reload(struct wmOperatorType *ot);
+
+void CACHEFILE_OT_layer_add(struct wmOperatorType *ot);
+void CACHEFILE_OT_layer_remove(struct wmOperatorType *ot);
+void CACHEFILE_OT_layer_move(struct wmOperatorType *ot);
diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c
new file mode 100644
index 00000000000..2bc2a832d20
--- /dev/null
+++ b/source/blender/editors/io/io_obj.c
@@ -0,0 +1,369 @@
+/*
+ * 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 editor/io
+ */
+
+#include "DNA_space_types.h"
+
+#include "BKE_context.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "DEG_depsgraph.h"
+
+#include "IO_wavefront_obj.h"
+#include "io_obj.h"
+
+static const EnumPropertyItem io_obj_transform_axis_forward[] = {
+ {OBJ_AXIS_X_FORWARD, "X_FORWARD", 0, "X", "Positive X axis"},
+ {OBJ_AXIS_Y_FORWARD, "Y_FORWARD", 0, "Y", "Positive Y axis"},
+ {OBJ_AXIS_Z_FORWARD, "Z_FORWARD", 0, "Z", "Positive Z axis"},
+ {OBJ_AXIS_NEGATIVE_X_FORWARD, "NEGATIVE_X_FORWARD", 0, "-X", "Negative X axis"},
+ {OBJ_AXIS_NEGATIVE_Y_FORWARD, "NEGATIVE_Y_FORWARD", 0, "-Y", "Negative Y axis"},
+ {OBJ_AXIS_NEGATIVE_Z_FORWARD, "NEGATIVE_Z_FORWARD", 0, "-Z (Default)", "Negative Z axis"},
+ {0, NULL, 0, NULL, NULL}};
+
+static const EnumPropertyItem io_obj_transform_axis_up[] = {
+ {OBJ_AXIS_X_UP, "X_UP", 0, "X", "Positive X axis"},
+ {OBJ_AXIS_Y_UP, "Y_UP", 0, "Y (Default)", "Positive Y axis"},
+ {OBJ_AXIS_Z_UP, "Z_UP", 0, "Z", "Positive Z axis"},
+ {OBJ_AXIS_NEGATIVE_X_UP, "NEGATIVE_X_UP", 0, "-X", "Negative X axis"},
+ {OBJ_AXIS_NEGATIVE_Y_UP, "NEGATIVE_Y_UP", 0, "-Y", "Negative Y axis"},
+ {OBJ_AXIS_NEGATIVE_Z_UP, "NEGATIVE_Z_UP", 0, "-Z", "Negative Z axis"},
+ {0, NULL, 0, NULL, NULL}};
+
+static const EnumPropertyItem io_obj_export_evaluation_mode[] = {
+ {DAG_EVAL_RENDER, "DAG_EVAL_RENDER", 0, "Render", "Export objects as they appear in render"},
+ {DAG_EVAL_VIEWPORT,
+ "DAG_EVAL_VIEWPORT",
+ 0,
+ "Viewport (Default)",
+ "Export objects as they appear in the viewport"},
+ {0, NULL, 0, NULL, NULL}};
+
+static int wm_obj_export_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ Main *bmain = CTX_data_main(C);
+ char filepath[FILE_MAX];
+
+ if (BKE_main_blendfile_path(bmain)[0] == '\0') {
+ BLI_strncpy(filepath, "untitled", sizeof(filepath));
+ }
+ else {
+ BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath));
+ }
+
+ BLI_path_extension_replace(filepath, sizeof(filepath), ".obj");
+ RNA_string_set(op->ptr, "filepath", filepath);
+ }
+
+ WM_event_add_fileselect(C, op);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int wm_obj_export_exec(bContext *C, wmOperator *op)
+{
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ BKE_report(op->reports, RPT_ERROR, "No filename given");
+ return OPERATOR_CANCELLED;
+ }
+ struct OBJExportParams export_params;
+ RNA_string_get(op->ptr, "filepath", export_params.filepath);
+ export_params.blen_filepath = CTX_data_main(C)->filepath;
+ export_params.export_animation = RNA_boolean_get(op->ptr, "export_animation");
+ export_params.start_frame = RNA_int_get(op->ptr, "start_frame");
+ export_params.end_frame = RNA_int_get(op->ptr, "end_frame");
+
+ export_params.forward_axis = RNA_enum_get(op->ptr, "forward_axis");
+ export_params.up_axis = RNA_enum_get(op->ptr, "up_axis");
+ export_params.scaling_factor = RNA_float_get(op->ptr, "scaling_factor");
+ export_params.export_eval_mode = RNA_enum_get(op->ptr, "export_eval_mode");
+
+ export_params.export_selected_objects = RNA_boolean_get(op->ptr, "export_selected_objects");
+ export_params.export_uv = RNA_boolean_get(op->ptr, "export_uv");
+ export_params.export_normals = RNA_boolean_get(op->ptr, "export_normals");
+ export_params.export_materials = RNA_boolean_get(op->ptr, "export_materials");
+ export_params.export_triangulated_mesh = RNA_boolean_get(op->ptr, "export_triangulated_mesh");
+ export_params.export_curves_as_nurbs = RNA_boolean_get(op->ptr, "export_curves_as_nurbs");
+
+ export_params.export_object_groups = RNA_boolean_get(op->ptr, "export_object_groups");
+ export_params.export_material_groups = RNA_boolean_get(op->ptr, "export_material_groups");
+ export_params.export_vertex_groups = RNA_boolean_get(op->ptr, "export_vertex_groups");
+ export_params.export_smooth_groups = RNA_boolean_get(op->ptr, "export_smooth_groups");
+ export_params.smooth_groups_bitflags = RNA_boolean_get(op->ptr, "smooth_group_bitflags");
+
+ OBJ_export(C, &export_params);
+
+ return OPERATOR_FINISHED;
+}
+
+static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr)
+{
+
+ const bool export_animation = RNA_boolean_get(imfptr, "export_animation");
+ const bool export_smooth_groups = RNA_boolean_get(imfptr, "export_smooth_groups");
+
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+
+ /* Animation options. */
+ uiLayout *box = uiLayoutBox(layout);
+ uiItemL(box, IFACE_("Animation"), ICON_ANIM);
+ uiLayout *col = uiLayoutColumn(box, false);
+ uiLayout *sub = uiLayoutColumn(col, false);
+ uiItemR(sub, imfptr, "export_animation", 0, NULL, ICON_NONE);
+ sub = uiLayoutColumn(sub, true);
+ uiItemR(sub, imfptr, "start_frame", 0, IFACE_("Frame Start"), ICON_NONE);
+ uiItemR(sub, imfptr, "end_frame", 0, IFACE_("End"), ICON_NONE);
+ uiLayoutSetEnabled(sub, export_animation);
+
+ /* Object Transform options. */
+ box = uiLayoutBox(layout);
+ uiItemL(box, IFACE_("Object Properties"), ICON_OBJECT_DATA);
+ col = uiLayoutColumn(box, false);
+ sub = uiLayoutColumn(col, false);
+ uiItemR(sub, imfptr, "forward_axis", 0, IFACE_("Axis Forward"), ICON_NONE);
+ uiItemR(sub, imfptr, "up_axis", 0, IFACE_("Up"), ICON_NONE);
+ sub = uiLayoutColumn(col, false);
+ uiItemR(sub, imfptr, "scaling_factor", 0, NULL, ICON_NONE);
+ sub = uiLayoutColumnWithHeading(col, false, IFACE_("Objects"));
+ uiItemR(sub, imfptr, "export_selected_objects", 0, IFACE_("Selected Only"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_eval_mode", 0, IFACE_("Properties"), ICON_NONE);
+
+ /* Options for what to write. */
+ box = uiLayoutBox(layout);
+ uiItemL(box, IFACE_("Geometry Export"), ICON_EXPORT);
+ col = uiLayoutColumn(box, false);
+ sub = uiLayoutColumnWithHeading(col, false, IFACE_("Export"));
+ uiItemR(sub, imfptr, "export_uv", 0, IFACE_("UV Coordinates"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_normals", 0, IFACE_("Normals"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_materials", 0, IFACE_("Materials"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_triangulated_mesh", 0, IFACE_("Triangulated Mesh"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_curves_as_nurbs", 0, IFACE_("Curves as NURBS"), ICON_NONE);
+
+ box = uiLayoutBox(layout);
+ uiItemL(box, IFACE_("Grouping"), ICON_GROUP);
+ col = uiLayoutColumn(box, false);
+ sub = uiLayoutColumnWithHeading(col, false, IFACE_("Export"));
+ uiItemR(sub, imfptr, "export_object_groups", 0, IFACE_("Object Groups"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_material_groups", 0, IFACE_("Material Groups"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_vertex_groups", 0, IFACE_("Vertex Groups"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_smooth_groups", 0, IFACE_("Smooth Groups"), ICON_NONE);
+ sub = uiLayoutColumn(sub, false);
+ uiLayoutSetEnabled(sub, export_smooth_groups);
+ uiItemR(sub, imfptr, "smooth_group_bitflags", 0, IFACE_("Smooth Group Bitflags"), ICON_NONE);
+}
+
+static void wm_obj_export_draw(bContext *UNUSED(C), wmOperator *op)
+{
+ PointerRNA ptr;
+ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
+ ui_obj_export_settings(op->layout, &ptr);
+}
+
+/**
+ * Return true if any property in the UI is changed.
+ */
+static bool wm_obj_export_check(bContext *C, wmOperator *op)
+{
+ char filepath[FILE_MAX];
+ Scene *scene = CTX_data_scene(C);
+ bool changed = false;
+ RNA_string_get(op->ptr, "filepath", filepath);
+
+ if (!BLI_path_extension_check(filepath, ".obj")) {
+ BLI_path_extension_ensure(filepath, FILE_MAX, ".obj");
+ RNA_string_set(op->ptr, "filepath", filepath);
+ changed = true;
+ }
+
+ {
+ int start = RNA_int_get(op->ptr, "start_frame");
+ int end = RNA_int_get(op->ptr, "end_frame");
+ /* Set the defaults. */
+ if (start == INT_MIN) {
+ start = SFRA;
+ changed = true;
+ }
+ if (end == INT_MAX) {
+ end = EFRA;
+ changed = true;
+ }
+ /* Fix user errors. */
+ if (end < start) {
+ end = start;
+ changed = true;
+ }
+ RNA_int_set(op->ptr, "start_frame", start);
+ RNA_int_set(op->ptr, "end_frame", end);
+ }
+
+ /* Both forward and up axes cannot be the same (or same except opposite sign). */
+ if (RNA_enum_get(op->ptr, "forward_axis") % TOTAL_AXES ==
+ (RNA_enum_get(op->ptr, "up_axis") % TOTAL_AXES)) {
+ /* TODO(@ankitm): Show a warning here. */
+ RNA_enum_set(op->ptr, "up_axis", RNA_enum_get(op->ptr, "up_axis") % TOTAL_AXES + 1);
+ changed = true;
+ }
+ return changed;
+}
+
+void WM_OT_obj_export(struct wmOperatorType *ot)
+{
+ ot->name = "Export Wavefront OBJ";
+ ot->description = "Save the scene to a Wavefront OBJ file";
+ ot->idname = "WM_OT_obj_export";
+
+ ot->invoke = wm_obj_export_invoke;
+ ot->exec = wm_obj_export_exec;
+ ot->poll = WM_operator_winactive;
+ ot->ui = wm_obj_export_draw;
+ ot->check = wm_obj_export_check;
+
+ WM_operator_properties_filesel(ot,
+ FILE_TYPE_FOLDER | FILE_TYPE_OBJECT_IO,
+ FILE_BLENDER,
+ FILE_SAVE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS,
+ FILE_DEFAULTDISPLAY,
+ FILE_SORT_ALPHA);
+
+ /* Animation options. */
+ RNA_def_boolean(ot->srna,
+ "export_animation",
+ false,
+ "Export Animation",
+ "Export multiple frames instead of the current frame only");
+ RNA_def_int(ot->srna,
+ "start_frame",
+ INT_MIN, /* wm_obj_export_check uses this to set SFRA. */
+ INT_MIN,
+ INT_MAX,
+ "Start Frame",
+ "The first frame to be exported",
+ INT_MIN,
+ INT_MAX);
+ RNA_def_int(ot->srna,
+ "end_frame",
+ INT_MAX, /* wm_obj_export_check uses this to set EFRA. */
+ INT_MIN,
+ INT_MAX,
+ "End Frame",
+ "The last frame to be exported",
+ INT_MIN,
+ INT_MAX);
+ /* Object transform options. */
+ RNA_def_enum(ot->srna,
+ "forward_axis",
+ io_obj_transform_axis_forward,
+ OBJ_AXIS_NEGATIVE_Z_FORWARD,
+ "Forward Axis",
+ "");
+ RNA_def_enum(ot->srna, "up_axis", io_obj_transform_axis_up, OBJ_AXIS_Y_UP, "Up Axis", "");
+ RNA_def_float(ot->srna,
+ "scaling_factor",
+ 1.0f,
+ 0.001f,
+ 10000.0f,
+ "Scale",
+ "Upscale the object by this factor",
+ 0.01,
+ 1000.0f);
+ /* File Writer options. */
+ RNA_def_enum(ot->srna,
+ "export_eval_mode",
+ io_obj_export_evaluation_mode,
+ DAG_EVAL_VIEWPORT,
+ "Object Properties",
+ "Determines properties like object visibility, modifiers etc., where they differ "
+ "for Render and Viewport");
+ RNA_def_boolean(ot->srna,
+ "export_selected_objects",
+ false,
+ "Export Selected Objects",
+ "Export only selected objects instead of all supported objects");
+ RNA_def_boolean(ot->srna, "export_uv", true, "Export UVs", "");
+ RNA_def_boolean(ot->srna,
+ "export_normals",
+ true,
+ "Export Normals",
+ "Export per-face normals if the face is flat-shaded, per-face-per-loop "
+ "normals if smooth-shaded");
+ RNA_def_boolean(ot->srna,
+ "export_materials",
+ true,
+ "Export Materials",
+ "Export MTL library. There must be a Principled-BSDF node for image textures to "
+ "be exported to the MTL file");
+ RNA_def_boolean(ot->srna,
+ "export_triangulated_mesh",
+ false,
+ "Export Triangulated Mesh",
+ "All ngons with four or more vertices will be triangulated. Meshes in "
+ "the scene will not be affected. Behaves like Triangulate Modifier with "
+ "ngon-method: \"Beauty\", quad-method: \"Shortest Diagonal\", min vertices: 4");
+ RNA_def_boolean(ot->srna,
+ "export_curves_as_nurbs",
+ false,
+ "Export Curves as NURBS",
+ "Export curves in parametric form instead of exporting as mesh");
+
+ RNA_def_boolean(ot->srna,
+ "export_object_groups",
+ false,
+ "Export Object Groups",
+ "Append mesh name to object name, separated by a '_'");
+ RNA_def_boolean(ot->srna,
+ "export_material_groups",
+ false,
+ "Export Material Groups",
+ "Append mesh name and material name to object name, separated by a '_'");
+ RNA_def_boolean(
+ ot->srna,
+ "export_vertex_groups",
+ false,
+ "Export Vertex Groups",
+ "Export the name of the vertex group of a face. It is approximated "
+ "by choosing the vertex group with the most members among the vertices of a face");
+ RNA_def_boolean(
+ ot->srna,
+ "export_smooth_groups",
+ false,
+ "Export Smooth Groups",
+ "Every smooth-shaded face is assigned group \"1\" and every flat-shaded face \"off\"");
+ RNA_def_boolean(
+ ot->srna, "smooth_group_bitflags", false, "Generate Bitflags for Smooth Groups", "");
+}
diff --git a/source/blender/editors/io/io_obj.h b/source/blender/editors/io/io_obj.h
new file mode 100644
index 00000000000..5a0e6971edd
--- /dev/null
+++ b/source/blender/editors/io/io_obj.h
@@ -0,0 +1,25 @@
+/*
+ * 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 editor/io
+ */
+
+#pragma once
+
+struct wmOperatorType;
+
+void WM_OT_obj_export(struct wmOperatorType *ot);
diff --git a/source/blender/editors/io/io_ops.c b/source/blender/editors/io/io_ops.c
index b2788ee49a2..d9bbd7d8692 100644
--- a/source/blender/editors/io/io_ops.c
+++ b/source/blender/editors/io/io_ops.c
@@ -39,6 +39,7 @@
#include "io_cache.h"
#include "io_gpencil.h"
+#include "io_obj.h"
void ED_operatortypes_io(void)
{
@@ -68,4 +69,10 @@ void ED_operatortypes_io(void)
WM_operatortype_append(CACHEFILE_OT_open);
WM_operatortype_append(CACHEFILE_OT_reload);
+
+ WM_operatortype_append(CACHEFILE_OT_layer_add);
+ WM_operatortype_append(CACHEFILE_OT_layer_remove);
+ WM_operatortype_append(CACHEFILE_OT_layer_move);
+
+ WM_operatortype_append(WM_OT_obj_export);
}
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c
index 9504a8783a0..0e207df7f94 100644
--- a/source/blender/editors/mask/mask_draw.c
+++ b/source/blender/editors/mask/mask_draw.c
@@ -722,8 +722,8 @@ void ED_mask_draw_region(
/* find window pixel coordinates of origin */
UI_view2d_view_to_region(&region->v2d, 0.0f, 0.0f, &x, &y);
- /* w = BLI_rctf_size_x(&v2d->tot); */
- /* h = BLI_rctf_size_y(&v2d->tot); */
+ // w = BLI_rctf_size_x(&v2d->tot);
+ // h = BLI_rctf_size_y(&v2d->tot);
zoomx = (float)(BLI_rcti_size_x(&region->winrct) + 1) / BLI_rctf_size_x(&region->v2d.cur);
zoomy = (float)(BLI_rcti_size_y(&region->winrct) + 1) / BLI_rctf_size_y(&region->v2d.cur);
@@ -768,7 +768,8 @@ void ED_mask_draw_region(
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR);
GPU_shader_uniform_vector(
state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red);
- immDrawPixelsTex(&state, 0.0f, 0.0f, width, height, GPU_R16F, false, buffer, 1.0f, 1.0f, NULL);
+ immDrawPixelsTexTiled(
+ &state, 0.0f, 0.0f, width, height, GPU_R16F, false, buffer, 1.0f, 1.0f, NULL);
GPU_matrix_pop();
@@ -835,7 +836,7 @@ void ED_mask_draw_frames(
mask_layer_shape = mask_layer_shape->next) {
int frame = mask_layer_shape->frame;
- /* draw_keyframe(i, CFRA, sfra, framelen, 1); */
+ // draw_keyframe(i, CFRA, sfra, framelen, 1);
int height = (frame == cfra) ? 22 : 10;
int x = (frame - sfra) * framelen;
immVertex2i(pos, x, region_bottom);
diff --git a/source/blender/editors/mask/mask_intern.h b/source/blender/editors/mask/mask_intern.h
index 41ff14dcd5f..19a3b3966a1 100644
--- a/source/blender/editors/mask/mask_intern.h
+++ b/source/blender/editors/mask/mask_intern.h
@@ -95,8 +95,8 @@ bool ED_mask_spline_select_check(const struct MaskSpline *spline);
bool ED_mask_layer_select_check(const struct MaskLayer *mask_layer);
bool ED_mask_select_check(const struct Mask *mask);
-void ED_mask_spline_select_set(struct MaskSpline *spline, const bool do_select);
-void ED_mask_layer_select_set(struct MaskLayer *mask_layer, const bool do_select);
+void ED_mask_spline_select_set(struct MaskSpline *spline, bool do_select);
+void ED_mask_layer_select_set(struct MaskLayer *mask_layer, bool do_select);
void ED_mask_select_toggle_all(struct Mask *mask, int action);
void ED_mask_select_flush_all(struct Mask *mask);
@@ -126,8 +126,8 @@ bool ED_mask_find_nearest_diff_point(const struct bContext *C,
int threshold,
bool feather,
float tangent[2],
- const bool use_deform,
- const bool use_project,
+ bool use_deform,
+ bool use_project,
struct MaskLayer **r_mask_layer,
struct MaskSpline **r_spline,
struct MaskSplinePoint **r_point,
@@ -136,7 +136,7 @@ bool ED_mask_find_nearest_diff_point(const struct bContext *C,
bool ED_mask_feather_find_nearest(const struct bContext *C,
struct Mask *mask,
const float normal_co[2],
- const float threshold,
+ float threshold,
struct MaskLayer **r_mask_layer,
struct MaskSpline **r_spline,
struct MaskSplinePoint **r_point,
@@ -145,7 +145,7 @@ bool ED_mask_feather_find_nearest(const struct bContext *C,
struct MaskSplinePoint *ED_mask_point_find_nearest(const struct bContext *C,
struct Mask *mask,
const float normal_co[2],
- const float threshold,
+ float threshold,
struct MaskLayer **r_mask_layer,
struct MaskSpline **r_spline,
eMaskWhichHandle *r_which_handle,
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index 18fe9cf7ad3..81dc34f894f 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -57,7 +57,7 @@
#define USE_NET_ISLAND_CONNECT
/**
- * Compare selected with its self.
+ * Compare selected with itself.
*/
static int bm_face_isect_self(BMFace *f, void *UNUSED(user_data))
{
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 3772a37ac44..cae781327d5 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -2605,6 +2605,7 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd,
/**
* Calculate the center and maximum excursion of mesh.
+ * (Considers all meshes in multi-object edit mode)
*/
static void calc_ortho_extent(KnifeTool_OpData *kcd)
{
@@ -2613,6 +2614,7 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd)
BMIter iter;
BMVert *v;
float min[3], max[3];
+ float ws[3];
INIT_MINMAX(min, max);
for (uint b = 0; b < kcd->objects_len; b++) {
@@ -2620,11 +2622,17 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd)
em = BKE_editmesh_from_object(ob);
if (kcd->cagecos[b]) {
- minmax_v3v3_v3_array(min, max, kcd->cagecos[b], em->bm->totvert);
+ for (int i = 0; i < em->bm->totvert; i++) {
+ copy_v3_v3(ws, kcd->cagecos[b][i]);
+ mul_m4_v3(ob->obmat, ws);
+ minmax_v3v3_v3(min, max, ws);
+ }
}
else {
BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
- minmax_v3v3_v3(min, max, v->co);
+ copy_v3_v3(ws, v->co);
+ mul_m4_v3(ob->obmat, ws);
+ minmax_v3v3_v3(min, max, ws);
}
}
}
@@ -3009,6 +3017,12 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
for (val = BLI_smallhash_iternew(&kfes, &hiter, (uintptr_t *)&kfe); val;
val = BLI_smallhash_iternext(&hiter, (uintptr_t *)&kfe)) {
+ /* If we intersect any of the vertices, don't attempt to intersect the edge. */
+ if (BLI_smallhash_lookup(&kfvs, (intptr_t)kfe->v1) ||
+ BLI_smallhash_lookup(&kfvs, (intptr_t)kfe->v2)) {
+ continue;
+ }
+
knife_project_v2(kcd, kfe->v1->cageco, se1);
knife_project_v2(kcd, kfe->v2->cageco, se2);
int isect_kind = 1;
diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c
index 8cfcc96517c..a1a7dfac282 100644
--- a/source/blender/editors/mesh/editmesh_mask_extract.c
+++ b/source/blender/editors/mesh/editmesh_mask_extract.c
@@ -388,8 +388,7 @@ static int face_set_extract_modal(bContext *C, wmOperator *op, const wmEvent *ev
* that the mouse clicked in a viewport region and its coordinates can be used to ray-cast
* the PBVH and update the active Face Set ID. */
bScreen *screen = CTX_wm_screen(C);
- ARegion *region = BKE_screen_find_main_region_at_xy(
- screen, SPACE_VIEW3D, event->xy[0], event->xy[1]);
+ ARegion *region = BKE_screen_find_main_region_at_xy(screen, SPACE_VIEW3D, event->xy);
if (!region) {
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c
index 30a453a32ee..e48b5d8255e 100644
--- a/source/blender/editors/mesh/editmesh_path.c
+++ b/source/blender/editors/mesh/editmesh_path.c
@@ -377,7 +377,7 @@ static void edgetag_ensure_cd_flag(Mesh *me, const char edge_mode)
}
}
-/* mesh shortest path select, uses prev-selected edge */
+/* Mesh shortest path select, uses previously-selected edge. */
/* since you want to create paths with multiple selects, it doesn't have extend option */
static void mouse_mesh_shortest_path_edge(Scene *scene,
diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c
index f2311eb926d..949b12f9a65 100644
--- a/source/blender/editors/mesh/editmesh_select_similar.c
+++ b/source/blender/editors/mesh/editmesh_select_similar.c
@@ -1334,6 +1334,33 @@ static const EnumPropertyItem *select_similar_type_itemf(bContext *C,
return prop_similar_types;
}
+static bool edbm_select_similar_poll_property(const bContext *UNUSED(C),
+ wmOperator *op,
+ const PropertyRNA *prop)
+{
+ const char *prop_id = RNA_property_identifier(prop);
+ const int type = RNA_enum_get(op->ptr, "type");
+
+ /* Only show threshold when it is used. */
+ if (STREQ(prop_id, "threshold")) {
+ if (!ELEM(type,
+ SIMVERT_NORMAL,
+ SIMEDGE_BEVEL,
+ SIMEDGE_CREASE,
+ SIMEDGE_DIR,
+ SIMEDGE_LENGTH,
+ SIMEDGE_FACE_ANGLE,
+ SIMFACE_AREA,
+ SIMFACE_PERIMETER,
+ SIMFACE_NORMAL,
+ SIMFACE_COPLANAR)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
void MESH_OT_select_similar(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -1347,6 +1374,7 @@ void MESH_OT_select_similar(wmOperatorType *ot)
ot->invoke = WM_menu_invoke;
ot->exec = edbm_select_similar_exec;
ot->poll = ED_operator_editmesh;
+ ot->poll_property = edbm_select_similar_poll_property;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index f22d4bbe580..59c357aa416 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -104,7 +104,7 @@ typedef struct UndoMesh {
int selectmode;
/** \note
- * this isn't a prefect solution, if you edit keys and change shapes this works well
+ * This isn't a perfect solution, if you edit keys and change shapes this works well
* (fixing T32442), but editing shape keys, going into object mode, removing or changing their
* order, then go back into editmode and undo will give issues - where the old index will be
* out of sync with the new object index.
@@ -690,12 +690,12 @@ static void undomesh_to_editmesh(UndoMesh *um, Object *ob, BMEditMesh *em, Key *
em_tmp = BKE_editmesh_create(bm);
*em = *em_tmp;
- /* Calculate face normals and tessellation at once since it's multi-threaded.
- * The vertex normals are stored in the undo-mesh, so this doesn't need to be updated. */
- BKE_editmesh_looptri_calc_ex(em,
- &(const struct BMeshCalcTessellation_Params){
- .face_normals = true,
- });
+ /* Normals should not be stored in the undo mesh, so recalculate them. The edit
+ * mesh is expected to have valid normals and there is no tracked dirty state. */
+ BLI_assert(BKE_mesh_vertex_normals_are_dirty(&um->me));
+
+ /* Calculate face normals and tessellation at once since it's multi-threaded. */
+ BKE_editmesh_looptri_and_normals_calc(em);
em->selectmode = um->selectmode;
bm->selectmode = um->selectmode;
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 013d5e5a661..f3db8f1f0d2 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -334,9 +334,6 @@ void EDBM_mesh_clear(BMEditMesh *em)
/* clear bmesh */
BM_mesh_clear(em->bm);
- /* Free evaluated meshes & cache. */
- BKE_editmesh_free_derived_caches(em);
-
/* free tessellation data */
em->tottri = 0;
MEM_SAFE_FREE(em->looptris);
@@ -1404,8 +1401,6 @@ void EDBM_update(Mesh *mesh, const struct EDBMUpdate_Params *params)
BM_lnorspace_invalidate(em->bm, false);
em->bm->spacearr_dirty &= ~BM_SPACEARR_BMO_SET;
}
- /* Don't keep stale evaluated mesh data around, see: T38872. */
- BKE_editmesh_free_derived_caches(em);
#ifdef DEBUG
{
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index d7d1dc7dcae..0f58752f323 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -1019,11 +1019,6 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator
/* Tag edges as sharp according to smooth threshold if needed,
* to preserve autosmooth shading. */
if (me->flag & ME_AUTOSMOOTH) {
- float(*polynors)[3] = MEM_mallocN(sizeof(*polynors) * (size_t)me->totpoly, __func__);
-
- BKE_mesh_calc_normals_poly(
- me->mvert, me->totvert, me->mloop, me->totloop, me->mpoly, me->totpoly, polynors);
-
BKE_edges_sharp_from_angle_set(me->mvert,
me->totvert,
me->medge,
@@ -1031,11 +1026,9 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator
me->mloop,
me->totloop,
me->mpoly,
- polynors,
+ BKE_mesh_poly_normals_ensure(me),
me->totpoly,
me->smoothresh);
-
- MEM_freeN(polynors);
}
CustomData_add_layer(data, CD_CUSTOMLOOPNORMAL, CD_DEFAULT, NULL, me->totloop);
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index bba142133a6..575e6d66ccd 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -48,7 +48,7 @@ bool EDBM_op_callf(struct BMEditMesh *em, struct wmOperator *op, const char *fmt
bool EDBM_op_call_and_selectf(struct BMEditMesh *em,
struct wmOperator *op,
const char *select_slot,
- const bool select_replace,
+ bool select_replace,
const char *fmt,
...);
/**
@@ -74,7 +74,7 @@ bool EDBM_op_init(
bool EDBM_op_finish(struct BMEditMesh *em,
struct BMOperator *bmop,
struct wmOperator *op,
- const bool do_report);
+ bool do_report);
void EDBM_stats_update(struct BMEditMesh *em);
@@ -110,8 +110,8 @@ struct BMElem *EDBM_elem_from_index_any_multi(struct ViewLayer *view_layer,
*/
bool edbm_extrude_edges_indiv(struct BMEditMesh *em,
struct wmOperator *op,
- const char hflag,
- const bool use_normal_flip);
+ char hflag,
+ bool use_normal_flip);
/* *** editmesh_add.c *** */
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index ebe8b758aa2..c9615698c46 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -1363,8 +1363,7 @@ typedef struct VertPickData {
static void ed_mesh_pick_vert__mapFunc(void *userData,
int index,
const float co[3],
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
VertPickData *data = userData;
if ((data->mvert[index].flag & ME_HIDE) == 0) {
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 9354171a1e4..06e21f91d04 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -1742,15 +1742,16 @@ void OBJECT_OT_collection_instance_add(wmOperatorType *ot)
ot->prop = prop;
ED_object_add_generic_props(ot, false);
- RNA_def_int(ot->srna,
- "session_uuid",
- 0,
- INT32_MIN,
- INT32_MAX,
- "Session UUID",
- "Session UUID of the collection to add",
- INT32_MIN,
- INT32_MAX);
+ prop = RNA_def_int(ot->srna,
+ "session_uuid",
+ 0,
+ INT32_MIN,
+ INT32_MAX,
+ "Session UUID",
+ "Session UUID of the collection to add",
+ INT32_MIN,
+ INT32_MAX);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
object_add_drop_xy_props(ot);
}
@@ -3526,6 +3527,8 @@ static int object_add_named_exec(bContext *C, wmOperator *op)
}
basen->object->visibility_flag &= ~OB_HIDE_VIEWPORT;
+ /* Do immediately, as #copy_object_set_idnew() below operates on visible objects. */
+ BKE_base_eval_flags(basen);
/* object_add_duplicate_internal() doesn't deselect other objects, unlike object_add_common() or
* BKE_view_layer_base_deselect_all(). */
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index 1b6b0c78037..b903d664c9b 100644
--- a/source/blender/editors/object/object_bake.c
+++ b/source/blender/editors/object/object_bake.c
@@ -108,8 +108,10 @@ typedef struct {
ListBase data;
/** Clear the images before baking */
bool bake_clear;
- /** Bake-filter, aka margin */
- int bake_filter;
+ /** Margin size in pixels. */
+ int bake_margin;
+ /** margin type */
+ char bake_margin_type;
/** mode of baking (displacement, normals, AO) */
short mode;
/** Use low-resolution mesh when baking displacement maps */
@@ -372,7 +374,8 @@ static int multiresbake_image_exec_locked(bContext *C, wmOperator *op)
/* copy data stored in job descriptor */
bkr.scene = scene;
- bkr.bake_filter = scene->r.bake_filter;
+ bkr.bake_margin = scene->r.bake_margin;
+ bkr.bake_margin_type = scene->r.bake_margin_type;
bkr.mode = scene->r.bake_mode;
bkr.use_lores_mesh = scene->r.bake_flag & R_BAKE_LORES_MESH;
bkr.bias = scene->r.bake_biasdist;
@@ -416,7 +419,8 @@ static void init_multiresbake_job(bContext *C, MultiresBakeJob *bkj)
/* backup scene settings, so their changing in UI would take no effect on baker */
bkj->scene = scene;
- bkj->bake_filter = scene->r.bake_filter;
+ bkj->bake_margin = scene->r.bake_margin;
+ bkj->bake_margin_type = scene->r.bake_margin_type;
bkj->mode = scene->r.bake_mode;
bkj->use_lores_mesh = scene->r.bake_flag & R_BAKE_LORES_MESH;
bkj->bake_clear = scene->r.bake_flag & R_BAKE_CLEAR;
@@ -477,7 +481,8 @@ static void multiresbake_startjob(void *bkv, short *stop, short *do_update, floa
/* copy data stored in job descriptor */
bkr.scene = bkj->scene;
- bkr.bake_filter = bkj->bake_filter;
+ bkr.bake_margin = bkj->bake_margin;
+ bkr.bake_margin_type = bkj->bake_margin_type;
bkr.mode = bkj->mode;
bkr.use_lores_mesh = bkj->use_lores_mesh;
bkr.user_scale = bkj->user_scale;
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index 0de34e21462..d56d0edd5a2 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -89,6 +89,7 @@ typedef struct BakeAPIRender {
eScenePassType pass_type;
int pass_filter;
int margin;
+ eBakeMarginType margin_type;
bool is_clear;
bool is_selected_to_active;
@@ -184,8 +185,11 @@ static bool write_internal_bake_pixels(Image *image,
const int width,
const int height,
const int margin,
+ const char margin_type,
const bool is_clear,
- const bool is_noncolor)
+ const bool is_noncolor,
+ Mesh const *mesh,
+ char const *uv_layer)
{
ImBuf *ibuf;
void *lock;
@@ -281,7 +285,7 @@ static bool write_internal_bake_pixels(Image *image,
/* margins */
if (margin > 0) {
- RE_bake_margin(ibuf, mask_buffer, margin);
+ RE_bake_margin(ibuf, mask_buffer, margin, margin_type, mesh, uv_layer);
}
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
@@ -327,8 +331,11 @@ static bool write_external_bake_pixels(const char *filepath,
const int width,
const int height,
const int margin,
+ const int margin_type,
ImageFormatData *im_format,
- const bool is_noncolor)
+ const bool is_noncolor,
+ Mesh const *mesh,
+ char const *uv_layer)
{
ImBuf *ibuf = NULL;
bool ok = false;
@@ -385,7 +392,7 @@ static bool write_external_bake_pixels(const char *filepath,
mask_buffer = MEM_callocN(sizeof(char) * num_pixels, "Bake Mask");
RE_bake_mask_fill(pixel_array, num_pixels, mask_buffer);
- RE_bake_margin(ibuf, mask_buffer, margin);
+ RE_bake_margin(ibuf, mask_buffer, margin, margin_type, mesh, uv_layer);
if (mask_buffer) {
MEM_freeN(mask_buffer);
@@ -770,6 +777,7 @@ static bool bake_targets_output_internal(const BakeAPIRender *bkr,
ReportList *reports)
{
bool all_ok = true;
+ const Mesh *me = (Mesh *)ob->data;
for (int i = 0; i < targets->num_images; i++) {
BakeImage *bk_image = &targets->images[i];
@@ -780,8 +788,11 @@ static bool bake_targets_output_internal(const BakeAPIRender *bkr,
bk_image->width,
bk_image->height,
bkr->margin,
+ bkr->margin_type,
bkr->is_clear,
- targets->is_noncolor);
+ targets->is_noncolor,
+ me,
+ bkr->uv_layer);
/* might be read by UI to set active image for display */
bake_update_image(bkr->area, bk_image->image);
@@ -895,8 +906,11 @@ static bool bake_targets_output_external(const BakeAPIRender *bkr,
bk_image->width,
bk_image->height,
bkr->margin,
+ bkr->margin_type,
&bake->im_format,
- targets->is_noncolor);
+ targets->is_noncolor,
+ me,
+ bkr->uv_layer);
if (!ok) {
BKE_reportf(reports, RPT_ERROR, "Problem saving baked map in \"%s\"", name);
@@ -1625,6 +1639,7 @@ static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr)
bkr->pass_type = RNA_enum_get(op->ptr, "type");
bkr->pass_filter = RNA_enum_get(op->ptr, "pass_filter");
bkr->margin = RNA_int_get(op->ptr, "margin");
+ bkr->margin_type = RNA_enum_get(op->ptr, "margin_type");
bkr->save_mode = (eBakeSaveMode)RNA_enum_get(op->ptr, "save_mode");
bkr->target = (eBakeTarget)RNA_enum_get(op->ptr, "target");
@@ -1818,6 +1833,11 @@ static void bake_set_props(wmOperator *op, Scene *scene)
RNA_property_int_set(op->ptr, prop, bake->margin);
}
+ prop = RNA_struct_find_property(op->ptr, "margin_type");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_enum_set(op->ptr, prop, bake->margin_type);
+ }
+
prop = RNA_struct_find_property(op->ptr, "use_selected_to_active");
if (!RNA_property_is_set(op->ptr, prop)) {
RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_TO_ACTIVE) != 0);
@@ -2008,6 +2028,12 @@ void OBJECT_OT_bake(wmOperatorType *ot)
"Extends the baked result as a post process filter",
0,
64);
+ RNA_def_enum(ot->srna,
+ "margin_type",
+ rna_enum_bake_margin_type_items,
+ R_BAKE_EXTEND,
+ "Margin Type",
+ "Which algorithm to use to generate the margin");
RNA_def_boolean(ot->srna,
"use_selected_to_active",
false,
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_gpencil_modifier.c b/source/blender/editors/object/object_gpencil_modifier.c
index e3c2932e17a..5a6c25caacc 100644
--- a/source/blender/editors/object/object_gpencil_modifier.c
+++ b/source/blender/editors/object/object_gpencil_modifier.c
@@ -533,6 +533,10 @@ static GpencilModifierData *gpencil_edit_modifier_property_get(wmOperator *op,
Object *ob,
int type)
{
+ if (ob == NULL) {
+ return NULL;
+ }
+
char modifier_name[MAX_NAME];
GpencilModifierData *md;
RNA_string_get(op->ptr, "modifier", modifier_name);
@@ -968,6 +972,9 @@ static int dash_segment_add_exec(bContext *C, wmOperator *op)
DashGpencilModifierData *dmd = (DashGpencilModifierData *)gpencil_edit_modifier_property_get(
op, ob, eGpencilModifierType_Dash);
+ if (dmd == NULL) {
+ return OPERATOR_CANCELLED;
+ }
const int new_active_index = dmd->segment_active_index + 1;
DashGpencilModifierSegment *new_segments = MEM_malloc_arrayN(
dmd->segments_len + 1, sizeof(DashGpencilModifierSegment), __func__);
@@ -1032,6 +1039,10 @@ static int dash_segment_remove_exec(bContext *C, wmOperator *op)
DashGpencilModifierData *dmd = (DashGpencilModifierData *)gpencil_edit_modifier_property_get(
op, ob, eGpencilModifierType_Dash);
+ if (dmd == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
if (dmd->segment_active_index < 0 || dmd->segment_active_index >= dmd->segments_len) {
return OPERATOR_CANCELLED;
}
@@ -1108,6 +1119,10 @@ static int dash_segment_move_exec(bContext *C, wmOperator *op)
DashGpencilModifierData *dmd = (DashGpencilModifierData *)gpencil_edit_modifier_property_get(
op, ob, eGpencilModifierType_Dash);
+ if (dmd == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
if (dmd->segments_len < 2) {
return OPERATOR_CANCELLED;
}
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_intern.h b/source/blender/editors/object/object_intern.h
index 9a1b4b48464..d517d68f1fc 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -176,8 +176,8 @@ void COLLECTION_OT_objects_remove_active(struct wmOperatorType *ot);
bool edit_modifier_poll_generic(struct bContext *C,
struct StructRNA *rna_type,
int obtype_flag,
- const bool is_editmode_allowed,
- const bool is_liboverride_allowed);
+ bool is_editmode_allowed,
+ bool is_liboverride_allowed);
void edit_modifier_properties(struct wmOperatorType *ot);
bool edit_modifier_invoke_properties(struct bContext *C, struct wmOperator *op);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 811f20e82be..a6eb35d49b9 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");
@@ -2355,7 +2355,8 @@ static bool make_override_library_poll(bContext *C)
/* Object must be directly linked to be overridable. */
return (ED_operator_objectmode(C) && obact != NULL &&
(ID_IS_LINKED(obact) || (obact->instance_collection != NULL &&
- ID_IS_OVERRIDABLE_LIBRARY(obact->instance_collection))));
+ ID_IS_OVERRIDABLE_LIBRARY(obact->instance_collection) &&
+ !ID_IS_OVERRIDE_LIBRARY(obact))));
}
static const EnumPropertyItem *make_override_collections_of_linked_object_itemf(
diff --git a/source/blender/editors/object/object_remesh.cc b/source/blender/editors/object/object_remesh.cc
index 719ffd36f03..e4103db8e21 100644
--- a/source/blender/editors/object/object_remesh.cc
+++ b/source/blender/editors/object/object_remesh.cc
@@ -168,8 +168,6 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op)
new_mesh = mesh_fixed_poles;
}
- BKE_mesh_calc_normals(new_mesh);
-
if (mesh->flag & ME_REMESH_REPROJECT_VOLUME || mesh->flag & ME_REMESH_REPROJECT_PAINT_MASK ||
mesh->flag & ME_REMESH_REPROJECT_SCULPT_FACE_SETS) {
BKE_mesh_runtime_clear_geometry(mesh);
@@ -463,8 +461,8 @@ static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *ev
Object *active_object = CTX_data_active_object(C);
Mesh *mesh = (Mesh *)active_object->data;
- VoxelSizeEditCustomData *cd = (VoxelSizeEditCustomData *)MEM_callocN(
- sizeof(VoxelSizeEditCustomData), "Voxel Size Edit OP Custom Data");
+ VoxelSizeEditCustomData *cd = MEM_cnew<VoxelSizeEditCustomData>(
+ "Voxel Size Edit OP Custom Data");
/* Initial operator Custom Data setup. */
cd->draw_handle = ED_region_draw_cb_activate(
diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c
index fd649854d8f..a871ddea48c 100644
--- a/source/blender/editors/object/object_shapekey.c
+++ b/source/blender/editors/object/object_shapekey.c
@@ -43,13 +43,16 @@
#include "DNA_object_types.h"
#include "BKE_context.h"
+#include "BKE_crazyspace.h"
#include "BKE_key.h"
#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_object.h"
+#include "BKE_report.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
#include "BLI_sys_types.h" /* for intptr_t support */
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index 4c4727f51ee..c9114c7a925 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -811,8 +811,8 @@ static int apply_objects_internal(bContext *C,
/* adjust data */
BKE_mesh_transform(me, mat, true);
- /* update normals */
- BKE_mesh_calc_normals(me);
+ /* If normal layers exist, they are now dirty. */
+ BKE_mesh_normals_tag_dirty(me);
}
else if (ob->type == OB_ARMATURE) {
bArmature *arm = ob->data;
@@ -1408,6 +1408,19 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
sub_v3_v3(mpt, offset_local);
mul_v3_m4v3(&pt->x, diff_mat, mpt);
}
+
+ /* Apply transform to edit-curve. */
+ if (gps->editcurve != NULL) {
+ for (i = 0; i < gps->editcurve->tot_curve_points; i++) {
+ BezTriple *bezt = &gps->editcurve->curve_points[i].bezt;
+ for (int j = 0; j < 3; j++) {
+ float mpt[3];
+ mul_v3_m4v3(mpt, inverse_diff_mat, bezt->vec[j]);
+ sub_v3_v3(mpt, offset_local);
+ mul_v3_m4v3(bezt->vec[j], diff_mat, mpt);
+ }
+ }
+ }
}
}
}
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/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c
index 80e3f934c80..3214180309b 100644
--- a/source/blender/editors/physics/dynamicpaint_ops.c
+++ b/source/blender/editors/physics/dynamicpaint_ops.c
@@ -373,7 +373,7 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job)
/* Show progress bar. */
*(job->do_update) = true;
- /* Set frame to start point (also inits modifier data) */
+ /* Set frame to start point (also initializes modifier data). */
frame = surface->start_frame;
orig_frame = input_scene->r.cfra;
input_scene->r.cfra = (int)frame;
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index f1e6f02cb39..1407ca598a7 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -1441,7 +1441,7 @@ void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *UNUSED(ob), Part
PTCacheEdit *edit = psys->edit;
Mesh *mesh = edit->psmd_eval->mesh_final;
float *vec, *nor;
- int i, totface /*, totvert*/;
+ int i, totface;
if (!mesh) {
return;
@@ -1454,7 +1454,7 @@ void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *UNUSED(ob), Part
BLI_kdtree_3d_free(edit->emitter_field);
totface = mesh->totface;
- // totvert = dm->getNumVerts(dm); /* UNUSED */
+ // int totvert = dm->getNumVerts(dm); /* UNUSED */
edit->emitter_cosnos = MEM_callocN(sizeof(float[6]) * totface, "emitter cosnos");
@@ -1463,26 +1463,28 @@ void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *UNUSED(ob), Part
vec = edit->emitter_cosnos;
nor = vec + 3;
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
+
for (i = 0; i < totface; i++, vec += 6, nor += 6) {
MFace *mface = &mesh->mface[i];
MVert *mvert;
mvert = &mesh->mvert[mface->v1];
copy_v3_v3(vec, mvert->co);
- copy_v3fl_v3s(nor, mvert->no);
+ copy_v3_v3(nor, vert_normals[mface->v1]);
mvert = &mesh->mvert[mface->v2];
add_v3_v3v3(vec, vec, mvert->co);
- add_v3fl_v3fl_v3s(nor, nor, mvert->no);
+ add_v3_v3(nor, vert_normals[mface->v2]);
mvert = &mesh->mvert[mface->v3];
add_v3_v3v3(vec, vec, mvert->co);
- add_v3fl_v3fl_v3s(nor, nor, mvert->no);
+ add_v3_v3(nor, vert_normals[mface->v3]);
if (mface->v4) {
mvert = &mesh->mvert[mface->v4];
add_v3_v3v3(vec, vec, mvert->co);
- add_v3fl_v3fl_v3s(nor, nor, mvert->no);
+ add_v3_v3(nor, vert_normals[mface->v4]);
mul_v3_fl(vec, 0.25);
}
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index 367d72b0ad7..987b9e49057 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -743,8 +743,10 @@ static bool remap_hair_emitter(Depsgraph *depsgraph,
invert_m4_m4(from_imat, from_mat);
invert_m4_m4(to_imat, to_mat);
- if (target_psmd->mesh_final->runtime.deformed_only) {
- /* we don't want to mess up target_psmd->dm when converting to global coordinates below */
+ const bool use_dm_final_indices = (target_psys->part->use_modifier_stack &&
+ !target_psmd->mesh_final->runtime.deformed_only);
+
+ if (use_dm_final_indices || !target_psmd->mesh_original) {
mesh = target_psmd->mesh_final;
}
else {
@@ -755,6 +757,7 @@ static bool remap_hair_emitter(Depsgraph *depsgraph,
return false;
}
/* don't modify the original vertices */
+ /* we don't want to mess up target_psmd->dm when converting to global coordinates below */
mesh = (Mesh *)BKE_id_copy_ex(NULL, &mesh->id, NULL, LIB_ID_COPY_LOCALIZE);
/* BMESH_ONLY, deform dm may not have tessface */
@@ -825,7 +828,13 @@ static bool remap_hair_emitter(Depsgraph *depsgraph,
tpa->foffset = 0.0f;
tpa->num = nearest.index;
- tpa->num_dmcache = psys_particle_dm_face_lookup(target_mesh, mesh, tpa->num, tpa->fuv, NULL);
+ if (use_dm_final_indices) {
+ tpa->num_dmcache = DMCACHE_ISCHILD;
+ }
+ else {
+ tpa->num_dmcache = psys_particle_dm_face_lookup(
+ target_psmd->mesh_final, target_psmd->mesh_original, tpa->num, tpa->fuv, NULL);
+ }
}
else {
me = &medge[nearest.index];
@@ -930,7 +939,9 @@ static bool connect_hair(Depsgraph *depsgraph, Scene *scene, Object *ob, Particl
ob->obmat,
psys->flag & PSYS_GLOBAL_HAIR,
false);
- psys->flag &= ~PSYS_GLOBAL_HAIR;
+ if (ok) {
+ psys->flag &= ~PSYS_GLOBAL_HAIR;
+ }
return ok;
}
diff --git a/source/blender/editors/render/CMakeLists.txt b/source/blender/editors/render/CMakeLists.txt
index 46afa390997..1f867c6f1f7 100644
--- a/source/blender/editors/render/CMakeLists.txt
+++ b/source/blender/editors/render/CMakeLists.txt
@@ -28,6 +28,7 @@ set(INC
../../imbuf
../../makesdna
../../makesrna
+ ../../nodes
../../render
../../sequencer
../../windowmanager
@@ -36,15 +37,15 @@ set(INC
)
set(SRC
- render_internal.c
- render_opengl.c
- render_ops.c
- render_preview.c
- render_shading.c
- render_update.c
- render_view.c
+ render_internal.cc
+ render_opengl.cc
+ render_ops.cc
+ render_preview.cc
+ render_shading.cc
+ render_update.cc
+ render_view.cc
- render_intern.h
+ render_intern.hh
)
set(LIB
diff --git a/source/blender/editors/render/render_intern.h b/source/blender/editors/render/render_intern.hh
index d374717664b..d374717664b 100644
--- a/source/blender/editors/render/render_intern.h
+++ b/source/blender/editors/render/render_intern.hh
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.cc
index 0ed303d8f6d..8e9a052381c 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.cc
@@ -21,9 +21,9 @@
* \ingroup edrend
*/
-#include <math.h>
-#include <stddef.h>
-#include <string.h>
+#include <cmath>
+#include <cstddef>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -50,11 +50,14 @@
#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"
#include "BKE_screen.h"
+#include "NOD_composite.h"
+
#include "DEG_depsgraph.h"
#include "WM_api.h"
@@ -77,12 +80,12 @@
#include "SEQ_relations.h"
-#include "render_intern.h"
+#include "render_intern.hh"
/* Render Callbacks */
static int render_break(void *rjv);
-typedef struct RenderJob {
+struct RenderJob {
Main *main;
Scene *scene;
ViewLayer *single_layer;
@@ -109,7 +112,7 @@ typedef struct RenderJob {
ColorManagedDisplaySettings display_settings;
bool supports_glsl_draw;
bool interface_locked;
-} RenderJob;
+};
/* called inside thread! */
static bool image_buffer_calc_tile_rect(const RenderResult *rr,
@@ -121,15 +124,15 @@ static bool image_buffer_calc_tile_rect(const RenderResult *rr,
{
int tile_y, tile_height, tile_x, tile_width;
- /* When `renrect` argument is not NULL, we only refresh scan-lines. */
+ /* When `renrect` argument is not nullptr, we only refresh scan-lines. */
if (renrect) {
- /* if (tile_height == recty), rendering of layer is ready,
+ /* `if (tile_height == recty)`, rendering of layer is ready,
* we should not draw, other things happen... */
- if (rr->renlay == NULL || renrect->ymax >= rr->recty) {
+ if (rr->renlay == nullptr || renrect->ymax >= rr->recty) {
return false;
}
- /* tile_x here is first subrect x coord, tile_width defines subrect width */
+ /* `tile_x` here is first sub-rectangle x coord, tile_width defines sub-rectangle width. */
tile_x = renrect->xmin;
tile_width = renrect->xmax - tile_x;
if (tile_width < 2) {
@@ -189,7 +192,7 @@ static void image_buffer_rect_update(RenderJob *rj,
const char *viewname)
{
Scene *scene = rj->scene;
- const float *rectf = NULL;
+ const float *rectf = nullptr;
int linear_stride, linear_offset_x, linear_offset_y;
ColorManagedViewSettings *view_settings;
ColorManagedDisplaySettings *display_settings;
@@ -230,12 +233,12 @@ static void image_buffer_rect_update(RenderJob *rj,
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
return;
}
- if (rr->renlay == NULL) {
+ if (rr->renlay == nullptr) {
return;
}
rectf = RE_RenderLayerGetPass(rr->renlay, RE_PASSNAME_COMBINED, viewname);
}
- if (rectf == NULL) {
+ if (rectf == nullptr) {
return;
}
@@ -256,7 +259,7 @@ static void image_buffer_rect_update(RenderJob *rj,
IMB_partial_display_buffer_update(ibuf,
rectf,
- NULL,
+ nullptr,
linear_stride,
linear_offset_x,
linear_offset_y,
@@ -315,17 +318,17 @@ static int screen_render_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
RenderEngineType *re_type = RE_engines_find(scene->r.engine);
ViewLayer *active_layer = CTX_data_view_layer(C);
- ViewLayer *single_layer = NULL;
+ ViewLayer *single_layer = nullptr;
Render *re;
Image *ima;
View3D *v3d = CTX_wm_view3d(C);
Main *mainp = CTX_data_main(C);
const bool is_animation = RNA_boolean_get(op->ptr, "animation");
const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
- struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL;
+ struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : nullptr;
/* Cannot do render if there is not this function. */
- if (re_type->render == NULL) {
+ if (re_type->render == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -342,11 +345,11 @@ static int screen_render_exec(bContext *C, wmOperator *op)
G.is_break = false;
- RE_draw_lock_cb(re, NULL, NULL);
- RE_test_break_cb(re, NULL, render_break);
+ RE_draw_lock_cb(re, nullptr, nullptr);
+ RE_test_break_cb(re, nullptr, render_break);
ima = BKE_image_ensure_viewer(mainp, IMA_TYPE_R_RESULT, "Render Result");
- BKE_image_signal(mainp, ima, NULL, IMA_SIGNAL_FREE);
+ BKE_image_signal(mainp, ima, nullptr, IMA_SIGNAL_FREE);
BKE_image_backup_render(scene, ima, true);
/* cleanup sequencer caches before starting user triggered render.
@@ -371,7 +374,7 @@ static int screen_render_exec(bContext *C, wmOperator *op)
RE_RenderFrame(re, mainp, scene, single_layer, camera_override, scene->r.cfra, is_write_still);
}
- RE_SetReports(re, NULL);
+ RE_SetReports(re, nullptr);
/* No redraw needed, we leave state as we entered it. */
ED_update_for_newframe(mainp, CTX_data_depsgraph_pointer(C));
@@ -383,7 +386,7 @@ static int screen_render_exec(bContext *C, wmOperator *op)
static void render_freejob(void *rjv)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
BKE_color_managed_view_settings_free(&rj->view_settings);
MEM_freeN(rj);
@@ -471,15 +474,15 @@ static void make_renderinfo_string(const RenderStats *rs,
static void image_renderinfo_cb(void *rjv, RenderStats *rs)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
RenderResult *rr;
rr = RE_AcquireResultRead(rj->re);
if (rr) {
/* malloc OK here, stats_draw is not in tile threads */
- if (rr->text == NULL) {
- rr->text = MEM_callocN(IMA_MAX_RENDER_TEXT, "rendertext");
+ if (rr->text == nullptr) {
+ rr->text = static_cast<char *>(MEM_callocN(IMA_MAX_RENDER_TEXT, "rendertext"));
}
make_renderinfo_string(rs, rj->scene, rj->v3d_override, rr->error, rr->text);
@@ -493,7 +496,7 @@ static void image_renderinfo_cb(void *rjv, RenderStats *rs)
static void render_progress_update(void *rjv, float progress)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
if (rj->progress && *rj->progress != progress) {
*rj->progress = progress;
@@ -511,20 +514,22 @@ static void render_progress_update(void *rjv, float progress)
static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr, ImageUser *iuser)
{
wmWindowManager *wm;
- ScrArea *first_area = NULL, *matched_area = NULL;
+ ScrArea *first_area = nullptr, *matched_area = nullptr;
/* image window, compo node users */
- for (wm = rj->main->wm.first; wm && matched_area == NULL; wm = wm->id.next) { /* only 1 wm */
+ for (wm = static_cast<wmWindowManager *>(rj->main->wm.first); wm && matched_area == nullptr;
+ wm = static_cast<wmWindowManager *>(wm->id.next)) { /* only 1 wm */
wmWindow *win;
- for (win = wm->windows.first; win && matched_area == NULL; win = win->next) {
+ for (win = static_cast<wmWindow *>(wm->windows.first); win && matched_area == nullptr;
+ win = win->next) {
const bScreen *screen = WM_window_get_active_screen(win);
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
if (area->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = area->spacedata.first;
+ SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
/* area->spacedata might be empty when toggling full-screen mode. */
- if (sima != NULL && sima->image == rj->image) {
- if (first_area == NULL) {
+ if (sima != nullptr && sima->image == rj->image) {
+ if (first_area == nullptr) {
first_area = area;
}
if (area == rj->area) {
@@ -537,12 +542,12 @@ static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr,
}
}
- if (matched_area == NULL) {
+ if (matched_area == nullptr) {
matched_area = first_area;
}
if (matched_area) {
- SpaceImage *sima = matched_area->spacedata.first;
+ SpaceImage *sima = static_cast<SpaceImage *>(matched_area->spacedata.first);
RenderResult *main_rr = RE_AcquireResultRead(rj->re);
/* TODO(sergey): is there faster way to get the layer index? */
@@ -562,7 +567,7 @@ static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr,
static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
Image *ima = rj->image;
ImBuf *ibuf;
void *lock;
@@ -584,7 +589,7 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec
return;
}
- if (rr == NULL) {
+ if (rr == nullptr) {
return;
}
@@ -628,14 +633,14 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec
static void current_scene_update(void *rjv, Scene *scene)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
rj->current_scene = scene;
rj->iuser.scene = scene;
}
static void render_startjob(void *rjv, short *stop, short *do_update, float *progress)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
rj->stop = stop;
rj->do_update = do_update;
@@ -663,7 +668,7 @@ static void render_startjob(void *rjv, short *stop, short *do_update, float *pro
rj->write_still);
}
- RE_SetReports(rj->re, NULL);
+ RE_SetReports(rj->re, nullptr);
}
static void render_image_restore_layer(RenderJob *rj)
@@ -671,15 +676,16 @@ static void render_image_restore_layer(RenderJob *rj)
wmWindowManager *wm;
/* image window, compo node users */
- for (wm = rj->main->wm.first; wm; wm = wm->id.next) { /* only 1 wm */
+ for (wm = static_cast<wmWindowManager *>(rj->main->wm.first); wm;
+ wm = static_cast<wmWindowManager *>(wm->id.next)) { /* only 1 wm */
wmWindow *win;
- for (win = wm->windows.first; win; win = win->next) {
+ for (win = static_cast<wmWindow *>(wm->windows.first); win; win = win->next) {
const bScreen *screen = WM_window_get_active_screen(win);
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
if (area == rj->area) {
if (area->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = area->spacedata.first;
+ SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
if (RE_HasSingleLayer(rj->re)) {
/* For single layer renders keep the active layer
@@ -705,11 +711,11 @@ static void render_image_restore_layer(RenderJob *rj)
static void render_endjob(void *rjv)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
- /* this render may be used again by the sequencer without the active
+ /* This render may be used again by the sequencer without the active
* 'Render' where the callbacks would be re-assigned. assign dummy callbacks
- * to avoid referencing freed renderjobs bug T24508. */
+ * to avoid referencing freed render-jobs bug T24508. */
RE_InitRenderCB(rj->re);
if (rj->main != G_MAIN) {
@@ -731,7 +737,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, nullptr);
WM_main_add_notifier(NC_NODE | NA_EDITED, rj->scene);
}
@@ -741,7 +748,7 @@ static void render_endjob(void *rjv)
/* XXX render stability hack */
G.is_rendering = false;
- WM_main_add_notifier(NC_SCENE | ND_RENDER_RESULT, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_RENDER_RESULT, nullptr);
/* Partial render result will always update display buffer
* for first render layer only. This is nice because you'll
@@ -778,7 +785,7 @@ static void render_endjob(void *rjv)
* and using one from Global will unlock exactly the same manager as
* was locked before running the job.
*/
- WM_set_locked_interface(G_MAIN->wm.first, false);
+ WM_set_locked_interface(static_cast<wmWindowManager *>(G_MAIN->wm.first), false);
DEG_tag_on_visible_update(G_MAIN, false);
}
}
@@ -786,7 +793,7 @@ static void render_endjob(void *rjv)
/* called by render, check job 'stop' value or the global */
static int render_breakjob(void *rjv)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
if (G.is_break) {
return 1;
@@ -813,7 +820,7 @@ static int render_break(void *UNUSED(rjv))
/* maybe need a way to get job send notifier? */
static void render_drawlock(void *rjv, bool lock)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
/* If interface is locked, renderer callback shall do nothing. */
if (!rj->interface_locked) {
@@ -875,11 +882,12 @@ static void clean_viewport_memory(Main *bmain, Scene *scene)
BKE_main_id_tag_listbase(&bmain->objects, LIB_TAG_DOIT, true);
/* Go over all the visible objects. */
- for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
+ for (wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first); wm;
+ wm = static_cast<wmWindowManager *>(wm->id.next)) {
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
- for (base = view_layer->object_bases.first; base; base = base->next) {
+ for (base = static_cast<Base *>(view_layer->object_bases.first); base; base = base->next) {
clean_viewport_memory_base(base);
}
}
@@ -897,7 +905,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *active_layer = CTX_data_view_layer(C);
- ViewLayer *single_layer = NULL;
+ ViewLayer *single_layer = nullptr;
RenderEngineType *re_type = RE_engines_find(scene->r.engine);
Render *re;
wmJob *wm_job;
@@ -906,13 +914,13 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
const bool is_animation = RNA_boolean_get(op->ptr, "animation");
const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
const bool use_viewport = RNA_boolean_get(op->ptr, "use_viewport");
- View3D *v3d = use_viewport ? CTX_wm_view3d(C) : NULL;
- struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL;
+ View3D *v3d = use_viewport ? CTX_wm_view3d(C) : nullptr;
+ struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : nullptr;
const char *name;
ScrArea *area;
/* Cannot do render if there is not this function. */
- if (re_type->render == NULL) {
+ if (re_type->render == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -968,7 +976,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
area = render_view_open(C, event->xy[0], event->xy[1], op->reports);
/* job custom data */
- rj = MEM_callocN(sizeof(RenderJob), "render job");
+ rj = MEM_cnew<RenderJob>("render job");
rj->main = bmain;
rj->scene = scene;
rj->current_scene = rj->scene;
@@ -992,7 +1000,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
BKE_color_managed_view_settings_copy(&rj->view_settings, &scene->view_settings);
if (area) {
- SpaceImage *sima = area->spacedata.first;
+ SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
rj->orig_layer = sima->iuser.layer;
}
@@ -1036,7 +1044,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
WM_JOB_TYPE_RENDER);
WM_jobs_customdata_set(wm_job, rj, render_freejob);
WM_jobs_timer(wm_job, 0.2, NC_SCENE | ND_RENDER_RESULT, 0);
- WM_jobs_callbacks(wm_job, render_startjob, NULL, NULL, render_endjob);
+ WM_jobs_callbacks(wm_job, render_startjob, nullptr, nullptr, render_endjob);
if (RNA_struct_property_is_set(op->ptr, "layer")) {
WM_jobs_delay_start(wm_job, 0.2);
@@ -1044,7 +1052,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
/* get a render result image, and make sure it is empty */
ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result");
- BKE_image_signal(rj->main, ima, NULL, IMA_SIGNAL_FREE);
+ BKE_image_signal(rj->main, ima, nullptr, IMA_SIGNAL_FREE);
BKE_image_backup_render(rj->scene, ima, true);
rj->image = ima;
@@ -1104,32 +1112,32 @@ void RENDER_OT_render(wmOperatorType *ot)
prop = RNA_def_boolean(ot->srna,
"animation",
- 0,
+ false,
"Animation",
"Render files from the animation range of this scene");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
RNA_def_boolean(
ot->srna,
"write_still",
- 0,
+ false,
"Write Image",
"Save rendered the image to the output path (used only when animation is disabled)");
prop = RNA_def_boolean(ot->srna,
"use_viewport",
- 0,
+ false,
"Use 3D Viewport",
"When inside a 3D viewport, use layers and camera of the viewport");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_string(ot->srna,
"layer",
- NULL,
+ nullptr,
RE_MAXNAME,
"Render Layer",
"Single render layer to re-render (used only when animation is disabled)");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_string(ot->srna,
"scene",
- NULL,
+ nullptr,
MAX_ID_NAME - 2,
"Scene",
"Scene to render, current scene if not specified");
@@ -1145,7 +1153,7 @@ Scene *ED_render_job_get_scene(const bContext *C)
return rj->scene;
}
- return NULL;
+ return nullptr;
}
Scene *ED_render_job_get_current_scene(const bContext *C)
@@ -1155,7 +1163,7 @@ Scene *ED_render_job_get_current_scene(const bContext *C)
if (rj) {
return rj->current_scene;
}
- return NULL;
+ return nullptr;
}
/* Motion blur curve preset */
@@ -1186,7 +1194,7 @@ void RENDER_OT_shutter_curve_preset(wmOperatorType *ot)
{CURVE_PRESET_LINE, "LINE", 0, "Line", ""},
{CURVE_PRESET_ROUND, "ROUND", 0, "Round", ""},
{CURVE_PRESET_ROOT, "ROOT", 0, "Root", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
ot->name = "Shutter Curve Preset";
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.cc
index 1e1a95f2965..8bd0244c899 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.cc
@@ -21,9 +21,9 @@
* \ingroup render
*/
-#include <math.h>
-#include <stddef.h>
-#include <string.h>
+#include <cmath>
+#include <cstddef>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -82,7 +82,7 @@
#include "GPU_framebuffer.h"
#include "GPU_matrix.h"
-#include "render_intern.h"
+#include "render_intern.hh"
/* Define this to get timing information. */
// #define DEBUG_TIME
@@ -92,10 +92,10 @@
#endif
/* TODO(sergey): Find better approximation of the scheduled frames.
- * For really highres renders it might fail still. */
+ * For really high-resolution renders it might fail still. */
#define MAX_SCHEDULED_FRAMES 8
-typedef struct OGLRender {
+struct OGLRender {
Main *bmain;
Render *re;
Scene *scene;
@@ -141,7 +141,7 @@ typedef struct OGLRender {
wmWindowManager *wm;
wmWindow *win;
- /** Use to check if running modal or not (invoke'd or exec'd). */
+ /** Use to check if running modal or not (invoked or executed). */
wmTimer *timer;
void **movie_ctx_arr;
@@ -159,7 +159,7 @@ typedef struct OGLRender {
#ifdef DEBUG_TIME
double time_start;
#endif
-} OGLRender;
+};
static bool screen_opengl_is_multiview(OGLRender *oglrender)
{
@@ -167,12 +167,12 @@ static bool screen_opengl_is_multiview(OGLRender *oglrender)
RegionView3D *rv3d = oglrender->rv3d;
RenderData *rd = &oglrender->scene->r;
- if ((rd == NULL) || ((v3d != NULL) && (rv3d == NULL))) {
+ if ((rd == nullptr) || ((v3d != nullptr) && (rv3d == nullptr))) {
return false;
}
return (rd->scemode & R_MULTIVIEW) &&
- ((v3d == NULL) || (rv3d->persp == RV3D_CAMOB && v3d->camera));
+ ((v3d == nullptr) || (rv3d->persp == RV3D_CAMOB && v3d->camera));
}
static void screen_opengl_views_setup(OGLRender *oglrender)
@@ -192,10 +192,10 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
if (!is_multiview) {
/* we only have one view when multiview is off */
- rv = rr->views.first;
+ rv = static_cast<RenderView *>(rr->views.first);
- if (rv == NULL) {
- rv = MEM_callocN(sizeof(RenderView), "new opengl render view");
+ if (rv == nullptr) {
+ rv = MEM_cnew<RenderView>("new opengl render view");
BLI_addtail(&rr->views, rv);
}
@@ -224,9 +224,10 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
}
/* remove all the views that are not needed */
- rv = rr->views.last;
+ rv = static_cast<RenderView *>(rr->views.last);
while (rv) {
- srv = BLI_findstring(&rd->views, rv->name, offsetof(SceneRenderView, name));
+ srv = static_cast<SceneRenderView *>(
+ BLI_findstring(&rd->views, rv->name, offsetof(SceneRenderView, name)));
if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
rv = rv->prev;
}
@@ -253,15 +254,16 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
}
/* create all the views that are needed */
- for (srv = rd->views.first; srv; srv = srv->next) {
+ for (srv = static_cast<SceneRenderView *>(rd->views.first); srv; srv = srv->next) {
if (BKE_scene_multiview_is_render_view_active(rd, srv) == false) {
continue;
}
- rv = BLI_findstring(&rr->views, srv->name, offsetof(SceneRenderView, name));
+ rv = static_cast<RenderView *>(
+ BLI_findstring(&rr->views, srv->name, offsetof(SceneRenderView, name)));
- if (rv == NULL) {
- rv = MEM_callocN(sizeof(RenderView), "new opengl render view");
+ if (rv == nullptr) {
+ rv = MEM_cnew<RenderView>("new opengl render view");
BLI_strncpy(rv->name, srv->name, sizeof(rv->name));
BLI_addtail(&rr->views, rv);
}
@@ -291,19 +293,19 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
ARegion *region = oglrender->region;
View3D *v3d = oglrender->v3d;
RegionView3D *rv3d = oglrender->rv3d;
- Object *camera = NULL;
+ Object *camera = nullptr;
int sizex = oglrender->sizex;
int sizey = oglrender->sizey;
- const short view_context = (v3d != NULL);
+ const short view_context = (v3d != nullptr);
bool draw_sky = (scene->r.alphamode == R_ADDSKY);
- float *rectf = NULL;
- uchar *rect = NULL;
+ float *rectf = nullptr;
+ uchar *rect = nullptr;
const char *viewname = RE_GetActiveRenderView(oglrender->re);
- ImBuf *ibuf_result = NULL;
+ ImBuf *ibuf_result = nullptr;
if (oglrender->is_sequencer) {
SpaceSeq *sseq = oglrender->sseq;
- struct bGPdata *gpd = (sseq && (sseq->flag & SEQ_PREVIEW_SHOW_GPENCIL)) ? sseq->gpd : NULL;
+ struct bGPdata *gpd = (sseq && (sseq->flag & SEQ_PREVIEW_SHOW_GPENCIL)) ? sseq->gpd : nullptr;
/* use pre-calculated ImBuf (avoids deadlock), see: */
ImBuf *ibuf = oglrender->seq_data.ibufs_arr[oglrender->view_id];
@@ -318,7 +320,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
* TODO(sergey): In the case of output to float container (EXR)
* it actually makes sense to keep float buffer instead.
*/
- if (out->rect_float != NULL) {
+ if (out->rect_float != nullptr) {
IMB_rect_from_float(out);
imb_freerectfloatImBuf(out);
}
@@ -352,7 +354,8 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
ED_annotation_draw_ex(scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ);
G.f &= ~G_FLAG_RENDER_VIEWPORT;
- gp_rect = MEM_mallocN(sizeof(uchar[4]) * sizex * sizey, "offscreen rect");
+ gp_rect = static_cast<uchar *>(
+ MEM_mallocN(sizeof(uchar[4]) * sizex * sizey, "offscreen rect"));
GPU_offscreen_read_pixels(oglrender->ofs, GPU_DATA_UBYTE, gp_rect);
for (i = 0; i < sizex * sizey * 4; i += 4) {
@@ -372,7 +375,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
if (view_context) {
ibuf_view = ED_view3d_draw_offscreen_imbuf(depsgraph,
scene,
- v3d->shading.type,
+ static_cast<eDrawType>(v3d->shading.type),
v3d,
region,
sizex,
@@ -392,7 +395,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
else {
ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(depsgraph,
scene,
- NULL,
+ nullptr,
OB_SOLID,
scene->camera,
oglrender->sizex,
@@ -420,9 +423,9 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
}
}
- if (ibuf_result != NULL) {
+ if (ibuf_result != nullptr) {
if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) {
- BKE_image_stamp_buf(scene, camera, NULL, rect, rectf, rr->rectx, rr->recty, 4);
+ BKE_image_stamp_buf(scene, camera, nullptr, rect, rectf, rr->rectx, rr->recty, 4);
}
RE_render_result_rect_from_ibuf(rr, &scene->r, ibuf_result, oglrender->view_id);
IMB_freeImBuf(ibuf_result);
@@ -445,7 +448,7 @@ static void screen_opengl_render_write(OGLRender *oglrender)
&scene->r.im_format,
(scene->r.scemode & R_EXTENSION) != 0,
false,
- NULL);
+ nullptr);
/* write images as individual images or stereo */
BKE_render_result_stamp_info(scene, scene->camera, rr, false);
@@ -506,7 +509,8 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender)
}
rr = RE_AcquireResultRead(oglrender->re);
- for (rv = rr->views.first, view_id = 0; rv; rv = rv->next, view_id++) {
+ for (rv = static_cast<RenderView *>(rr->views.first), view_id = 0; rv;
+ rv = rv->next, view_id++) {
BLI_assert(view_id < oglrender->views_len);
RE_SetActiveRenderView(oglrender->re, rv->name);
oglrender->view_id = view_id;
@@ -530,7 +534,7 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender)
static void gather_frames_to_render_for_adt(const OGLRender *oglrender, const AnimData *adt)
{
- if (adt == NULL || adt->action == NULL) {
+ if (adt == nullptr || adt->action == nullptr) {
return;
}
@@ -539,7 +543,7 @@ static void gather_frames_to_render_for_adt(const OGLRender *oglrender, const An
int frame_end = PEFRA;
LISTBASE_FOREACH (FCurve *, fcu, &adt->action->curves) {
- if (fcu->driver != NULL || fcu->fpt != NULL) {
+ if (fcu->driver != nullptr || fcu->fpt != nullptr) {
/* Drivers have values for any point in time, so to get "the keyed frames" they are
* useless. Same for baked FCurves, they also have keys for every frame, which is not
* useful for rendering the keyed subset of the frames. */
@@ -568,7 +572,7 @@ static void gather_frames_to_render_for_adt(const OGLRender *oglrender, const An
static void gather_frames_to_render_for_grease_pencil(const OGLRender *oglrender,
const bGPdata *gp)
{
- if (gp == NULL) {
+ if (gp == nullptr) {
return;
}
@@ -589,7 +593,7 @@ static void gather_frames_to_render_for_grease_pencil(const OGLRender *oglrender
static int gather_frames_to_render_for_id(LibraryIDLinkCallbackData *cb_data)
{
ID **id_p = cb_data->id_pointer;
- if (*id_p == NULL) {
+ if (*id_p == nullptr) {
return IDWALK_RET_NOP;
}
ID *id = *id_p;
@@ -602,7 +606,7 @@ static int gather_frames_to_render_for_id(LibraryIDLinkCallbackData *cb_data)
return IDWALK_RET_STOP_RECURSION;
}
- OGLRender *oglrender = cb_data->user_data;
+ OGLRender *oglrender = static_cast<OGLRender *>(cb_data->user_data);
/* Whitelist of datablocks to follow pointers into. */
const ID_Type id_type = GS(id->name);
@@ -699,7 +703,7 @@ static void gather_frames_to_render(bContext *C, OGLRender *oglrender)
/* Gather the frames from linked data-blocks (materials, shape-keys, etc.). */
BKE_library_foreach_ID_link(
- NULL, id, gather_frames_to_render_for_id, oglrender, IDWALK_RECURSE);
+ nullptr, id, gather_frames_to_render_for_id, oglrender, IDWALK_RECURSE);
}
CTX_DATA_END;
}
@@ -722,8 +726,8 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
const bool is_render_keyed_only = RNA_boolean_get(op->ptr, "render_keyed_only");
const bool is_sequencer = RNA_boolean_get(op->ptr, "sequencer");
const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
- const eImageFormatDepth color_depth = (is_animation) ? scene->r.im_format.depth :
- R_IMF_CHAN_DEPTH_32;
+ const eImageFormatDepth color_depth = static_cast<eImageFormatDepth>(
+ (is_animation) ? (eImageFormatDepth)scene->r.im_format.depth : R_IMF_CHAN_DEPTH_32);
char err_out[256] = "unknown";
if (G.background) {
@@ -747,7 +751,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
is_view_context = false;
}
- if (!is_view_context && scene->camera == NULL) {
+ if (!is_view_context && scene->camera == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Scene has no camera");
return false;
}
@@ -777,7 +781,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
}
/* allocate opengl render */
- oglrender = MEM_callocN(sizeof(OGLRender), "OGLRender");
+ oglrender = MEM_new<OGLRender>("OGLRender");
op->customdata = oglrender;
oglrender->ofs = ofs;
@@ -801,7 +805,8 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
oglrender->is_sequencer = is_sequencer;
if (is_sequencer) {
oglrender->sseq = CTX_wm_space_seq(C);
- ImBuf **ibufs_arr = MEM_callocN(sizeof(*ibufs_arr) * oglrender->views_len, __func__);
+ ImBuf **ibufs_arr = static_cast<ImBuf **>(
+ MEM_callocN(sizeof(*ibufs_arr) * oglrender->views_len, __func__));
oglrender->seq_data.ibufs_arr = ibufs_arr;
}
@@ -812,7 +817,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
/* so quad view renders camera */
ED_view3d_context_user_region(C, &oglrender->v3d, &oglrender->region);
- oglrender->rv3d = oglrender->region->regiondata;
+ oglrender->rv3d = static_cast<RegionView3D *>(oglrender->region->regiondata);
/* MUST be cleared on exit */
memset(&oglrender->scene->customdata_mask_modal,
@@ -832,13 +837,14 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
/* create image and image user */
oglrender->ima = BKE_image_ensure_viewer(oglrender->bmain, IMA_TYPE_R_RESULT, "Render Result");
- BKE_image_signal(oglrender->bmain, oglrender->ima, NULL, IMA_SIGNAL_FREE);
+ BKE_image_signal(oglrender->bmain, oglrender->ima, nullptr, IMA_SIGNAL_FREE);
BKE_image_backup_render(oglrender->scene, oglrender->ima, true);
oglrender->iuser.scene = scene;
/* create render result */
- RE_InitState(oglrender->re, NULL, &scene->r, &scene->view_layers, NULL, sizex, sizey, NULL);
+ RE_InitState(
+ oglrender->re, nullptr, &scene->r, &scene->view_layers, nullptr, sizex, sizey, nullptr);
/* create render views */
screen_opengl_views_setup(oglrender);
@@ -848,8 +854,8 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
oglrender->win = win;
oglrender->totvideos = 0;
- oglrender->mh = NULL;
- oglrender->movie_ctx_arr = NULL;
+ oglrender->mh = nullptr;
+ oglrender->movie_ctx_arr = nullptr;
if (is_animation) {
if (is_render_keyed_only) {
@@ -866,7 +872,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
BLI_spin_init(&oglrender->reports_lock);
}
else {
- oglrender->task_pool = NULL;
+ oglrender->task_pool = nullptr;
}
oglrender->num_scheduled_frames = 0;
BLI_mutex_init(&oglrender->task_mutex);
@@ -954,12 +960,12 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
CTX_wm_area_set(C, oglrender->prevsa);
CTX_wm_region_set(C, oglrender->prevar);
- MEM_freeN(oglrender);
+ MEM_delete(oglrender);
}
static void screen_opengl_render_cancel(bContext *C, wmOperator *op)
{
- screen_opengl_render_end(C, op->customdata);
+ screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
}
/* share between invoke and exec */
@@ -969,7 +975,7 @@ static bool screen_opengl_render_anim_init(bContext *C, wmOperator *op)
OGLRender *oglrender;
Scene *scene;
- oglrender = op->customdata;
+ oglrender = static_cast<OGLRender *>(op->customdata);
scene = oglrender->scene;
oglrender->totvideos = BKE_scene_multiview_num_videos_get(&scene->r);
@@ -983,13 +989,14 @@ static bool screen_opengl_render_anim_init(bContext *C, wmOperator *op)
&scene->r, oglrender->sizex, oglrender->sizey, &width, &height);
oglrender->mh = BKE_movie_handle_get(scene->r.im_format.imtype);
- if (oglrender->mh == NULL) {
+ if (oglrender->mh == nullptr) {
BKE_report(oglrender->reports, RPT_ERROR, "Movie format unsupported");
screen_opengl_render_end(C, oglrender);
return false;
}
- oglrender->movie_ctx_arr = MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies");
+ oglrender->movie_ctx_arr = static_cast<void **>(
+ MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies"));
for (i = 0; i < oglrender->totvideos; i++) {
Scene *scene_eval = DEG_get_evaluated_scene(oglrender->depsgraph);
@@ -1017,10 +1024,10 @@ static bool screen_opengl_render_anim_init(bContext *C, wmOperator *op)
return true;
}
-typedef struct WriteTaskData {
+struct WriteTaskData {
RenderResult *rr;
Scene tmp_scene;
-} WriteTaskData;
+};
static void write_result_func(TaskPool *__restrict pool, void *task_data_v)
{
@@ -1073,18 +1080,19 @@ static void write_result_func(TaskPool *__restrict pool, void *task_data_v)
&scene->r.im_format,
(scene->r.scemode & R_EXTENSION) != 0,
true,
- NULL);
+ nullptr);
BKE_render_result_stamp_info(scene, scene->camera, rr, false);
- ok = RE_WriteRenderViewsImage(NULL, rr, scene, true, name);
+ ok = RE_WriteRenderViewsImage(nullptr, rr, scene, true, name);
if (!ok) {
BKE_reportf(&reports, RPT_ERROR, "Write error: cannot save %s", name);
}
}
- if (reports.list.first != NULL) {
+ if (reports.list.first != nullptr) {
BLI_spin_lock(&oglrender->reports_lock);
- for (Report *report = reports.list.first; report != NULL; report = report->next) {
- BKE_report(oglrender->reports, report->type, report->message);
+ for (Report *report = static_cast<Report *>(reports.list.first); report != nullptr;
+ report = report->next) {
+ BKE_report(oglrender->reports, static_cast<eReportType>(report->type), report->message);
}
BLI_spin_unlock(&oglrender->reports_lock);
}
@@ -1105,27 +1113,27 @@ static bool schedule_write_result(OGLRender *oglrender, RenderResult *rr)
return false;
}
Scene *scene = oglrender->scene;
- WriteTaskData *task_data = MEM_mallocN(sizeof(WriteTaskData), "write task data");
+ WriteTaskData *task_data = MEM_new<WriteTaskData>("write task data");
task_data->rr = rr;
- task_data->tmp_scene = *scene;
+ memcpy(&task_data->tmp_scene, scene, sizeof(task_data->tmp_scene));
BLI_mutex_lock(&oglrender->task_mutex);
oglrender->num_scheduled_frames++;
if (oglrender->num_scheduled_frames > MAX_SCHEDULED_FRAMES) {
BLI_condition_wait(&oglrender->task_condition, &oglrender->task_mutex);
}
BLI_mutex_unlock(&oglrender->task_mutex);
- BLI_task_pool_push(oglrender->task_pool, write_result_func, task_data, true, NULL);
+ BLI_task_pool_push(oglrender->task_pool, write_result_func, task_data, true, nullptr);
return true;
}
static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
{
- OGLRender *oglrender = op->customdata;
+ OGLRender *oglrender = static_cast<OGLRender *>(op->customdata);
Scene *scene = oglrender->scene;
Depsgraph *depsgraph = oglrender->depsgraph;
char name[FILE_MAX];
bool ok = false;
- const bool view_context = (oglrender->v3d != NULL);
+ const bool view_context = (oglrender->v3d != nullptr);
bool is_movie;
RenderResult *rr;
@@ -1148,7 +1156,7 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
&scene->r.im_format,
(scene->r.scemode & R_EXTENSION) != 0,
true,
- NULL);
+ nullptr);
if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) {
BLI_spin_lock(&oglrender->reports_lock);
@@ -1177,7 +1185,7 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
BKE_scene_camera_switch_update(scene);
}
- if (oglrender->render_frames == NULL ||
+ if (oglrender->render_frames == nullptr ||
BLI_BITMAP_TEST_BOOL(oglrender->render_frames, CFRA - PSFRA)) {
/* render into offscreen buffer */
screen_opengl_render_apply(C, oglrender);
@@ -1185,10 +1193,12 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
/* save to disk */
rr = RE_AcquireResultRead(oglrender->re);
- RenderResult *new_rr = RE_DuplicateRenderResult(rr);
- RE_ReleaseResult(oglrender->re);
+ {
+ RenderResult *new_rr = RE_DuplicateRenderResult(rr);
+ RE_ReleaseResult(oglrender->re);
- ok = schedule_write_result(oglrender, new_rr);
+ ok = schedule_write_result(oglrender, new_rr);
+ }
finally: /* Step the frame and bail early if needed */
@@ -1197,16 +1207,16 @@ finally: /* Step the frame and bail early if needed */
/* stop at the end or on error */
if (CFRA >= PEFRA || !ok) {
- screen_opengl_render_end(C, op->customdata);
- return 0;
+ screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
+ return false;
}
- return 1;
+ return true;
}
static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- OGLRender *oglrender = op->customdata;
+ OGLRender *oglrender = static_cast<OGLRender *>(op->customdata);
const bool anim = RNA_boolean_get(op->ptr, "animation");
bool ret;
@@ -1214,7 +1224,7 @@ static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent
case EVT_ESCKEY:
/* cancel */
oglrender->pool_ok = false; /* Flag pool for cancel. */
- screen_opengl_render_end(C, op->customdata);
+ screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
return OPERATOR_FINISHED;
case TIMER:
/* render frame? */
@@ -1231,8 +1241,8 @@ static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, oglrender->scene);
if (anim == 0) {
- screen_opengl_render_apply(C, op->customdata);
- screen_opengl_render_end(C, op->customdata);
+ screen_opengl_render_apply(C, static_cast<OGLRender *>(op->customdata));
+ screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
return OPERATOR_FINISHED;
}
@@ -1261,7 +1271,7 @@ static int screen_opengl_render_invoke(bContext *C, wmOperator *op, const wmEven
}
}
- oglrender = op->customdata;
+ oglrender = static_cast<OGLRender *>(op->customdata);
render_view_open(C, event->xy[0], event->xy[1], op->reports);
/* View may be changed above #USER_RENDER_DISPLAY_WINDOW. */
@@ -1284,8 +1294,8 @@ static int screen_opengl_render_exec(bContext *C, wmOperator *op)
if (!is_animation) { /* same as invoke */
/* render image */
- screen_opengl_render_apply(C, op->customdata);
- screen_opengl_render_end(C, op->customdata);
+ screen_opengl_render_apply(C, static_cast<OGLRender *>(op->customdata));
+ screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
return OPERATOR_FINISHED;
}
@@ -1312,7 +1322,7 @@ static char *screen_opengl_render_description(struct bContext *UNUSED(C),
struct PointerRNA *ptr)
{
if (!RNA_boolean_get(ptr, "animation")) {
- return NULL;
+ return nullptr;
}
if (RNA_boolean_get(ptr, "render_keyed_only")) {
@@ -1344,32 +1354,32 @@ void RENDER_OT_opengl(wmOperatorType *ot)
prop = RNA_def_boolean(ot->srna,
"animation",
- 0,
+ false,
"Animation",
"Render files from the animation range of this scene");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna,
"render_keyed_only",
- 0,
+ false,
"Render Keyframes Only",
"Render only those frames where selected objects have a key in their "
"animation data. Only used when rendering animation");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(
- ot->srna, "sequencer", 0, "Sequencer", "Render using the sequencer's OpenGL display");
+ ot->srna, "sequencer", false, "Sequencer", "Render using the sequencer's OpenGL display");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(
ot->srna,
"write_still",
- 0,
+ false,
"Write Image",
"Save rendered the image to the output path (used only when animation is disabled)");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna,
"view_context",
- 1,
+ true,
"View Context",
"Use the current 3D view for rendering, else use scene settings");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
diff --git a/source/blender/editors/render/render_ops.c b/source/blender/editors/render/render_ops.cc
index e0aa02b354d..0f10d186e6e 100644
--- a/source/blender/editors/render/render_ops.c
+++ b/source/blender/editors/render/render_ops.cc
@@ -21,7 +21,7 @@
* \ingroup edrend
*/
-#include <stdlib.h>
+#include <cstdlib>
#include "BLI_utildefines.h"
@@ -29,11 +29,11 @@
#include "WM_api.h"
-#include "render_intern.h" /* own include */
+#include "render_intern.hh" /* own include */
/***************************** render ***********************************/
-void ED_operatortypes_render(void)
+void ED_operatortypes_render()
{
WM_operatortype_append(OBJECT_OT_material_slot_add);
WM_operatortype_append(OBJECT_OT_material_slot_remove);
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.cc
index e1121aa4b1e..79c3b2f7ac6 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.cc
@@ -23,9 +23,9 @@
/* global includes */
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
+#include <cmath>
+#include <cstdlib>
+#include <cstring>
#ifndef WIN32
# include <unistd.h>
@@ -116,7 +116,7 @@ static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect);
/** \name Local Structs
* \{ */
-typedef struct ShaderPreview {
+struct ShaderPreview {
/* from wmJob */
void *owner;
short *stop, *do_update;
@@ -137,31 +137,32 @@ typedef struct ShaderPreview {
int sizex, sizey;
uint *pr_rect;
- int pr_method;
+ ePreviewRenderMethod pr_method;
bool own_id_copy;
Main *bmain;
Main *pr_main;
-} ShaderPreview;
+};
-typedef struct IconPreviewSize {
+struct IconPreviewSize {
struct IconPreviewSize *next, *prev;
int sizex, sizey;
uint *rect;
-} IconPreviewSize;
+};
-typedef struct IconPreview {
+struct IconPreview {
Main *bmain;
- Depsgraph *depsgraph; /* May be NULL (see #WM_OT_previews_ensure). */
+ Depsgraph *depsgraph; /* May be nullptr (see #WM_OT_previews_ensure). */
Scene *scene;
void *owner;
- ID *id, *id_copy; /* May be NULL! (see ICON_TYPE_PREVIEW case in #ui_icon_ensure_deferred()) */
+ ID *id,
+ *id_copy; /* May be nullptr! (see ICON_TYPE_PREVIEW case in #ui_icon_ensure_deferred()) */
ListBase sizes;
- /* May be NULL, is used for rendering IDs that require some other object for it to be applied on
- * before the ID can be represented as an image, for example when rendering an Action. */
+ /* May be nullptr, is used for rendering IDs that require some other object for it to be applied
+ * on before the ID can be represented as an image, for example when rendering an Action. */
struct Object *active_object;
-} IconPreview;
+};
/** \} */
@@ -169,18 +170,18 @@ typedef struct IconPreview {
/** \name Preview for Buttons
* \{ */
-static Main *G_pr_main = NULL;
-static Main *G_pr_main_grease_pencil = NULL;
+static Main *G_pr_main = nullptr;
+static Main *G_pr_main_grease_pencil = nullptr;
#ifndef WITH_HEADLESS
static Main *load_main_from_memory(const void *blend, int blend_size)
{
const int fileflags = G.fileflags;
- Main *bmain = NULL;
+ Main *bmain = nullptr;
BlendFileData *bfd;
G.fileflags |= G_FILE_NO_UI;
- bfd = BLO_read_from_memory(blend, blend_size, BLO_READ_SKIP_NONE, NULL);
+ bfd = BLO_read_from_memory(blend, blend_size, BLO_READ_SKIP_NONE, nullptr);
if (bfd) {
bmain = bfd->main;
@@ -192,7 +193,7 @@ static Main *load_main_from_memory(const void *blend, int blend_size)
}
#endif
-void ED_preview_ensure_dbase(void)
+void ED_preview_ensure_dbase()
{
#ifndef WITH_HEADLESS
static bool base_initialized = false;
@@ -212,12 +213,12 @@ static bool check_engine_supports_preview(Scene *scene)
return (type->flag & RE_USE_PREVIEW) != 0;
}
-static bool preview_method_is_render(int pr_method)
+static bool preview_method_is_render(const ePreviewRenderMethod pr_method)
{
- return ELEM(pr_method, PR_ICON_RENDER, PR_BUTS_RENDER, PR_NODE_RENDER);
+ return ELEM(pr_method, PR_ICON_RENDER, PR_BUTS_RENDER);
}
-void ED_preview_free_dbase(void)
+void ED_preview_free_dbase()
{
if (G_pr_main) {
BKE_main_free(G_pr_main);
@@ -230,11 +231,11 @@ void ED_preview_free_dbase(void)
static Scene *preview_get_scene(Main *pr_main)
{
- if (pr_main == NULL) {
- return NULL;
+ if (pr_main == nullptr) {
+ return nullptr;
}
- return pr_main->scenes.first;
+ return static_cast<Scene *>(pr_main->scenes.first);
}
static const char *preview_collection_name(const ePreviewType pr_type)
@@ -276,10 +277,10 @@ static bool render_engine_supports_ray_visibility(const Scene *sce)
static void switch_preview_collection_visibilty(ViewLayer *view_layer, const ePreviewType pr_type)
{
/* Set appropriate layer as visible. */
- LayerCollection *lc = view_layer->layer_collections.first;
+ LayerCollection *lc = static_cast<LayerCollection *>(view_layer->layer_collections.first);
const char *collection_name = preview_collection_name(pr_type);
- for (lc = lc->layer_collections.first; lc; lc = lc->next) {
+ for (lc = static_cast<LayerCollection *>(lc->layer_collections.first); lc; lc = lc->next) {
if (STREQ(lc->collection->id.name + 2, collection_name)) {
lc->collection->flag &= ~COLLECTION_HIDE_RENDER;
}
@@ -308,7 +309,8 @@ static void switch_preview_floor_material(Main *pr_main,
}
const char *material_name = preview_floor_material_name(scene, pr_method);
- Material *mat = BLI_findstring(&pr_main->materials, material_name, offsetof(ID, name) + 2);
+ Material *mat = static_cast<Material *>(
+ BLI_findstring(&pr_main->materials, material_name, offsetof(ID, name) + 2));
if (mat) {
me->mat[0] = mat;
}
@@ -329,7 +331,8 @@ static void switch_preview_floor_visibility(Main *pr_main,
}
}
if (base->object->type == OB_MESH) {
- switch_preview_floor_material(pr_main, base->object->data, scene, pr_method);
+ switch_preview_floor_material(
+ pr_main, static_cast<Mesh *>(base->object->data), scene, pr_method);
}
}
}
@@ -348,16 +351,16 @@ static void set_preview_visibility(Main *pr_main,
static World *preview_get_localized_world(ShaderPreview *sp, World *world)
{
- if (world == NULL) {
- return NULL;
+ if (world == nullptr) {
+ return nullptr;
}
- if (sp->worldcopy != NULL) {
+ if (sp->worldcopy != nullptr) {
return sp->worldcopy;
}
- ID *id_copy = BKE_id_copy_ex(NULL,
+ ID *id_copy = BKE_id_copy_ex(nullptr,
&world->id,
- NULL,
+ nullptr,
LIB_ID_CREATE_LOCAL | LIB_ID_COPY_LOCALIZE |
LIB_ID_COPY_NO_ANIMDATA);
sp->worldcopy = (World *)id_copy;
@@ -367,9 +370,9 @@ static World *preview_get_localized_world(ShaderPreview *sp, World *world)
static ID *duplicate_ids(ID *id, const bool allow_failure)
{
- if (id == NULL) {
+ if (id == nullptr) {
/* Non-ID preview render. */
- return NULL;
+ return nullptr;
}
switch (GS(id->name)) {
@@ -379,20 +382,23 @@ static ID *duplicate_ids(ID *id, const bool allow_failure)
case ID_LA:
case ID_WO: {
BLI_assert(BKE_previewimg_id_supports_jobs(id));
- ID *id_copy = BKE_id_copy_ex(
- NULL, id, NULL, LIB_ID_CREATE_LOCAL | LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA);
+ ID *id_copy = BKE_id_copy_ex(nullptr,
+ id,
+ nullptr,
+ LIB_ID_CREATE_LOCAL | LIB_ID_COPY_LOCALIZE |
+ LIB_ID_COPY_NO_ANIMDATA);
return id_copy;
}
/* These support threading, but don't need duplicating. */
case ID_IM:
case ID_BR:
BLI_assert(BKE_previewimg_id_supports_jobs(id));
- return NULL;
+ return nullptr;
default:
if (!allow_failure) {
BLI_assert_msg(0, "ID type preview not supported.");
}
- return NULL;
+ return nullptr;
}
}
@@ -404,8 +410,8 @@ static const char *preview_world_name(const Scene *sce,
* material trick to show the floor in the reflections, but hide the floor for camera rays. For
* Eevee we use a transparent world that has a projected grid.
*
- * In the future when Eevee supports vulkan raytracing we can re-evaluate and perhaps remove this
- * approximation.
+ * In the future when Eevee supports VULKAN ray-tracing we can re-evaluate and perhaps remove
+ * this approximation.
*/
if (id_type == ID_MA && pr_method == PR_ICON_RENDER &&
!render_engine_supports_ray_visibility(sce)) {
@@ -419,13 +425,14 @@ static World *preview_get_world(Main *pr_main,
const ID_Type id_type,
const ePreviewRenderMethod pr_method)
{
- World *result = NULL;
+ World *result = nullptr;
const char *world_name = preview_world_name(sce, id_type, pr_method);
- result = BLI_findstring(&pr_main->worlds, world_name, offsetof(ID, name) + 2);
+ result = static_cast<World *>(
+ BLI_findstring(&pr_main->worlds, world_name, offsetof(ID, name) + 2));
/* No world found return first world. */
- if (result == NULL) {
- result = pr_main->worlds.first;
+ if (result == nullptr) {
+ result = static_cast<World *>(pr_main->worlds.first);
}
BLI_assert_msg(result, "Preview file has no world.");
@@ -454,7 +461,7 @@ static World *preview_prepare_world(Main *pr_main,
}
/* call this with a pointer to initialize preview scene */
-/* call this with NULL to restore assigned ID pointers in preview scene */
+/* call this with nullptr to restore assigned ID pointers in preview scene */
static Scene *preview_prepare_scene(
Main *bmain, Scene *scene, ID *id, int id_type, ShaderPreview *sp)
{
@@ -465,7 +472,7 @@ static Scene *preview_prepare_scene(
sce = preview_get_scene(pr_main);
if (sce) {
- ViewLayer *view_layer = sce->view_layers.first;
+ ViewLayer *view_layer = static_cast<ViewLayer *>(sce->view_layers.first);
/* Only enable the combined renderpass */
view_layer->passflag = SCE_PASS_COMBINED;
@@ -491,7 +498,8 @@ static Scene *preview_prepare_scene(
sce->r.cfra = scene->r.cfra;
/* Setup the world. */
- sce->world = preview_prepare_world(pr_main, sce, scene->world, id_type, sp->pr_method);
+ sce->world = preview_prepare_world(
+ pr_main, sce, scene->world, static_cast<ID_Type>(id_type), sp->pr_method);
if (id_type == ID_TE) {
/* Texture is not actually rendered with engine, just set dummy value. */
@@ -499,13 +507,13 @@ static Scene *preview_prepare_scene(
}
if (id_type == ID_MA) {
- Material *mat = NULL, *origmat = (Material *)id;
+ Material *mat = nullptr, *origmat = (Material *)id;
if (origmat) {
/* work on a copy */
- BLI_assert(sp->id_copy != NULL);
+ BLI_assert(sp->id_copy != nullptr);
mat = sp->matcopy = (Material *)sp->id_copy;
- sp->id_copy = NULL;
+ sp->id_copy = nullptr;
BLI_addtail(&pr_main->materials, mat);
/* Use current scene world for lighting. */
@@ -523,20 +531,11 @@ static Scene *preview_prepare_scene(
}
/* For grease pencil, always use sphere for icon renders. */
- const ePreviewType preview_type = (sp->pr_method == PR_ICON_RENDER &&
- sp->pr_main == G_pr_main_grease_pencil) ?
- MA_SPHERE_A :
- mat->pr_type;
+ const ePreviewType preview_type = static_cast<ePreviewType>(
+ (sp->pr_method == PR_ICON_RENDER && sp->pr_main == G_pr_main_grease_pencil) ?
+ MA_SPHERE_A :
+ (ePreviewType)mat->pr_type);
set_preview_visibility(pr_main, sce, view_layer, preview_type, sp->pr_method);
-
- if (sp->pr_method != PR_ICON_RENDER) {
- if (mat->nodetree && sp->pr_method == PR_NODE_RENDER) {
- /* two previews, they get copied by wmJob */
- BKE_node_preview_init_tree(mat->nodetree, sp->sizex, sp->sizey, true);
- /* WATCH: Accessing origmat is not safe! */
- BKE_node_preview_init_tree(origmat->nodetree, sp->sizex, sp->sizey, true);
- }
- }
}
else {
sce->display.render_aa = SCE_DISPLAY_AA_OFF;
@@ -564,30 +563,23 @@ static Scene *preview_prepare_scene(
}
}
else if (id_type == ID_TE) {
- Tex *tex = NULL, *origtex = (Tex *)id;
+ Tex *tex = nullptr, *origtex = (Tex *)id;
if (origtex) {
- BLI_assert(sp->id_copy != NULL);
+ BLI_assert(sp->id_copy != nullptr);
tex = sp->texcopy = (Tex *)sp->id_copy;
- sp->id_copy = NULL;
+ sp->id_copy = nullptr;
BLI_addtail(&pr_main->textures, tex);
}
-
- if (tex && tex->nodetree && sp->pr_method == PR_NODE_RENDER) {
- /* two previews, they get copied by wmJob */
- BKE_node_preview_init_tree(tex->nodetree, sp->sizex, sp->sizey, true);
- /* WATCH: Accessing origtex is not safe! */
- BKE_node_preview_init_tree(origtex->nodetree, sp->sizex, sp->sizey, true);
- }
}
else if (id_type == ID_LA) {
- Light *la = NULL, *origla = (Light *)id;
+ Light *la = nullptr, *origla = (Light *)id;
/* work on a copy */
if (origla) {
- BLI_assert(sp->id_copy != NULL);
+ BLI_assert(sp->id_copy != nullptr);
la = sp->lampcopy = (Light *)sp->id_copy;
- sp->id_copy = NULL;
+ sp->id_copy = nullptr;
BLI_addtail(&pr_main->lights, la);
}
@@ -608,39 +600,25 @@ static Scene *preview_prepare_scene(
}
}
}
-
- if (la && la->nodetree && sp->pr_method == PR_NODE_RENDER) {
- /* two previews, they get copied by wmJob */
- BKE_node_preview_init_tree(la->nodetree, sp->sizex, sp->sizey, true);
- /* WATCH: Accessing origla is not safe! */
- BKE_node_preview_init_tree(origla->nodetree, sp->sizex, sp->sizey, true);
- }
}
else if (id_type == ID_WO) {
- World *wrld = NULL, *origwrld = (World *)id;
+ World *wrld = nullptr, *origwrld = (World *)id;
if (origwrld) {
- BLI_assert(sp->id_copy != NULL);
+ BLI_assert(sp->id_copy != nullptr);
wrld = sp->worldcopy = (World *)sp->id_copy;
- sp->id_copy = NULL;
+ sp->id_copy = nullptr;
BLI_addtail(&pr_main->worlds, wrld);
}
set_preview_visibility(pr_main, sce, view_layer, MA_SKY, sp->pr_method);
sce->world = wrld;
-
- if (wrld && wrld->nodetree && sp->pr_method == PR_NODE_RENDER) {
- /* two previews, they get copied by wmJob */
- BKE_node_preview_init_tree(wrld->nodetree, sp->sizex, sp->sizey, true);
- /* WATCH: Accessing origwrld is not safe! */
- BKE_node_preview_init_tree(origwrld->nodetree, sp->sizex, sp->sizey, true);
- }
}
return sce;
}
- return NULL;
+ return nullptr;
}
/* new UI convention: draw is in pixel space already. */
@@ -677,7 +655,7 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect
/* test if something rendered ok */
re = RE_GetRender(name);
- if (re == NULL) {
+ if (re == nullptr) {
return false;
}
@@ -689,7 +667,7 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect
}
else {
/* possible the job clears the views but we're still drawing T45496 */
- rv = NULL;
+ rv = nullptr;
}
if (rv && rv->rectf) {
@@ -700,8 +678,8 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect
newrect->ymax = max_ii(newrect->ymax, rect->ymin + rres.recty);
if (rres.rectx && rres.recty) {
- uchar *rect_byte = MEM_mallocN(rres.rectx * rres.recty * sizeof(int),
- "ed_preview_draw_rect");
+ uchar *rect_byte = static_cast<uchar *>(
+ MEM_mallocN(rres.rectx * rres.recty * sizeof(int), "ed_preview_draw_rect"));
float fx = rect->xmin + offx;
float fy = rect->ymin;
@@ -709,12 +687,21 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect
RE_AcquiredResultGet32(re, &rres, (uint *)rect_byte, 0);
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- immDrawPixelsTex(
- &state, fx, fy, rres.rectx, rres.recty, GPU_RGBA8, false, rect_byte, 1.0f, 1.0f, NULL);
+ immDrawPixelsTexTiled(&state,
+ fx,
+ fy,
+ rres.rectx,
+ rres.recty,
+ GPU_RGBA8,
+ false,
+ rect_byte,
+ 1.0f,
+ 1.0f,
+ nullptr);
MEM_freeN(rect_byte);
- ok = 1;
+ ok = true;
}
}
}
@@ -733,9 +720,9 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r
ID *parent = (ID *)parentp;
MTex *slot = (MTex *)slotp;
SpaceProperties *sbuts = CTX_wm_space_properties(C);
- ShaderPreview *sp = WM_jobs_customdata(wm, area);
+ ShaderPreview *sp = static_cast<ShaderPreview *>(WM_jobs_customdata(wm, area));
rcti newrect;
- int ok;
+ bool ok;
int newx = BLI_rcti_size_x(rect);
int newy = BLI_rcti_size_y(rect);
@@ -759,10 +746,10 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r
/* start a new preview render job if signaled through sbuts->preview,
* if no render result was found and no preview render job is running,
* or if the job is running and the size of preview changed */
- if ((sbuts != NULL && sbuts->preview) ||
+ if ((sbuts != nullptr && sbuts->preview) ||
(!ok && !WM_jobs_test(wm, area, WM_JOB_TYPE_RENDER_PREVIEW)) ||
(sp && (abs(sp->sizex - newx) >= 2 || abs(sp->sizey - newy) > 2))) {
- if (sbuts != NULL) {
+ if (sbuts != nullptr) {
sbuts->preview = 0;
}
ED_preview_shader_job(C, area, id, parent, slot, newx, newy, PR_BUTS_RENDER);
@@ -826,11 +813,11 @@ static Scene *object_preview_scene_create(const struct ObjectPreviewData *previe
* viewport displays. */
CFRA = preview_data->cfra;
- ViewLayer *view_layer = scene->view_layers.first;
+ ViewLayer *view_layer = static_cast<ViewLayer *>(scene->view_layers.first);
Depsgraph *depsgraph = DEG_graph_new(
preview_data->pr_main, scene, view_layer, DAG_EVAL_VIEWPORT);
- BLI_assert(preview_data->object != NULL);
+ BLI_assert(preview_data->object != nullptr);
BLI_addtail(&preview_data->pr_main->objects, preview_data->object);
BKE_collection_object_add(preview_data->pr_main, scene->master_collection, preview_data->object);
@@ -861,26 +848,23 @@ static Scene *object_preview_scene_create(const struct ObjectPreviewData *previe
static void object_preview_render(IconPreview *preview, IconPreviewSize *preview_sized)
{
Main *preview_main = BKE_main_new();
- const float pixelsize_old = U.pixelsize;
char err_out[256] = "unknown";
BLI_assert(preview->id_copy && (preview->id_copy != preview->id));
- struct ObjectPreviewData preview_data = {
- .pr_main = preview_main,
- /* Act on a copy. */
- .object = (Object *)preview->id_copy,
- .cfra = preview->scene->r.cfra,
- .sizex = preview_sized->sizex,
- .sizey = preview_sized->sizey,
- };
+ struct ObjectPreviewData preview_data = {};
+ preview_data.pr_main = preview_main;
+ /* Act on a copy. */
+ preview_data.object = (Object *)preview->id_copy;
+ preview_data.cfra = preview->scene->r.cfra;
+ preview_data.sizex = preview_sized->sizex;
+ preview_data.sizey = preview_sized->sizey;
+
Depsgraph *depsgraph;
Scene *scene = object_preview_scene_create(&preview_data, &depsgraph);
/* Ownership is now ours. */
- preview->id_copy = NULL;
-
- U.pixelsize = 2.0f;
+ preview->id_copy = nullptr;
View3DShading shading;
BKE_screen_view3d_shading_init(&shading);
@@ -898,13 +882,11 @@ static void object_preview_render(IconPreview *preview, IconPreviewSize *preview
IB_rect,
V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS,
R_ALPHAPREMUL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
err_out);
/* TODO: color-management? */
- U.pixelsize = pixelsize_old;
-
if (ibuf) {
icon_copy_rect(ibuf, preview_sized->sizex, preview_sized->sizey, preview_sized->rect);
IMB_freeImBuf(ibuf);
@@ -923,15 +905,15 @@ static void object_preview_render(IconPreview *preview, IconPreviewSize *preview
static struct PoseBackup *action_preview_render_prepare(IconPreview *preview)
{
Object *object = preview->active_object;
- if (object == NULL) {
+ if (object == nullptr) {
WM_report(RPT_WARNING, "No active object, unable to apply the Action before rendering");
- return NULL;
+ return nullptr;
}
- if (object->pose == NULL) {
+ if (object->pose == nullptr) {
WM_reportf(RPT_WARNING,
"Object %s has no pose, unable to apply the Action before rendering",
object->id.name + 2);
- return NULL;
+ return nullptr;
}
/* Create a backup of the current pose. */
@@ -952,7 +934,7 @@ static struct PoseBackup *action_preview_render_prepare(IconPreview *preview)
static void action_preview_render_cleanup(IconPreview *preview, struct PoseBackup *pose_backup)
{
- if (pose_backup == NULL) {
+ if (pose_backup == nullptr) {
return;
}
ED_pose_backup_restore(pose_backup);
@@ -972,7 +954,7 @@ static void action_preview_render(IconPreview *preview, IconPreviewSize *preview
/* Not all code paths that lead to this function actually provide a depsgraph.
* The "Refresh Asset Preview" button (ED_OT_lib_id_generate_preview) does,
* but WM_OT_previews_ensure does not. */
- BLI_assert(depsgraph != NULL);
+ BLI_assert(depsgraph != nullptr);
BLI_assert(preview->scene == DEG_get_input_scene(depsgraph));
/* Apply the pose before getting the evaluated scene, so that the new pose is evaluated. */
@@ -980,7 +962,7 @@ static void action_preview_render(IconPreview *preview, IconPreviewSize *preview
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
Object *camera_eval = scene_eval->camera;
- if (camera_eval == NULL) {
+ if (camera_eval == nullptr) {
printf("Scene has no camera, unable to render preview of %s without it.\n",
preview->id->name + 2);
return;
@@ -989,7 +971,7 @@ static void action_preview_render(IconPreview *preview, IconPreviewSize *preview
/* This renders with the Workbench engine settings stored on the Scene. */
ImBuf *ibuf = ED_view3d_draw_offscreen_imbuf_simple(depsgraph,
scene_eval,
- NULL,
+ nullptr,
OB_SOLID,
camera_eval,
preview_sized->sizex,
@@ -997,8 +979,8 @@ static void action_preview_render(IconPreview *preview, IconPreviewSize *preview
IB_rect,
V3D_OFSDRAW_NONE,
R_ADDSKY,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
err_out);
action_preview_render_cleanup(preview, pose_backup);
@@ -1024,7 +1006,7 @@ static void shader_preview_update(void *spv,
RenderResult *UNUSED(rr),
volatile struct rcti *UNUSED(rect))
{
- ShaderPreview *sp = spv;
+ ShaderPreview *sp = static_cast<ShaderPreview *>(spv);
*(sp->do_update) = true;
}
@@ -1032,46 +1014,13 @@ static void shader_preview_update(void *spv,
/* called by renderer, checks job value */
static int shader_preview_break(void *spv)
{
- ShaderPreview *sp = spv;
+ ShaderPreview *sp = static_cast<ShaderPreview *>(spv);
return *(sp->stop);
}
-/* outside thread, called before redraw notifiers, it moves finished preview over */
-static void shader_preview_updatejob(void *spv)
+static void shader_preview_updatejob(void *UNUSED(spv))
{
- ShaderPreview *sp = spv;
-
- if (sp->pr_method == PR_NODE_RENDER) {
- if (GS(sp->id->name) == ID_MA) {
- Material *mat = (Material *)sp->id;
-
- if (sp->matcopy && mat->nodetree && sp->matcopy->nodetree) {
- ntreeLocalSync(sp->matcopy->nodetree, mat->nodetree);
- }
- }
- else if (GS(sp->id->name) == ID_TE) {
- Tex *tex = (Tex *)sp->id;
-
- if (sp->texcopy && tex->nodetree && sp->texcopy->nodetree) {
- ntreeLocalSync(sp->texcopy->nodetree, tex->nodetree);
- }
- }
- else if (GS(sp->id->name) == ID_WO) {
- World *wrld = (World *)sp->id;
-
- if (sp->worldcopy && wrld->nodetree && sp->worldcopy->nodetree) {
- ntreeLocalSync(sp->worldcopy->nodetree, wrld->nodetree);
- }
- }
- else if (GS(sp->id->name) == ID_LA) {
- Light *la = (Light *)sp->id;
-
- if (sp->lampcopy && la->nodetree && sp->lampcopy->nodetree) {
- ntreeLocalSync(sp->lampcopy->nodetree, la->nodetree);
- }
- }
- }
}
/* Renders texture directly to render buffer. */
@@ -1083,13 +1032,14 @@ static void shader_preview_texture(ShaderPreview *sp, Tex *tex, Scene *sce, Rend
/* This is needed otherwise no RenderResult is created. */
sce->r.scemode &= ~R_BUTS_PREVIEW;
- RE_InitState(re, NULL, &sce->r, &sce->view_layers, NULL, width, height, NULL);
+ RE_InitState(re, nullptr, &sce->r, &sce->view_layers, nullptr, width, height, nullptr);
RE_SetScene(re, sce);
/* Create buffer in empty RenderView created in the init step. */
RenderResult *rr = RE_AcquireResultWrite(re);
RenderView *rv = (RenderView *)rr->views.first;
- rv->rectf = MEM_callocN(sizeof(float[4]) * width * height, "texture render result");
+ rv->rectf = static_cast<float *>(
+ MEM_callocN(sizeof(float[4]) * width * height, "texture render result"));
RE_ReleaseResult(re);
/* Get texture image pool (if any) */
@@ -1162,7 +1112,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
/* get the stuff from the builtin preview dbase */
sce = preview_prepare_scene(sp->bmain, sp->scene, id, idtype, sp);
- if (sce == NULL) {
+ if (sce == nullptr) {
return;
}
@@ -1175,7 +1125,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
re = RE_GetRender(name);
/* full refreshed render from first tile */
- if (re == NULL) {
+ if (re == nullptr) {
re = RE_NewRender(name);
}
@@ -1187,21 +1137,12 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
sce->r.scemode |= R_NO_IMAGE_LOAD;
sce->display.render_aa = SCE_DISPLAY_AA_SAMPLES_8;
}
- else if (sp->pr_method == PR_NODE_RENDER) {
- if (idtype == ID_MA) {
- sce->r.scemode |= R_MATNODE_PREVIEW;
- }
- else if (idtype == ID_TE) {
- sce->r.scemode |= R_TEXNODE_PREVIEW;
- }
- sce->display.render_aa = SCE_DISPLAY_AA_OFF;
- }
else { /* PR_BUTS_RENDER */
sce->display.render_aa = SCE_DISPLAY_AA_SAMPLES_8;
}
/* Callbacks are cleared on GetRender(). */
- if (ELEM(sp->pr_method, PR_BUTS_RENDER, PR_NODE_RENDER)) {
+ if (sp->pr_method == PR_BUTS_RENDER) {
RE_display_update_cb(re, sp, shader_preview_update);
}
/* set this for all previews, default is react to G.is_break still */
@@ -1234,7 +1175,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
}
/* unassign the pointers, reset vars */
- preview_prepare_scene(sp->bmain, sp->scene, NULL, GS(id->name), sp);
+ preview_prepare_scene(sp->bmain, sp->scene, nullptr, GS(id->name), sp);
/* XXX bad exception, end-exec is not being called in render, because it uses local main. */
#if 0
@@ -1249,7 +1190,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
/* runs inside thread for material and icons */
static void shader_preview_startjob(void *customdata, short *stop, short *do_update)
{
- ShaderPreview *sp = customdata;
+ ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
sp->stop = stop;
sp->do_update = do_update;
@@ -1280,17 +1221,17 @@ static void preview_id_copy_free(ID *id)
static void shader_preview_free(void *customdata)
{
- ShaderPreview *sp = customdata;
+ ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
Main *pr_main = sp->pr_main;
- ID *main_id_copy = NULL;
- ID *sub_id_copy = NULL;
+ ID *main_id_copy = nullptr;
+ ID *sub_id_copy = nullptr;
if (sp->matcopy) {
main_id_copy = (ID *)sp->matcopy;
BLI_remlink(&pr_main->materials, sp->matcopy);
}
if (sp->texcopy) {
- BLI_assert(main_id_copy == NULL);
+ BLI_assert(main_id_copy == nullptr);
main_id_copy = (ID *)sp->texcopy;
BLI_remlink(&pr_main->textures, sp->texcopy);
}
@@ -1305,14 +1246,10 @@ static void shader_preview_free(void *customdata)
BLI_remlink(&pr_main->worlds, sp->worldcopy);
}
if (sp->lampcopy) {
- BLI_assert(main_id_copy == NULL);
+ BLI_assert(main_id_copy == nullptr);
main_id_copy = (ID *)sp->lampcopy;
BLI_remlink(&pr_main->lights, sp->lampcopy);
}
- if (main_id_copy || sp->id_copy) {
- /* node previews */
- shader_preview_updatejob(sp);
- }
if (sp->own_id_copy) {
if (sp->id_copy) {
preview_id_copy_free(sp->id_copy);
@@ -1351,7 +1288,7 @@ static ImBuf *icon_preview_imbuf_from_brush(Brush *brush)
BLI_path_abs(path, ID_BLEND_PATH_FROM_GLOBAL(&brush->id));
/* Use default color-spaces for brushes. */
- brush->icon_imbuf = IMB_loadiffname(path, flags, NULL);
+ brush->icon_imbuf = IMB_loadiffname(path, flags, nullptr);
/* otherwise lets try to find it in other directories */
if (!(brush->icon_imbuf)) {
@@ -1362,7 +1299,7 @@ static ImBuf *icon_preview_imbuf_from_brush(Brush *brush)
if (path[0]) {
/* Use default color spaces. */
- brush->icon_imbuf = IMB_loadiffname(path, flags, NULL);
+ brush->icon_imbuf = IMB_loadiffname(path, flags, nullptr);
}
}
@@ -1388,7 +1325,7 @@ static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect)
short ex, ey, dx, dy;
/* paranoia test */
- if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) {
+ if (ibuf == nullptr || (ibuf->rect == nullptr && ibuf->rect_float == nullptr)) {
return;
}
@@ -1418,7 +1355,7 @@ static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect)
IMB_scalefastImBuf(ima, ex, ey);
/* if needed, convert to 32 bits */
- if (ima->rect == NULL) {
+ if (ima->rect == nullptr) {
IMB_rect_from_float(ima);
}
@@ -1446,13 +1383,13 @@ static void set_alpha(char *cp, int sizex, int sizey, char alpha)
static void icon_preview_startjob(void *customdata, short *stop, short *do_update)
{
- ShaderPreview *sp = customdata;
+ ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
if (sp->pr_method == PR_ICON_DEFERRED) {
- PreviewImage *prv = sp->owner;
+ PreviewImage *prv = static_cast<PreviewImage *>(sp->owner);
ImBuf *thumb;
- char *deferred_data = PRV_DEFERRED_DATA(prv);
- int source = deferred_data[0];
+ char *deferred_data = static_cast<char *>(PRV_DEFERRED_DATA(prv));
+ ThumbSource source = static_cast<ThumbSource>(deferred_data[0]);
char *path = &deferred_data[1];
// printf("generating deferred %d×%d preview for %s\n", sp->sizex, sp->sizey, path);
@@ -1471,15 +1408,15 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat
ID *id = sp->id;
short idtype = GS(id->name);
- BLI_assert(id != NULL);
+ BLI_assert(id != nullptr);
if (idtype == ID_IM) {
Image *ima = (Image *)id;
- ImBuf *ibuf = NULL;
+ ImBuf *ibuf = nullptr;
ImageUser iuser;
BKE_imageuser_default(&iuser);
- if (ima == NULL) {
+ if (ima == nullptr) {
return;
}
@@ -1487,12 +1424,12 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat
iuser.framenr = 1;
iuser.scene = sp->scene;
- /* elubie: this needs to be changed: here image is always loaded if not
+ /* NOTE(@elubie): this needs to be changed: here image is always loaded if not
* already there. Very expensive for large images. Need to find a way to
- * only get existing ibuf */
- ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
- if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ * only get existing `ibuf`. */
+ ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
+ if (ibuf == nullptr || (ibuf->rect == nullptr && ibuf->rect_float == nullptr)) {
+ BKE_image_release_ibuf(ima, ibuf, nullptr);
return;
}
@@ -1500,7 +1437,7 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat
*do_update = true;
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ BKE_image_release_ibuf(ima, ibuf, nullptr);
}
else if (idtype == ID_BR) {
Brush *br = (Brush *)id;
@@ -1544,7 +1481,7 @@ static void common_preview_startjob(void *customdata,
short *do_update,
float *UNUSED(progress))
{
- ShaderPreview *sp = customdata;
+ ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
if (ELEM(sp->pr_method, PR_ICON_RENDER, PR_ICON_DEFERRED)) {
icon_preview_startjob(customdata, stop, do_update);
@@ -1560,17 +1497,17 @@ static void common_preview_startjob(void *customdata,
*/
static void other_id_types_preview_render(IconPreview *ip,
IconPreviewSize *cur_size,
- const int pr_method,
+ const ePreviewRenderMethod pr_method,
short *stop,
short *do_update,
float *progress)
{
- ShaderPreview *sp = MEM_callocN(sizeof(ShaderPreview), "Icon ShaderPreview");
+ ShaderPreview *sp = MEM_cnew<ShaderPreview>("Icon ShaderPreview");
/* These types don't use the ShaderPreview mess, they have their own types and functions. */
BLI_assert(!ip->id || !ELEM(GS(ip->id->name), ID_OB));
- /* construct shader preview from image size and previewcustomdata */
+ /* Construct shader preview from image size and preview custom-data. */
sp->scene = ip->scene;
sp->owner = ip->owner;
sp->sizex = cur_size->sizex;
@@ -1581,7 +1518,7 @@ static void other_id_types_preview_render(IconPreview *ip,
sp->id_copy = ip->id_copy;
sp->bmain = ip->bmain;
sp->own_id_copy = false;
- Material *ma = NULL;
+ Material *ma = nullptr;
if (sp->pr_method == PR_ICON_RENDER) {
BLI_assert(ip->id);
@@ -1591,7 +1528,7 @@ static void other_id_types_preview_render(IconPreview *ip,
ma = (Material *)ip->id;
}
- if ((ma == NULL) || (ma->gp_style == NULL)) {
+ if ((ma == nullptr) || (ma->gp_style == nullptr)) {
sp->pr_main = G_pr_main;
}
else {
@@ -1629,10 +1566,12 @@ static void icon_preview_startjob_all_sizes(void *customdata,
IconPreview *ip = (IconPreview *)customdata;
IconPreviewSize *cur_size;
- for (cur_size = ip->sizes.first; cur_size; cur_size = cur_size->next) {
- PreviewImage *prv = ip->owner;
+ for (cur_size = static_cast<IconPreviewSize *>(ip->sizes.first); cur_size;
+ cur_size = cur_size->next) {
+ PreviewImage *prv = static_cast<PreviewImage *>(ip->owner);
/* Is this a render job or a deferred loading job? */
- const int pr_method = (prv->tag & PRV_TAG_DEFFERED) ? PR_ICON_DEFERRED : PR_ICON_RENDER;
+ const ePreviewRenderMethod pr_method = (prv->tag & PRV_TAG_DEFFERED) ? PR_ICON_DEFERRED :
+ PR_ICON_RENDER;
if (*stop) {
break;
@@ -1649,7 +1588,7 @@ static void icon_preview_startjob_all_sizes(void *customdata,
* they can skip this test. */
/* TODO: Decouple the ID-type-specific render functions from this function, so that it's not
* necessary to know here what happens inside lower-level functions. */
- const bool use_solid_render_mode = (ip->id != NULL) && ELEM(GS(ip->id->name), ID_OB, ID_AC);
+ const bool use_solid_render_mode = (ip->id != nullptr) && ELEM(GS(ip->id->name), ID_OB, ID_AC);
if (!use_solid_render_mode && preview_method_is_render(pr_method) &&
!check_engine_supports_preview(ip->scene)) {
continue;
@@ -1662,7 +1601,7 @@ static void icon_preview_startjob_all_sizes(void *customdata,
}
#endif
- if (ip->id != NULL) {
+ if (ip->id != nullptr) {
switch (GS(ip->id->name)) {
case ID_OB:
if (object_preview_is_type_supported((Object *)ip->id)) {
@@ -1675,7 +1614,7 @@ static void icon_preview_startjob_all_sizes(void *customdata,
action_preview_render(ip, cur_size);
continue;
default:
- /* Fall through to the same code as the `ip->id == NULL` case. */
+ /* Fall through to the same code as the `ip->id == nullptr` case. */
break;
}
}
@@ -1685,7 +1624,7 @@ static void icon_preview_startjob_all_sizes(void *customdata,
static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int sizey)
{
- IconPreviewSize *cur_size = ip->sizes.first, *new_size;
+ IconPreviewSize *cur_size = static_cast<IconPreviewSize *>(ip->sizes.first);
while (cur_size) {
if (cur_size->sizex == sizex && cur_size->sizey == sizey) {
@@ -1696,7 +1635,7 @@ static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int si
cur_size = cur_size->next;
}
- new_size = MEM_callocN(sizeof(IconPreviewSize), "IconPreviewSize");
+ IconPreviewSize *new_size = MEM_cnew<IconPreviewSize>("IconPreviewSize");
new_size->sizex = sizex;
new_size->sizey = sizey;
new_size->rect = rect;
@@ -1706,7 +1645,7 @@ static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int si
static void icon_preview_endjob(void *customdata)
{
- IconPreview *ip = customdata;
+ IconPreview *ip = static_cast<IconPreview *>(customdata);
if (ip->id) {
@@ -1723,7 +1662,7 @@ static void icon_preview_endjob(void *customdata)
for (i = 0; i < NUM_ICON_SIZES; i++) {
if (prv_img->gputexture[i]) {
GPU_texture_free(prv_img->gputexture[i]);
- prv_img->gputexture[i] = NULL;
+ prv_img->gputexture[i] = nullptr;
WM_main_add_notifier(NC_MATERIAL | ND_SHADING_DRAW, ip->id);
}
}
@@ -1732,7 +1671,7 @@ static void icon_preview_endjob(void *customdata)
}
if (ip->owner) {
- PreviewImage *prv_img = ip->owner;
+ PreviewImage *prv_img = static_cast<PreviewImage *>(ip->owner);
prv_img->tag &= ~PRV_TAG_DEFFERED_RENDERING;
LISTBASE_FOREACH (IconPreviewSize *, icon_size, &ip->sizes) {
@@ -1761,20 +1700,23 @@ static void icon_preview_free(void *customdata)
bool ED_preview_id_is_supported(const ID *id)
{
- if (id == NULL) {
+ if (id == nullptr) {
+ return false;
+ }
+ if (GS(id->name) == ID_NT) {
+ /* Node groups don't support standard preview generation. */
return false;
}
-
if (GS(id->name) == ID_OB) {
return object_preview_is_type_supported((const Object *)id);
}
- return BKE_previewimg_id_get_p(id) != NULL;
+ return BKE_previewimg_id_get_p(id) != nullptr;
}
void ED_preview_icon_render(
const bContext *C, Scene *scene, ID *id, uint *rect, int sizex, int sizey)
{
- IconPreview ip = {NULL};
+ IconPreview ip = {nullptr};
short stop = false, update = false;
float progress = 0.0f;
@@ -1797,7 +1739,7 @@ void ED_preview_icon_render(
icon_preview_endjob(&ip);
BLI_freelistN(&ip.sizes);
- if (ip.id_copy != NULL) {
+ if (ip.id_copy != nullptr) {
preview_id_copy_free(ip.id_copy);
}
}
@@ -1818,10 +1760,10 @@ void ED_preview_icon_job(
WM_JOB_EXCL_RENDER,
WM_JOB_TYPE_RENDER_PREVIEW);
- ip = MEM_callocN(sizeof(IconPreview), "icon preview");
+ ip = MEM_cnew<IconPreview>("icon preview");
/* render all resolutions from suspended job too */
- old_ip = WM_jobs_customdata_get(wm_job);
+ old_ip = static_cast<IconPreview *>(WM_jobs_customdata_get(wm_job));
if (old_ip) {
BLI_movelisttolist(&ip->sizes, &old_ip->sizes);
}
@@ -1840,7 +1782,7 @@ void ED_preview_icon_job(
/* Special threading hack:
* warn main code that this preview is being rendered and cannot be freed... */
{
- PreviewImage *prv_img = owner;
+ PreviewImage *prv_img = static_cast<PreviewImage *>(owner);
if (prv_img->tag & PRV_TAG_DEFFERED) {
prv_img->tag |= PRV_TAG_DEFFERED_RENDERING;
}
@@ -1853,7 +1795,8 @@ void ED_preview_icon_job(
* Particularly important for heavy scenes and Eevee using OpenGL that blocks
* the user interface drawing. */
WM_jobs_delay_start(wm_job, (delay) ? 2.0 : 0.0);
- WM_jobs_callbacks(wm_job, icon_preview_startjob_all_sizes, NULL, NULL, icon_preview_endjob);
+ WM_jobs_callbacks(
+ wm_job, icon_preview_startjob_all_sizes, nullptr, nullptr, icon_preview_endjob);
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
@@ -1865,13 +1808,13 @@ void ED_preview_shader_job(const bContext *C,
MTex *slot,
int sizex,
int sizey,
- int method)
+ ePreviewRenderMethod method)
{
Object *ob = CTX_data_active_object(C);
wmJob *wm_job;
ShaderPreview *sp;
Scene *scene = CTX_data_scene(C);
- short id_type = GS(id->name);
+ const ID_Type id_type = GS(id->name);
BLI_assert(BKE_previewimg_id_supports_jobs(id));
@@ -1882,11 +1825,6 @@ void ED_preview_shader_job(const bContext *C,
return;
}
- /* Only texture node preview is supported with Cycles. */
- if (method == PR_NODE_RENDER && id_type != ID_TE) {
- return;
- }
-
ED_preview_ensure_dbase();
wm_job = WM_jobs_get(CTX_wm_manager(C),
@@ -1895,7 +1833,7 @@ void ED_preview_shader_job(const bContext *C,
"Shader Preview",
WM_JOB_EXCL_RENDER,
WM_JOB_TYPE_RENDER_PREVIEW);
- sp = MEM_callocN(sizeof(ShaderPreview), "shader preview");
+ sp = MEM_cnew<ShaderPreview>("shader preview");
/* customdata for preview thread */
sp->scene = scene;
@@ -1909,17 +1847,17 @@ void ED_preview_shader_job(const bContext *C,
sp->parent = parent;
sp->slot = slot;
sp->bmain = CTX_data_main(C);
- Material *ma = NULL;
+ Material *ma = nullptr;
/* hardcoded preview .blend for Eevee + Cycles, this should be solved
* once with custom preview .blend path for external engines */
/* grease pencil use its own preview file */
- if (GS(id->name) == ID_MA) {
+ if (id_type == ID_MA) {
ma = (Material *)id;
}
- if ((ma == NULL) || (ma->gp_style == NULL)) {
+ if ((ma == nullptr) || (ma->gp_style == nullptr)) {
sp->pr_main = G_pr_main;
}
else {
@@ -1936,7 +1874,7 @@ void ED_preview_shader_job(const bContext *C,
/* setup job */
WM_jobs_customdata_set(wm_job, sp, shader_preview_free);
WM_jobs_timer(wm_job, 0.1, NC_MATERIAL, NC_MATERIAL);
- WM_jobs_callbacks(wm_job, common_preview_startjob, NULL, shader_preview_updatejob, NULL);
+ WM_jobs_callbacks(wm_job, common_preview_startjob, nullptr, shader_preview_updatejob, nullptr);
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
@@ -1946,28 +1884,28 @@ void ED_preview_kill_jobs(wmWindowManager *wm, Main *UNUSED(bmain))
if (wm) {
/* This is called to stop all preview jobs before scene data changes, to
* avoid invalid memory access. */
- WM_jobs_kill(wm, NULL, common_preview_startjob);
- WM_jobs_kill(wm, NULL, icon_preview_startjob_all_sizes);
+ WM_jobs_kill(wm, nullptr, common_preview_startjob);
+ WM_jobs_kill(wm, nullptr, icon_preview_startjob_all_sizes);
}
}
-typedef struct PreviewRestartQueueEntry {
+struct PreviewRestartQueueEntry {
struct PreviewRestartQueueEntry *next, *prev;
enum eIconSizes size;
ID *id;
-} PreviewRestartQueueEntry;
+};
static ListBase /* #PreviewRestartQueueEntry */ G_restart_previews_queue;
-void ED_preview_restart_queue_free(void)
+void ED_preview_restart_queue_free()
{
BLI_freelistN(&G_restart_previews_queue);
}
void ED_preview_restart_queue_add(ID *id, enum eIconSizes size)
{
- PreviewRestartQueueEntry *queue_entry = MEM_mallocN(sizeof(*queue_entry), __func__);
+ PreviewRestartQueueEntry *queue_entry = MEM_new<PreviewRestartQueueEntry>(__func__);
queue_entry->size = size;
queue_entry->id = id;
BLI_addtail(&G_restart_previews_queue, queue_entry);
@@ -1986,7 +1924,7 @@ void ED_preview_restart_queue_work(const bContext *C)
}
BKE_previewimg_clear_single(preview, queue_entry->size);
- UI_icon_render_id(C, NULL, queue_entry->id, queue_entry->size, true);
+ UI_icon_render_id(C, nullptr, queue_entry->id, queue_entry->size, true);
BLI_freelinkN(&G_restart_previews_queue, queue_entry);
}
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.cc
index 54ff25ede28..19ab6841e22 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.cc
@@ -20,8 +20,8 @@
* \ingroup edrend
*/
-#include <stdlib.h>
-#include <string.h>
+#include <cstdlib>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -64,6 +64,8 @@
#include "BKE_workspace.h"
#include "BKE_world.h"
+#include "NOD_composite.h"
+
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -96,7 +98,7 @@
#include "engines/eevee/eevee_lightcache.h"
-#include "render_intern.h" /* own include */
+#include "render_intern.hh" /* own include */
static bool object_materials_supported_poll_ex(bContext *C, const Object *ob);
@@ -106,7 +108,7 @@ static bool object_materials_supported_poll_ex(bContext *C, const Object *ob);
static bool object_array_for_shading_edit_mode_enabled_filter(const Object *ob, void *user_data)
{
- bContext *C = user_data;
+ bContext *C = static_cast<bContext *>(user_data);
if (object_materials_supported_poll_ex(C, ob)) {
if (BKE_object_is_in_editmode(ob) == true) {
return true;
@@ -123,7 +125,7 @@ static Object **object_array_for_shading_edit_mode_enabled(bContext *C, uint *r_
static bool object_array_for_shading_edit_mode_disabled_filter(const Object *ob, void *user_data)
{
- bContext *C = user_data;
+ bContext *C = static_cast<bContext *>(user_data);
if (object_materials_supported_poll_ex(C, ob)) {
if (BKE_object_is_in_editmode(ob) == false) {
return true;
@@ -159,7 +161,7 @@ static bool object_materials_supported_poll_ex(bContext *C, const Object *ob)
}
/* Material linked to obdata. */
- const ID *data = ob->data;
+ const ID *data = static_cast<ID *>(ob->data);
return (data && !ID_IS_LINKED(data) && !ID_IS_OVERRIDE_LIBRARY(data));
}
@@ -188,8 +190,8 @@ static int material_slot_add_exec(bContext *C, wmOperator *UNUSED(op))
if (ob->mode & OB_MODE_TEXTURE_PAINT) {
Scene *scene = CTX_data_scene(C);
- ED_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
- WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ ED_paint_proj_mesh_data_check(scene, ob, nullptr, nullptr, nullptr, nullptr);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, nullptr);
}
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
@@ -238,8 +240,8 @@ static int material_slot_remove_exec(bContext *C, wmOperator *op)
if (ob->mode & OB_MODE_TEXTURE_PAINT) {
Scene *scene = CTX_data_scene(C);
- ED_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
- WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ ED_paint_proj_mesh_data_check(scene, ob, nullptr, nullptr, nullptr, nullptr);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, nullptr);
}
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
@@ -277,7 +279,7 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op))
bool changed_multi = false;
Object *obact = CTX_data_active_object(C);
- const Material *mat_active = obact ? BKE_object_material_get(obact, obact->actcol) : NULL;
+ const Material *mat_active = obact ? BKE_object_material_get(obact, obact->actcol) : nullptr;
uint objects_len = 0;
Object **objects = object_array_for_shading_edit_mode_enabled(C, &objects_len);
@@ -328,7 +330,7 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op))
ListBase *nurbs = BKE_curve_editNurbs_get((Curve *)ob->data);
if (nurbs) {
- for (nu = nurbs->first; nu; nu = nu->next) {
+ for (nu = static_cast<Nurb *>(nurbs->first); nu; nu = nu->next) {
if (ED_curve_nurb_select_check(v3d, nu)) {
changed = true;
nu->mat_nr = mat_nr_active;
@@ -384,7 +386,7 @@ static int material_slot_de_select(bContext *C, bool select)
{
bool changed_multi = false;
Object *obact = CTX_data_active_object(C);
- const Material *mat_active = obact ? BKE_object_material_get(obact, obact->actcol) : NULL;
+ const Material *mat_active = obact ? BKE_object_material_get(obact, obact->actcol) : nullptr;
uint objects_len = 0;
Object **objects = object_array_for_shading_edit_mode_enabled(C, &objects_len);
@@ -432,7 +434,7 @@ static int material_slot_de_select(bContext *C, bool select)
int a;
if (nurbs) {
- for (nu = nurbs->first; nu; nu = nu->next) {
+ for (nu = static_cast<Nurb *>(nurbs->first); nu; nu = nu->next) {
if (nu->mat_nr == mat_nr_active) {
if (nu->bezt) {
a = nu->pntsu;
@@ -477,7 +479,7 @@ static int material_slot_de_select(bContext *C, bool select)
if (changed) {
changed_multi = true;
- DEG_id_tag_update(ob->data, ID_RECALC_SELECT);
+ DEG_id_tag_update(static_cast<ID *>(ob->data), ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
}
}
@@ -545,7 +547,8 @@ static int material_slot_copy_exec(bContext *C, wmOperator *UNUSED(op))
Material ***matar_object = &ob->mat;
- Material **matar = MEM_callocN(sizeof(*matar) * (size_t)ob->totcol, __func__);
+ Material **matar = static_cast<Material **>(
+ MEM_callocN(sizeof(*matar) * (size_t)ob->totcol, __func__));
for (int i = ob->totcol; i--;) {
matar[i] = ob->matbits[i] ? (*matar_object)[i] : (*matar_obdata)[i];
}
@@ -620,7 +623,7 @@ static int material_slot_move_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- slot_remap = MEM_mallocN(sizeof(uint) * ob->totcol, __func__);
+ slot_remap = static_cast<uint *>(MEM_mallocN(sizeof(uint) * ob->totcol, __func__));
range_vn_u(slot_remap, ob->totcol, 0);
@@ -643,7 +646,7 @@ void OBJECT_OT_material_slot_move(wmOperatorType *ot)
static const EnumPropertyItem material_slot_move[] = {
{1, "UP", 0, "Up", ""},
{-1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -715,8 +718,8 @@ static int material_slot_remove_unused_exec(bContext *C, wmOperator *op)
if (ob_active->mode & OB_MODE_TEXTURE_PAINT) {
Scene *scene = CTX_data_scene(C);
- ED_paint_proj_mesh_data_check(scene, ob_active, NULL, NULL, NULL, NULL);
- WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ ED_paint_proj_mesh_data_check(scene, ob_active, nullptr, nullptr, nullptr, nullptr);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, nullptr);
}
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob_active);
@@ -749,7 +752,8 @@ void OBJECT_OT_material_slot_remove_unused(wmOperatorType *ot)
static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
{
- Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
+ Material *ma = static_cast<Material *>(
+ CTX_data_pointer_get_type(C, "material", &RNA_Material).data);
Main *bmain = CTX_data_main(C);
PointerRNA ptr, idptr;
PropertyRNA *prop;
@@ -757,17 +761,18 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
/* hook into UI */
UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
- Object *ob = (prop && RNA_struct_is_a(ptr.type, &RNA_Object)) ? ptr.data : NULL;
+ Object *ob = static_cast<Object *>((prop && RNA_struct_is_a(ptr.type, &RNA_Object)) ? ptr.data :
+ nullptr);
/* add or copy material */
if (ma) {
Material *new_ma = (Material *)BKE_id_copy_ex(
- bmain, &ma->id, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS);
+ bmain, &ma->id, nullptr, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS);
ma = new_ma;
}
else {
const char *name = DATA_("Material");
- if (!(ob != NULL && ob->type == OB_GPENCIL)) {
+ if (!(ob != nullptr && ob->type == OB_GPENCIL)) {
ma = BKE_material_add(bmain, name);
}
else {
@@ -778,10 +783,10 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
}
if (prop) {
- if (ob != NULL) {
+ if (ob != nullptr) {
/* Add slot follows user-preferences for creating new slots,
* RNA pointer assignment doesn't, see: T60014. */
- if (BKE_object_material_get_p(ob, ob->actcol) == NULL) {
+ if (BKE_object_material_get_p(ob, ob->actcol) == nullptr) {
BKE_object_material_slot_add(bmain, ob);
}
}
@@ -791,7 +796,7 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
id_us_min(&ma->id);
RNA_id_pointer_create(&ma->id, &idptr);
- RNA_property_pointer_set(&ptr, prop, idptr, NULL);
+ RNA_property_pointer_set(&ptr, prop, idptr, nullptr);
RNA_property_update(C, &ptr, prop);
}
@@ -823,7 +828,7 @@ void MATERIAL_OT_new(wmOperatorType *ot)
static int new_texture_exec(bContext *C, wmOperator *UNUSED(op))
{
- Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
+ Tex *tex = static_cast<Tex *>(CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data);
Main *bmain = CTX_data_main(C);
PointerRNA ptr, idptr;
PropertyRNA *prop;
@@ -845,7 +850,7 @@ static int new_texture_exec(bContext *C, wmOperator *UNUSED(op))
id_us_min(&tex->id);
RNA_id_pointer_create(&tex->id, &idptr);
- RNA_property_pointer_set(&ptr, prop, idptr, NULL);
+ RNA_property_pointer_set(&ptr, prop, idptr, nullptr);
RNA_property_update(C, &ptr, prop);
}
@@ -876,7 +881,7 @@ void TEXTURE_OT_new(wmOperatorType *ot)
static int new_world_exec(bContext *C, wmOperator *UNUSED(op))
{
- World *wo = CTX_data_pointer_get_type(C, "world", &RNA_World).data;
+ World *wo = static_cast<World *>(CTX_data_pointer_get_type(C, "world", &RNA_World).data);
Main *bmain = CTX_data_main(C);
PointerRNA ptr, idptr;
PropertyRNA *prop;
@@ -884,7 +889,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op))
/* add or copy world */
if (wo) {
World *new_wo = (World *)BKE_id_copy_ex(
- bmain, &wo->id, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS);
+ bmain, &wo->id, nullptr, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS);
wo = new_wo;
}
else {
@@ -902,7 +907,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op))
id_us_min(&wo->id);
RNA_id_pointer_create(&wo->id, &idptr);
- RNA_property_pointer_set(&ptr, prop, idptr, NULL);
+ RNA_property_pointer_set(&ptr, prop, idptr, nullptr);
RNA_property_update(C, &ptr, prop);
}
@@ -960,7 +965,7 @@ void SCENE_OT_view_layer_add(wmOperatorType *ot)
0,
"Blank",
"Add a new view layer with all collections disabled"},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -997,7 +1002,7 @@ static int view_layer_remove_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- if (!ED_scene_view_layer_delete(bmain, scene, view_layer, NULL)) {
+ if (!ED_scene_view_layer_delete(bmain, scene, view_layer, nullptr)) {
return OPERATOR_CANCELLED;
}
@@ -1041,7 +1046,7 @@ static int view_layer_add_aov_exec(bContext *C, wmOperator *UNUSED(op))
BKE_view_layer_verify_aov(engine, scene, view_layer);
}
RE_engine_free(engine);
- engine = NULL;
+ engine = nullptr;
}
if (scene->nodetree) {
@@ -1080,7 +1085,7 @@ static int view_layer_remove_aov_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- if (view_layer->active_aov == NULL) {
+ if (view_layer->active_aov == nullptr) {
return OPERATOR_FINISHED;
}
@@ -1093,7 +1098,7 @@ static int view_layer_remove_aov_exec(bContext *C, wmOperator *UNUSED(op))
BKE_view_layer_verify_aov(engine, scene, view_layer);
}
RE_engine_free(engine);
- engine = NULL;
+ engine = nullptr;
}
if (scene->nodetree) {
@@ -1135,7 +1140,7 @@ enum {
static void light_cache_bake_tag_cache(Scene *scene, wmOperator *op)
{
- if (scene->eevee.light_cache_data != NULL) {
+ if (scene->eevee.light_cache_data != nullptr) {
int subset = RNA_enum_get(op->ptr, "subset");
switch (subset) {
case LIGHTCACHE_SUBSET_ALL:
@@ -1261,7 +1266,7 @@ void SCENE_OT_light_cache_bake(wmOperatorType *ot)
0,
"Cubemaps Only",
"Try to only bake reflection cubemaps if irradiance grids are up to date"},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -1317,7 +1322,7 @@ static int light_cache_free_exec(bContext *C, wmOperator *UNUSED(op))
}
EEVEE_lightcache_free(scene->eevee.light_cache_data);
- scene->eevee.light_cache_data = NULL;
+ scene->eevee.light_cache_data = nullptr;
EEVEE_lightcache_info_update(&scene->eevee);
@@ -1358,7 +1363,7 @@ static int render_view_add_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- BKE_scene_add_render_view(scene, NULL);
+ BKE_scene_add_render_view(scene, nullptr);
scene->r.actview = BLI_listbase_count(&scene->r.views) - 1;
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
@@ -1389,7 +1394,8 @@ void SCENE_OT_render_view_add(wmOperatorType *ot)
static int render_view_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- SceneRenderView *rv = BLI_findlink(&scene->r.views, scene->r.actview);
+ SceneRenderView *rv = static_cast<SceneRenderView *>(
+ BLI_findlink(&scene->r.views, scene->r.actview));
if (!BKE_scene_remove_render_view(scene, rv)) {
return OPERATOR_CANCELLED;
@@ -1444,9 +1450,9 @@ static bool freestyle_linestyle_check_report(FreestyleLineSet *lineset, ReportLi
static bool freestyle_active_module_poll(bContext *C)
{
PointerRNA ptr = CTX_data_pointer_get_type(C, "freestyle_module", &RNA_FreestyleModuleSettings);
- FreestyleModuleConfig *module = ptr.data;
+ FreestyleModuleConfig *module = static_cast<FreestyleModuleConfig *>(ptr.data);
- return module != NULL;
+ return module != nullptr;
}
static int freestyle_module_add_exec(bContext *C, wmOperator *UNUSED(op))
@@ -1486,7 +1492,7 @@ static int freestyle_module_remove_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
PointerRNA ptr = CTX_data_pointer_get_type(C, "freestyle_module", &RNA_FreestyleModuleSettings);
- FreestyleModuleConfig *module = ptr.data;
+ FreestyleModuleConfig *module = static_cast<FreestyleModuleConfig *>(ptr.data);
BKE_freestyle_module_delete(&view_layer->freestyle_config, module);
@@ -1516,7 +1522,7 @@ static int freestyle_module_move_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
PointerRNA ptr = CTX_data_pointer_get_type(C, "freestyle_module", &RNA_FreestyleModuleSettings);
- FreestyleModuleConfig *module = ptr.data;
+ FreestyleModuleConfig *module = static_cast<FreestyleModuleConfig *>(ptr.data);
int dir = RNA_enum_get(op->ptr, "direction");
if (BKE_freestyle_module_move(&view_layer->freestyle_config, module, dir)) {
@@ -1538,7 +1544,7 @@ void SCENE_OT_freestyle_module_move(wmOperatorType *ot)
static const EnumPropertyItem direction_items[] = {
{-1, "UP", 0, "Up", ""},
{1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -1574,7 +1580,7 @@ static int freestyle_lineset_add_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- BKE_freestyle_lineset_add(bmain, &view_layer->freestyle_config, NULL);
+ BKE_freestyle_lineset_add(bmain, &view_layer->freestyle_config, nullptr);
DEG_id_tag_update(&scene->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
@@ -1610,7 +1616,7 @@ static bool freestyle_active_lineset_poll(bContext *C)
return false;
}
- return BKE_freestyle_lineset_get_active(&view_layer->freestyle_config) != NULL;
+ return BKE_freestyle_lineset_get_active(&view_layer->freestyle_config) != nullptr;
}
static int freestyle_lineset_copy_exec(bContext *C, wmOperator *UNUSED(op))
@@ -1730,7 +1736,7 @@ void SCENE_OT_freestyle_lineset_move(wmOperatorType *ot)
static const EnumPropertyItem direction_items[] = {
{-1, "UP", 0, "Up", ""},
{1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -1814,7 +1820,7 @@ static int freestyle_color_modifier_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (BKE_linestyle_color_modifier_add(lineset->linestyle, NULL, type) == NULL) {
+ if (BKE_linestyle_color_modifier_add(lineset->linestyle, nullptr, type) == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Unknown line color modifier type");
return OPERATOR_CANCELLED;
}
@@ -1861,7 +1867,7 @@ static int freestyle_alpha_modifier_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (BKE_linestyle_alpha_modifier_add(lineset->linestyle, NULL, type) == NULL) {
+ if (BKE_linestyle_alpha_modifier_add(lineset->linestyle, nullptr, type) == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Unknown alpha transparency modifier type");
return OPERATOR_CANCELLED;
}
@@ -1908,7 +1914,7 @@ static int freestyle_thickness_modifier_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (BKE_linestyle_thickness_modifier_add(lineset->linestyle, NULL, type) == NULL) {
+ if (BKE_linestyle_thickness_modifier_add(lineset->linestyle, nullptr, type) == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Unknown line thickness modifier type");
return OPERATOR_CANCELLED;
}
@@ -1955,7 +1961,7 @@ static int freestyle_geometry_modifier_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (BKE_linestyle_geometry_modifier_add(lineset->linestyle, NULL, type) == NULL) {
+ if (BKE_linestyle_geometry_modifier_add(lineset->linestyle, nullptr, type) == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Unknown stroke geometry modifier type");
return OPERATOR_CANCELLED;
}
@@ -2014,7 +2020,7 @@ static int freestyle_modifier_remove_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier);
- LineStyleModifier *modifier = ptr.data;
+ LineStyleModifier *modifier = static_cast<LineStyleModifier *>(ptr.data);
if (!freestyle_linestyle_check_report(lineset, op->reports)) {
return OPERATOR_CANCELLED;
@@ -2070,7 +2076,7 @@ static int freestyle_modifier_copy_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier);
- LineStyleModifier *modifier = ptr.data;
+ LineStyleModifier *modifier = static_cast<LineStyleModifier *>(ptr.data);
if (!freestyle_linestyle_check_report(lineset, op->reports)) {
return OPERATOR_CANCELLED;
@@ -2126,7 +2132,7 @@ static int freestyle_modifier_move_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier);
- LineStyleModifier *modifier = ptr.data;
+ LineStyleModifier *modifier = static_cast<LineStyleModifier *>(ptr.data);
int dir = RNA_enum_get(op->ptr, "direction");
bool changed = false;
@@ -2166,7 +2172,7 @@ void SCENE_OT_freestyle_modifier_move(wmOperatorType *ot)
static const EnumPropertyItem direction_items[] = {
{-1, "UP", 0, "Up", ""},
{1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -2252,9 +2258,12 @@ static int texture_slot_move_exec(bContext *C, wmOperator *op)
mtex_ar[act] = mtex_ar[act - 1];
mtex_ar[act - 1] = mtexswap;
- BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act - 1, -1, 0);
- BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act, act - 1, 0);
- BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, -1, act, 0);
+ BKE_animdata_fix_paths_rename(
+ id, adt, nullptr, "texture_slots", nullptr, nullptr, act - 1, -1, false);
+ BKE_animdata_fix_paths_rename(
+ id, adt, nullptr, "texture_slots", nullptr, nullptr, act, act - 1, false);
+ BKE_animdata_fix_paths_rename(
+ id, adt, nullptr, "texture_slots", nullptr, nullptr, -1, act, false);
set_active_mtex(id, act - 1);
}
@@ -2265,9 +2274,12 @@ static int texture_slot_move_exec(bContext *C, wmOperator *op)
mtex_ar[act] = mtex_ar[act + 1];
mtex_ar[act + 1] = mtexswap;
- BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act + 1, -1, 0);
- BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act, act + 1, 0);
- BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, -1, act, 0);
+ BKE_animdata_fix_paths_rename(
+ id, adt, nullptr, "texture_slots", nullptr, nullptr, act + 1, -1, false);
+ BKE_animdata_fix_paths_rename(
+ id, adt, nullptr, "texture_slots", nullptr, nullptr, act, act + 1, false);
+ BKE_animdata_fix_paths_rename(
+ id, adt, nullptr, "texture_slots", nullptr, nullptr, -1, act, false);
set_active_mtex(id, act + 1);
}
@@ -2285,7 +2297,7 @@ void TEXTURE_OT_slot_move(wmOperatorType *ot)
static const EnumPropertyItem slot_move[] = {
{-1, "UP", 0, "Up", ""},
{1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -2311,9 +2323,10 @@ void TEXTURE_OT_slot_move(wmOperatorType *ot)
/* material copy/paste */
static int copy_material_exec(bContext *C, wmOperator *UNUSED(op))
{
- Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
+ Material *ma = static_cast<Material *>(
+ CTX_data_pointer_get_type(C, "material", &RNA_Material).data);
- if (ma == NULL) {
+ if (ma == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -2345,9 +2358,10 @@ void MATERIAL_OT_copy(wmOperatorType *ot)
static int paste_material_exec(bContext *C, wmOperator *UNUSED(op))
{
- Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
+ Material *ma = static_cast<Material *>(
+ CTX_data_pointer_get_type(C, "material", &RNA_Material).data);
- if (ma == NULL) {
+ if (ma == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -2382,14 +2396,14 @@ void MATERIAL_OT_paste(wmOperatorType *ot)
static short mtexcopied = 0; /* must be reset on file load */
static MTex mtexcopybuf;
-void ED_render_clear_mtex_copybuf(void)
+void ED_render_clear_mtex_copybuf()
{ /* use for file reload */
mtexcopied = 0;
}
static void copy_mtex_copybuf(ID *id)
{
- MTex **mtex = NULL;
+ MTex **mtex = nullptr;
switch (GS(id->name)) {
case ID_PA:
@@ -2413,9 +2427,9 @@ static void copy_mtex_copybuf(ID *id)
static void paste_mtex_copybuf(ID *id)
{
- MTex **mtex = NULL;
+ MTex **mtex = nullptr;
- if (mtexcopied == 0 || mtexcopybuf.tex == NULL) {
+ if (mtexcopied == 0 || mtexcopybuf.tex == nullptr) {
return;
}
@@ -2432,8 +2446,8 @@ static void paste_mtex_copybuf(ID *id)
}
if (mtex) {
- if (*mtex == NULL) {
- *mtex = MEM_mallocN(sizeof(MTex), "mtex copy");
+ if (*mtex == nullptr) {
+ *mtex = MEM_new<MTex>("mtex copy");
}
else if ((*mtex)->tex) {
id_us_min(&(*mtex)->tex->id);
@@ -2455,7 +2469,7 @@ static int copy_mtex_exec(bContext *C, wmOperator *UNUSED(op))
{
ID *id = CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot).owner_id;
- if (id == NULL) {
+ if (id == nullptr) {
/* copying empty slot */
ED_render_clear_mtex_copybuf();
return OPERATOR_CANCELLED;
@@ -2470,7 +2484,7 @@ static bool copy_mtex_poll(bContext *C)
{
ID *id = CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot).owner_id;
- return (id != NULL);
+ return (id != nullptr);
}
void TEXTURE_OT_slot_copy(wmOperatorType *ot)
@@ -2499,14 +2513,15 @@ static int paste_mtex_exec(bContext *C, wmOperator *UNUSED(op))
{
ID *id = CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot).owner_id;
- if (id == NULL) {
- Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
- Light *la = CTX_data_pointer_get_type(C, "light", &RNA_Light).data;
- World *wo = CTX_data_pointer_get_type(C, "world", &RNA_World).data;
- ParticleSystem *psys =
- CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data;
- FreestyleLineStyle *linestyle =
- CTX_data_pointer_get_type(C, "line_style", &RNA_FreestyleLineStyle).data;
+ if (id == nullptr) {
+ Material *ma = static_cast<Material *>(
+ CTX_data_pointer_get_type(C, "material", &RNA_Material).data);
+ Light *la = static_cast<Light *>(CTX_data_pointer_get_type(C, "light", &RNA_Light).data);
+ World *wo = static_cast<World *>(CTX_data_pointer_get_type(C, "world", &RNA_World).data);
+ ParticleSystem *psys = static_cast<ParticleSystem *>(
+ CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data);
+ FreestyleLineStyle *linestyle = static_cast<FreestyleLineStyle *>(
+ CTX_data_pointer_get_type(C, "line_style", &RNA_FreestyleLineStyle).data);
if (ma) {
id = &ma->id;
@@ -2524,14 +2539,14 @@ static int paste_mtex_exec(bContext *C, wmOperator *UNUSED(op))
id = &linestyle->id;
}
- if (id == NULL) {
+ if (id == nullptr) {
return OPERATOR_CANCELLED;
}
}
paste_mtex_copybuf(id);
- WM_event_add_notifier(C, NC_TEXTURE | ND_SHADING_LINKS, NULL);
+ WM_event_add_notifier(C, NC_TEXTURE | ND_SHADING_LINKS, nullptr);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.cc
index e975eab4736..b1e8e3927ef 100644
--- a/source/blender/editors/render/render_update.c
+++ b/source/blender/editors/render/render_update.cc
@@ -20,8 +20,8 @@
* \ingroup edrend
*/
-#include <stdlib.h>
-#include <string.h>
+#include <cstdlib>
+#include <cstring>
#include "DNA_cachefile_types.h"
#include "DNA_light_types.h"
@@ -49,6 +49,8 @@
#include "BKE_paint.h"
#include "BKE_scene.h"
+#include "NOD_composite.h"
+
#include "RE_engine.h"
#include "RE_pipeline.h"
@@ -62,7 +64,7 @@
#include "WM_api.h"
-#include <stdio.h>
+#include <cstdio>
/* -------------------------------------------------------------------- */
/** \name Render Engines
@@ -82,8 +84,8 @@ void ED_render_view3d_update(Depsgraph *depsgraph,
continue;
}
- View3D *v3d = area->spacedata.first;
- RegionView3D *rv3d = region->regiondata;
+ View3D *v3d = static_cast<View3D *>(area->spacedata.first);
+ RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
RenderEngine *engine = rv3d->render_engine;
/* call update if the scene changed, or if the render engine
@@ -94,7 +96,7 @@ void ED_render_view3d_update(Depsgraph *depsgraph,
bContext *C = CTX_create();
CTX_data_main_set(C, bmain);
CTX_data_scene_set(C, scene);
- CTX_wm_manager_set(C, bmain->wm.first);
+ CTX_wm_manager_set(C, static_cast<wmWindowManager *>(bmain->wm.first));
CTX_wm_window_set(C, window);
CTX_wm_screen_set(C, WM_window_get_active_screen(window));
CTX_wm_area_set(C, area);
@@ -111,15 +113,15 @@ void ED_render_view3d_update(Depsgraph *depsgraph,
else {
RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type);
if (updated) {
- DRW_notify_view_update((&(DRWUpdateContext){
- .bmain = bmain,
- .depsgraph = depsgraph,
- .scene = scene,
- .view_layer = view_layer,
- .region = region,
- .v3d = v3d,
- .engine_type = engine_type,
- }));
+ DRWUpdateContext drw_context = {nullptr};
+ drw_context.bmain = bmain;
+ drw_context.depsgraph = depsgraph;
+ drw_context.scene = scene;
+ drw_context.view_layer = view_layer;
+ drw_context.region = region;
+ drw_context.v3d = v3d;
+ drw_context.engine_type = engine_type;
+ DRW_notify_view_update(&drw_context);
}
}
}
@@ -148,7 +150,7 @@ void ED_render_scene_update(const DEGEditorUpdateContext *update_ctx, const bool
recursive_check = true;
- wmWindowManager *wm = bmain->wm.first;
+ wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
bScreen *screen = WM_window_get_active_screen(window);
@@ -166,13 +168,13 @@ void ED_render_engine_area_exit(Main *bmain, ScrArea *area)
{
/* clear all render engines in this area */
ARegion *region;
- wmWindowManager *wm = bmain->wm.first;
+ wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
if (area->spacetype != SPACE_VIEW3D) {
return;
}
- for (region = area->regionbase.first; region; region = region->next) {
+ for (region = static_cast<ARegion *>(area->regionbase.first); region; region = region->next) {
if (region->regiontype != RGN_TYPE_WINDOW || !(region->regiondata)) {
continue;
}
@@ -183,16 +185,18 @@ void ED_render_engine_area_exit(Main *bmain, ScrArea *area)
void ED_render_engine_changed(Main *bmain, const bool update_scene_data)
{
/* on changing the render engine type, clear all running render engines */
- for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (bScreen *screen = static_cast<bScreen *>(bmain->screens.first); screen;
+ screen = static_cast<bScreen *>(screen->id.next)) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
ED_render_engine_area_exit(bmain, area);
}
}
- RE_FreePersistentData(NULL);
+ RE_FreePersistentData(nullptr);
/* Inform all render engines and draw managers. */
- DEGEditorUpdateContext update_ctx = {NULL};
+ DEGEditorUpdateContext update_ctx = {nullptr};
update_ctx.bmain = bmain;
- for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ for (Scene *scene = static_cast<Scene *>(bmain->scenes.first); scene;
+ scene = static_cast<Scene *>(scene->id.next)) {
update_ctx.scene = scene;
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
/* TDODO(sergey): Iterate over depsgraphs instead? */
@@ -258,14 +262,16 @@ static void texture_changed(Main *bmain, Tex *tex)
/* icons */
BKE_icon_changed(BKE_icon_id_ensure(&tex->id));
- for (scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ for (scene = static_cast<Scene *>(bmain->scenes.first); scene;
+ scene = static_cast<Scene *>(scene->id.next)) {
/* paint overlays */
- for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (view_layer = static_cast<ViewLayer *>(scene->view_layers.first); view_layer;
+ view_layer = view_layer->next) {
BKE_paint_invalidate_overlay_tex(scene, view_layer, tex);
}
/* find compositing nodes */
if (scene->use_nodes && scene->nodetree) {
- for (node = scene->nodetree->nodes.first; node; node = node->next) {
+ for (node = static_cast<bNode *>(scene->nodetree->nodes.first); node; node = node->next) {
if (node->id == &tex->id) {
ED_node_tag_update_id(&scene->id);
}
@@ -288,7 +294,8 @@ static void image_changed(Main *bmain, Image *ima)
BKE_icon_changed(BKE_icon_id_ensure(&ima->id));
/* textures */
- for (tex = bmain->textures.first; tex; tex = tex->id.next) {
+ for (tex = static_cast<Tex *>(bmain->textures.first); tex;
+ tex = static_cast<Tex *>(tex->id.next)) {
if (tex->type == TEX_IMAGE && tex->ima == ima) {
texture_changed(bmain, tex);
}
@@ -300,10 +307,11 @@ static void scene_changed(Main *bmain, Scene *scene)
Object *ob;
/* glsl */
- for (ob = bmain->objects.first; ob; ob = ob->id.next) {
+ for (ob = static_cast<Object *>(bmain->objects.first); ob;
+ ob = static_cast<Object *>(ob->id.next)) {
if (ob->mode & OB_MODE_TEXTURE_PAINT) {
BKE_texpaint_slots_refresh_object(scene, ob);
- ED_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+ ED_paint_proj_mesh_data_check(scene, ob, nullptr, nullptr, nullptr, nullptr);
}
}
}
diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.cc
index 9163718ffad..980cd899120 100644
--- a/source/blender/editors/render/render_view.c
+++ b/source/blender/editors/render/render_view.cc
@@ -21,8 +21,8 @@
* \ingroup edrend
*/
-#include <stddef.h>
-#include <string.h>
+#include <cstddef>
+#include <cstring>
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
@@ -47,7 +47,7 @@
#include "wm_window.h"
-#include "render_intern.h"
+#include "render_intern.hh"
/*********************** utilities for finding areas *************************/
@@ -59,11 +59,11 @@
static ScrArea *biggest_non_image_area(bContext *C)
{
bScreen *screen = CTX_wm_screen(C);
- ScrArea *area, *big = NULL;
+ ScrArea *area, *big = nullptr;
int size, maxsize = 0, bwmaxsize = 0;
short foundwin = 0;
- for (area = screen->areabase.first; area; area = area->next) {
+ for (area = static_cast<ScrArea *>(screen->areabase.first); area; area = area->next) {
if (area->winx > 30 && area->winy > 30) {
size = area->winx * area->winy;
if (!area->full && area->spacetype == SPACE_PROPERTIES) {
@@ -86,17 +86,17 @@ static ScrArea *biggest_non_image_area(bContext *C)
static ScrArea *find_area_showing_r_result(bContext *C, Scene *scene, wmWindow **win)
{
wmWindowManager *wm = CTX_wm_manager(C);
- ScrArea *area = NULL;
+ ScrArea *area = nullptr;
SpaceImage *sima;
/* find an imagewindow showing render result */
- for (*win = wm->windows.first; *win; *win = (*win)->next) {
+ for (*win = static_cast<wmWindow *>(wm->windows.first); *win; *win = (*win)->next) {
if (WM_window_get_active_scene(*win) == scene) {
const bScreen *screen = WM_window_get_active_screen(*win);
- for (area = screen->areabase.first; area; area = area->next) {
+ for (area = static_cast<ScrArea *>(screen->areabase.first); area; area = area->next) {
if (area->spacetype == SPACE_IMAGE) {
- sima = area->spacedata.first;
+ sima = static_cast<SpaceImage *>(area->spacedata.first);
if (sima->image && sima->image->type == IMA_TYPE_R_RESULT) {
break;
}
@@ -118,9 +118,9 @@ static ScrArea *find_area_image_empty(bContext *C)
SpaceImage *sima;
/* find an imagewindow showing render result */
- for (area = screen->areabase.first; area; area = area->next) {
+ for (area = static_cast<ScrArea *>(screen->areabase.first); area; area = area->next) {
if (area->spacetype == SPACE_IMAGE) {
- sima = area->spacedata.first;
+ sima = static_cast<SpaceImage *>(area->spacedata.first);
if ((sima->mode == SI_MODE_VIEW) && !sima->image) {
break;
}
@@ -136,13 +136,13 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- wmWindow *win = NULL;
- ScrArea *area = NULL;
+ wmWindow *win = nullptr;
+ ScrArea *area = nullptr;
SpaceImage *sima;
bool area_was_image = false;
if (U.render_display_type == USER_RENDER_DISPLAY_NONE) {
- return NULL;
+ return nullptr;
}
if (U.render_display_type == USER_RENDER_DISPLAY_WINDOW) {
@@ -168,14 +168,14 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
true,
false,
true,
- WIN_ALIGN_LOCATION_CENTER) == NULL) {
+ WIN_ALIGN_LOCATION_CENTER) == nullptr) {
BKE_report(reports, RPT_ERROR, "Failed to open window!");
- return NULL;
+ return nullptr;
}
area = CTX_wm_area(C);
if (BLI_listbase_is_single(&area->spacedata) == false) {
- sima = area->spacedata.first;
+ sima = static_cast<SpaceImage *>(area->spacedata.first);
sima->flag |= SI_PREVSPACE;
}
}
@@ -185,7 +185,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
/* If the active screen is already in full-screen mode, skip this and
* unset the area, so that the full-screen area is just changed later. */
if (area && area->full) {
- area = NULL;
+ area = nullptr;
}
else {
if (area && area->spacetype == SPACE_IMAGE) {
@@ -199,7 +199,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
if (!area) {
area = find_area_showing_r_result(C, scene, &win);
- if (area == NULL) {
+ if (area == nullptr) {
area = find_area_image_empty(C);
}
@@ -208,12 +208,12 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
wm_window_raise(win);
}
- if (area == NULL) {
+ if (area == nullptr) {
/* find largest open non-image area */
area = biggest_non_image_area(C);
if (area) {
ED_area_newspace(C, area, SPACE_IMAGE, true);
- sima = area->spacedata.first;
+ sima = static_cast<SpaceImage *>(area->spacedata.first);
/* Makes "Escape" go back to previous space. */
sima->flag |= SI_PREVSPACE;
@@ -228,7 +228,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
area = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_TYPE_ANY, 0);
if (area->spacetype != SPACE_IMAGE) {
// XXX newspace(area, SPACE_IMAGE);
- sima = area->spacedata.first;
+ sima = static_cast<SpaceImage *>(area->spacedata.first);
/* Makes "Escape" go back to previous space. */
sima->flag |= SI_PREVSPACE;
@@ -236,7 +236,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
}
}
}
- sima = area->spacedata.first;
+ sima = static_cast<SpaceImage *>(area->spacedata.first);
sima->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
/* get the correct image, and scale it */
@@ -272,7 +272,7 @@ static int render_view_cancel_exec(bContext *C, wmOperator *UNUSED(op))
{
wmWindow *win = CTX_wm_window(C);
ScrArea *area = CTX_wm_area(C);
- SpaceImage *sima = area->spacedata.first;
+ SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
/* ensure image editor full-screen and area full-screen states are in sync */
if ((sima->flag & SI_FULLWINDOW) && !area->full) {
@@ -333,7 +333,7 @@ static int render_view_show_invoke(bContext *C, wmOperator *op, const wmEvent *e
ScrArea *area = find_area_showing_r_result(C, CTX_data_scene(C), &winshow);
/* is there another window on current scene showing result? */
- for (win = CTX_wm_manager(C)->windows.first; win; win = win->next) {
+ for (win = static_cast<wmWindow *>(CTX_wm_manager(C)->windows.first); win; win = win->next) {
const bScreen *screen = WM_window_get_active_screen(win);
if ((WM_window_is_temp_screen(win) &&
@@ -348,7 +348,7 @@ static int render_view_show_invoke(bContext *C, wmOperator *op, const wmEvent *e
if (area) {
/* but don't close it when rendering */
if (G.is_rendering == false) {
- SpaceImage *sima = area->spacedata.first;
+ SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
if (sima->flag & SI_PREVSPACE) {
sima->flag &= ~SI_PREVSPACE;
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 5dc6fe88663..c6834c84794 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -1667,7 +1667,7 @@ static bool event_in_markers_region(const ARegion *region, const wmEvent *event)
{
rcti rect = region->winrct;
rect.ymax = rect.ymin + UI_MARKER_MARGIN_Y;
- return BLI_rcti_isect_pt(&rect, event->xy[0], event->xy[1]);
+ return BLI_rcti_isect_pt_v(&rect, event->xy);
}
/**
@@ -1680,7 +1680,7 @@ static void ed_default_handlers(
/* NOTE: add-handler checks if it already exists. */
- /* XXX it would be good to have boundbox checks for some of these... */
+ /* XXX: it would be good to have bound-box checks for some of these. */
if (flag & ED_KEYMAP_UI) {
wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "User Interface", 0, 0);
WM_event_add_keymap_handler(handlers, keymap);
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index 5f523df18d1..63b7fbc14a7 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -64,7 +64,7 @@ IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin)
state.shader = GPU_shader_get_builtin_shader(builtin);
- /* Shader will be unbind by immUnbindProgram in immDrawPixelsTexScaled_clipping */
+ /* Shader will be unbind by immUnbindProgram in a `immDrawPixelsTex` function. */
immBindBuiltinProgram(builtin);
immUniform1i("image", 0);
state.do_shader_unbind = true;
@@ -72,23 +72,92 @@ IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin)
return state;
}
-void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
- float x,
- float y,
- int img_w,
- int img_h,
- eGPUTextureFormat gpu_format,
- bool use_filter,
- void *rect,
- float scaleX,
- float scaleY,
- float clip_min_x,
- float clip_min_y,
- float clip_max_x,
- float clip_max_y,
- float xzoom,
- float yzoom,
- const float color[4])
+void immDrawPixelsTexScaledFullSize(const IMMDrawPixelsTexState *state,
+ const float x,
+ const float y,
+ const int img_w,
+ const int img_h,
+ const eGPUTextureFormat gpu_format,
+ const bool use_filter,
+ const void *rect,
+ const float scaleX,
+ const float scaleY,
+ const float xzoom,
+ const float yzoom,
+ const float color[4])
+{
+ static const float white[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ const float draw_width = img_w * scaleX * xzoom;
+ const float draw_height = img_h * scaleY * yzoom;
+ /* Down-scaling with regular bi-linear interpolation (i.e. #GL_LINEAR) doesn't give good
+ * filtering results. Mipmaps can be used to get better results (i.e. #GL_LINEAR_MIPMAP_LINEAR),
+ * so always use mipmaps when filtering. */
+ const bool use_mipmap = use_filter && ((draw_width < img_w) || (draw_height < img_h));
+
+ GPUTexture *tex = GPU_texture_create_2d("immDrawPixels", img_w, img_h, 1, gpu_format, NULL);
+
+ const bool use_float_data = ELEM(gpu_format, GPU_RGBA16F, GPU_RGB16F, GPU_R16F);
+ eGPUDataFormat gpu_data_format = (use_float_data) ? GPU_DATA_FLOAT : GPU_DATA_UBYTE;
+ GPU_texture_update(tex, gpu_data_format, rect);
+
+ GPU_texture_filter_mode(tex, use_filter);
+ if (use_mipmap) {
+ GPU_texture_generate_mipmap(tex);
+ GPU_texture_mipmap_mode(tex, true, true);
+ }
+ GPU_texture_wrap_mode(tex, false, true);
+
+ GPU_texture_bind(tex, 0);
+
+ /* optional */
+ /* NOTE: Shader could be null for GLSL OCIO drawing, it is fine, since
+ * it does not need color.
+ */
+ if (state->shader != NULL && GPU_shader_get_uniform(state->shader, "color") != -1) {
+ immUniformColor4fv((color) ? color : white);
+ }
+
+ uint pos = state->pos, texco = state->texco;
+
+ immBegin(GPU_PRIM_TRI_FAN, 4);
+ immAttr2f(texco, 0.0f, 0.0f);
+ immVertex2f(pos, x, y);
+
+ immAttr2f(texco, 1.0f, 0.0f);
+ immVertex2f(pos, x + draw_width, y);
+
+ immAttr2f(texco, 1.0f, 1.0f);
+ immVertex2f(pos, x + draw_width, y + draw_height);
+
+ immAttr2f(texco, 0.0f, 1.0f);
+ immVertex2f(pos, x, y + draw_height);
+ immEnd();
+
+ if (state->do_shader_unbind) {
+ immUnbindProgram();
+ }
+
+ GPU_texture_unbind(tex);
+ GPU_texture_free(tex);
+}
+
+void immDrawPixelsTexTiled_scaling_clipping(IMMDrawPixelsTexState *state,
+ float x,
+ float y,
+ int img_w,
+ int img_h,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
+ void *rect,
+ float scaleX,
+ float scaleY,
+ float clip_min_x,
+ float clip_min_y,
+ float clip_max_x,
+ float clip_max_y,
+ float xzoom,
+ float yzoom,
+ const float color[4])
{
int subpart_x, subpart_y, tex_w = 256, tex_h = 256;
int seamless, offset_x, offset_y, nsubparts_x, nsubparts_y;
@@ -242,103 +311,103 @@ void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
GPU_unpack_row_length_set(0);
}
-void immDrawPixelsTexScaled(IMMDrawPixelsTexState *state,
- float x,
- float y,
- int img_w,
- int img_h,
- eGPUTextureFormat gpu_format,
- bool use_filter,
- void *rect,
- float scaleX,
- float scaleY,
- float xzoom,
- float yzoom,
- const float color[4])
+void immDrawPixelsTexTiled_scaling(IMMDrawPixelsTexState *state,
+ float x,
+ float y,
+ int img_w,
+ int img_h,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
+ void *rect,
+ float scaleX,
+ float scaleY,
+ float xzoom,
+ float yzoom,
+ const float color[4])
{
- immDrawPixelsTexScaled_clipping(state,
- x,
- y,
- img_w,
- img_h,
- gpu_format,
- use_filter,
- rect,
- scaleX,
- scaleY,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- xzoom,
- yzoom,
- color);
+ immDrawPixelsTexTiled_scaling_clipping(state,
+ x,
+ y,
+ img_w,
+ img_h,
+ gpu_format,
+ use_filter,
+ rect,
+ scaleX,
+ scaleY,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ xzoom,
+ yzoom,
+ color);
}
-void immDrawPixelsTex(IMMDrawPixelsTexState *state,
- float x,
- float y,
- int img_w,
- int img_h,
- eGPUTextureFormat gpu_format,
- bool use_filter,
- void *rect,
- float xzoom,
- float yzoom,
- const float color[4])
+void immDrawPixelsTexTiled(IMMDrawPixelsTexState *state,
+ float x,
+ float y,
+ int img_w,
+ int img_h,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
+ void *rect,
+ float xzoom,
+ float yzoom,
+ const float color[4])
{
- immDrawPixelsTexScaled_clipping(state,
- x,
- y,
- img_w,
- img_h,
- gpu_format,
- use_filter,
- rect,
- 1.0f,
- 1.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- xzoom,
- yzoom,
- color);
+ immDrawPixelsTexTiled_scaling_clipping(state,
+ x,
+ y,
+ img_w,
+ img_h,
+ gpu_format,
+ use_filter,
+ rect,
+ 1.0f,
+ 1.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ xzoom,
+ yzoom,
+ color);
}
-void immDrawPixelsTex_clipping(IMMDrawPixelsTexState *state,
- float x,
- float y,
- int img_w,
- int img_h,
- eGPUTextureFormat gpu_format,
- bool use_filter,
- void *rect,
- float clip_min_x,
- float clip_min_y,
- float clip_max_x,
- float clip_max_y,
- float xzoom,
- float yzoom,
- const float color[4])
+void immDrawPixelsTexTiled_clipping(IMMDrawPixelsTexState *state,
+ float x,
+ float y,
+ int img_w,
+ int img_h,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
+ void *rect,
+ float clip_min_x,
+ float clip_min_y,
+ float clip_max_x,
+ float clip_max_y,
+ float xzoom,
+ float yzoom,
+ const float color[4])
{
- immDrawPixelsTexScaled_clipping(state,
- x,
- y,
- img_w,
- img_h,
- gpu_format,
- use_filter,
- rect,
- 1.0f,
- 1.0f,
- clip_min_x,
- clip_min_y,
- clip_max_x,
- clip_max_y,
- xzoom,
- yzoom,
- color);
+ immDrawPixelsTexTiled_scaling_clipping(state,
+ x,
+ y,
+ img_w,
+ img_h,
+ gpu_format,
+ use_filter,
+ rect,
+ 1.0f,
+ 1.0f,
+ clip_min_x,
+ clip_min_y,
+ clip_max_x,
+ clip_max_y,
+ xzoom,
+ yzoom,
+ color);
}
/* **** Color management helper functions for GLSL display/transform ***** */
@@ -409,40 +478,40 @@ void ED_draw_imbuf_clipping(ImBuf *ibuf,
}
if (format != 0) {
- immDrawPixelsTex_clipping(&state,
- x,
- y,
- ibuf->x,
- ibuf->y,
- format,
- use_filter,
- ibuf->rect_float,
- clip_min_x,
- clip_min_y,
- clip_max_x,
- clip_max_y,
- zoom_x,
- zoom_y,
- NULL);
+ immDrawPixelsTexTiled_clipping(&state,
+ x,
+ y,
+ ibuf->x,
+ ibuf->y,
+ format,
+ use_filter,
+ ibuf->rect_float,
+ clip_min_x,
+ clip_min_y,
+ clip_max_x,
+ clip_max_y,
+ zoom_x,
+ zoom_y,
+ NULL);
}
}
else if (ibuf->rect) {
/* ibuf->rect is always RGBA */
- immDrawPixelsTex_clipping(&state,
- x,
- y,
- ibuf->x,
- ibuf->y,
- GPU_RGBA8,
- use_filter,
- ibuf->rect,
- clip_min_x,
- clip_min_y,
- clip_max_x,
- clip_max_y,
- zoom_x,
- zoom_y,
- NULL);
+ immDrawPixelsTexTiled_clipping(&state,
+ x,
+ y,
+ ibuf->x,
+ ibuf->y,
+ GPU_RGBA8,
+ use_filter,
+ ibuf->rect,
+ clip_min_x,
+ clip_min_y,
+ clip_max_x,
+ clip_max_y,
+ zoom_x,
+ zoom_y,
+ NULL);
}
IMB_colormanagement_finish_glsl_draw();
@@ -461,21 +530,21 @@ void ED_draw_imbuf_clipping(ImBuf *ibuf,
if (display_buffer) {
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- immDrawPixelsTex_clipping(&state,
- x,
- y,
- ibuf->x,
- ibuf->y,
- GPU_RGBA8,
- use_filter,
- display_buffer,
- clip_min_x,
- clip_min_y,
- clip_max_x,
- clip_max_y,
- zoom_x,
- zoom_y,
- NULL);
+ immDrawPixelsTexTiled_clipping(&state,
+ x,
+ y,
+ ibuf->x,
+ ibuf->y,
+ GPU_RGBA8,
+ use_filter,
+ display_buffer,
+ clip_min_x,
+ clip_min_y,
+ clip_max_x,
+ clip_max_y,
+ zoom_x,
+ zoom_y,
+ NULL);
}
IMB_display_buffer_release(cache_handle);
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/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c
index e720ae4b9d8..01730b3c9aa 100644
--- a/source/blender/editors/screen/screen_draw.c
+++ b/source/blender/editors/screen/screen_draw.c
@@ -144,7 +144,7 @@ static void drawscredge_area_draw(
}
GPUBatch *batch = batch_screen_edges_get(NULL);
- GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_AREA_EDGES);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_AREA_BORDERS);
GPU_batch_uniform_4fv(batch, "rect", (float *)&rect);
GPU_batch_draw(batch);
}
@@ -212,7 +212,7 @@ void ED_screen_draw_edges(wmWindow *win)
GPU_blend(GPU_BLEND_ALPHA);
GPUBatch *batch = batch_screen_edges_get(&verts_per_corner);
- GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_AREA_EDGES);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_AREA_BORDERS);
GPU_batch_uniform_1i(batch, "cornerLen", verts_per_corner);
GPU_batch_uniform_1f(batch, "scale", corner_scale);
GPU_batch_uniform_4fv(batch, "color", col);
diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h
index bc06e46ba96..e42c891b0ba 100644
--- a/source/blender/editors/screen/screen_intern.h
+++ b/source/blender/editors/screen/screen_intern.h
@@ -71,10 +71,10 @@ typedef enum eScreenAxis {
/**
* we swap spaces for fullscreen to keep all allocated data area vertices were set
*/
-void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, const bool do_free);
+void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, bool do_free);
void ED_area_data_swap(ScrArea *area_dst, ScrArea *area_src);
/* for quick toggle, can skip fades */
-void region_toggle_hidden(struct bContext *C, ARegion *region, const bool do_fade);
+void region_toggle_hidden(struct bContext *C, ARegion *region, bool do_fade);
/* screen_draw.c */
@@ -85,7 +85,7 @@ void region_toggle_hidden(struct bContext *C, ARegion *region, const bool do_fad
* \param sa2: Target area that will be replaced.
*/
void screen_draw_join_highlight(struct ScrArea *sa1, struct ScrArea *sa2);
-void screen_draw_split_preview(struct ScrArea *area, const eScreenAxis dir_axis, const float fac);
+void screen_draw_split_preview(struct ScrArea *area, eScreenAxis dir_axis, float fac);
/* screen_edit.c */
@@ -111,9 +111,9 @@ void screen_change_prepare(bScreen *screen_old,
ScrArea *area_split(const wmWindow *win,
bScreen *screen,
ScrArea *area,
- const eScreenAxis dir_axis,
- const float fac,
- const bool merge);
+ eScreenAxis dir_axis,
+ float fac,
+ bool merge);
/**
* Join any two neighboring areas. Might involve complex changes.
*/
@@ -127,8 +127,7 @@ eScreenDir area_getorientation(ScrArea *sa_a, ScrArea *sa_b);
/**
* Get alignment offset of adjacent areas. 'dir' value is like #area_getorientation().
*/
-void area_getoffsets(
- ScrArea *sa_a, ScrArea *sa_b, const eScreenDir dir, int *r_offset1, int *r_offset2);
+void area_getoffsets(ScrArea *sa_a, ScrArea *sa_b, eScreenDir dir, int *r_offset1, int *r_offset2);
/**
* Close a screen area, allowing most-aligned neighbor to take its place.
*/
@@ -150,15 +149,15 @@ bool screen_geom_edge_is_horizontal(ScrEdge *se);
*/
ScrEdge *screen_geom_area_map_find_active_scredge(const struct ScrAreaMap *area_map,
const rcti *bounds_rect,
- const int mx,
- const int my);
+ int mx,
+ int my);
/**
* Need win size to make sure not to include edges along screen edge.
*/
ScrEdge *screen_geom_find_active_scredge(const wmWindow *win,
const bScreen *screen,
- const int mx,
- const int my);
+ int mx,
+ int my);
/**
* \brief Main screen-layout calculation function.
*
@@ -172,7 +171,7 @@ void screen_geom_vertices_scale(const wmWindow *win, bScreen *screen);
*/
short screen_geom_find_area_split_point(const ScrArea *area,
const rcti *window_rect,
- const eScreenAxis dir_axis,
+ eScreenAxis dir_axis,
float fac);
/**
* Select all edges that are directly or indirectly connected to \a edge.
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index d017345b523..6581bffb6bd 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -1128,8 +1128,7 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
AREAMAP_FROM_SCREEN(screen), &screen_rect, event->xy[0], event->xy[1]) == NULL)) {
/* What area are we now in? */
- ScrArea *area = BKE_screen_find_area_xy(
- screen, SPACE_TYPE_ANY, event->xy[0], event->xy[1]);
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy);
if (area == sad->sa1) {
/* Same area, so possible split. */
@@ -1173,7 +1172,7 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* gesture is large enough? */
if (is_gesture) {
/* second area, for join when (sa1 != sa2) */
- sad->sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy[0], event->xy[1]);
+ sad->sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy);
/* apply sends event */
actionzone_apply(C, op, sad->az->type);
actionzone_exit(op);
@@ -1241,12 +1240,16 @@ static ScrEdge *screen_area_edge_from_cursor(const bContext *C,
int borderwidth = (4 * UI_DPI_FAC);
ScrArea *sa1, *sa2;
if (screen_geom_edge_is_horizontal(actedge)) {
- sa1 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0], cursor[1] + borderwidth);
- sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0], cursor[1] - borderwidth);
+ sa1 = BKE_screen_find_area_xy(
+ screen, SPACE_TYPE_ANY, (const int[2]){cursor[0], cursor[1] + borderwidth});
+ sa2 = BKE_screen_find_area_xy(
+ screen, SPACE_TYPE_ANY, (const int[2]){cursor[0], cursor[1] - borderwidth});
}
else {
- sa1 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0] + borderwidth, cursor[1]);
- sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0] - borderwidth, cursor[1]);
+ sa1 = BKE_screen_find_area_xy(
+ screen, SPACE_TYPE_ANY, (const int[2]){cursor[0] + borderwidth, cursor[1]});
+ sa2 = BKE_screen_find_area_xy(
+ screen, SPACE_TYPE_ANY, (const int[2]){cursor[0] - borderwidth, cursor[1]});
}
bool isGlobal = ((sa1 && ED_area_is_global(sa1)) || (sa2 && ED_area_is_global(sa2)));
if (!isGlobal) {
@@ -1334,8 +1337,7 @@ static int area_swap_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case MOUSEMOVE:
/* second area, for join */
- sad->sa2 = BKE_screen_find_area_xy(
- CTX_wm_screen(C), SPACE_TYPE_ANY, event->xy[0], event->xy[1]);
+ sad->sa2 = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->xy);
break;
case LEFTMOUSE: /* release LMB */
if (event->val == KM_RELEASE) {
@@ -2081,15 +2083,31 @@ typedef struct sAreaSplitData {
} sAreaSplitData;
+static bool area_split_allowed(const ScrArea *area, const eScreenAxis dir_axis)
+{
+ if (!area || area->global) {
+ /* Must be a non-global area. */
+ return false;
+ }
+
+ if ((dir_axis == SCREEN_AXIS_V && area->winx <= 2 * AREAMINX) ||
+ (dir_axis == SCREEN_AXIS_H && area->winy <= 2 * ED_area_headersize())) {
+ /* Must be at least double minimum sizes to split into two. */
+ return false;
+ }
+
+ return true;
+}
+
static void area_split_draw_cb(const struct wmWindow *UNUSED(win), void *userdata)
{
const wmOperator *op = userdata;
sAreaSplitData *sd = op->customdata;
- if (sd->sarea) {
- const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction");
- float fac = RNA_float_get(op->ptr, "factor");
+ const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction");
+ if (area_split_allowed(sd->sarea, dir_axis)) {
+ float fac = RNA_float_get(op->ptr, "factor");
screen_draw_split_preview(sd->sarea, dir_axis, fac);
}
}
@@ -2119,18 +2137,6 @@ static bool area_split_init(bContext *C, wmOperator *op)
/* required properties */
const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction");
- /* minimal size */
- if (dir_axis == SCREEN_AXIS_V) {
- if (area->winx < 2 * AREAMINX) {
- return false;
- }
- }
- else {
- if (area->winy < 2 * ED_area_headersize()) {
- return false;
- }
- }
-
/* custom data */
sAreaSplitData *sd = (sAreaSplitData *)MEM_callocN(sizeof(sAreaSplitData), "op_area_split");
op->customdata = sd;
@@ -2187,6 +2193,10 @@ static bool area_split_apply(bContext *C, wmOperator *op)
float fac = RNA_float_get(op->ptr, "factor");
const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction");
+ if (!area_split_allowed(sd->sarea, dir_axis)) {
+ return false;
+ }
+
sd->narea = area_split(win, screen, sd->sarea, dir_axis, fac, false); /* false = no merge */
if (sd->narea == NULL) {
@@ -2252,9 +2262,15 @@ static void area_split_exit(bContext *C, wmOperator *op)
static void area_split_preview_update_cursor(bContext *C, wmOperator *op)
{
- wmWindow *win = CTX_wm_window(C);
+ sAreaSplitData *sd = (sAreaSplitData *)op->customdata;
const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction");
- WM_cursor_set(win, (dir_axis == SCREEN_AXIS_H) ? WM_CURSOR_H_SPLIT : WM_CURSOR_V_SPLIT);
+ if (area_split_allowed(sd->sarea, dir_axis)) {
+ WM_cursor_set(CTX_wm_window(C),
+ (dir_axis == SCREEN_AXIS_H) ? WM_CURSOR_H_SPLIT : WM_CURSOR_V_SPLIT);
+ }
+ else {
+ WM_cursor_set(CTX_wm_window(C), WM_CURSOR_STOP);
+ }
}
/* UI callback, adds new handler */
@@ -2507,9 +2523,11 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (sd->sarea) {
ED_area_tag_redraw(sd->sarea);
}
+
+ area_split_preview_update_cursor(C, op);
+
/* area context not set */
- sd->sarea = BKE_screen_find_area_xy(
- CTX_wm_screen(C), SPACE_TYPE_ANY, event->xy[0], event->xy[1]);
+ sd->sarea = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->xy);
if (sd->sarea) {
ScrArea *area = sd->sarea;
@@ -3517,7 +3535,7 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case MOUSEMOVE: {
- ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy[0], event->xy[1]);
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy);
jd->dir = area_getorientation(jd->sa1, jd->sa2);
if (area == jd->sa1) {
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index 5c4ba67d72a..4bc9f1e2565 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -166,8 +166,7 @@ static int screenshot_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (use_crop) {
area = CTX_wm_area(C);
bScreen *screen = CTX_wm_screen(C);
- ScrArea *area_test = BKE_screen_find_area_xy(
- screen, SPACE_TYPE_ANY, event->xy[0], event->xy[1]);
+ ScrArea *area_test = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy);
if (area_test != NULL) {
area = area_test;
}
@@ -180,8 +179,9 @@ static int screenshot_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* extension is added by 'screenshot_check' after */
char filepath[FILE_MAX] = "//screen";
- if (G.relbase_valid) {
- BLI_strncpy(filepath, BKE_main_blendfile_path_from_global(), sizeof(filepath));
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ if (blendfile_path[0] != '\0') {
+ BLI_strncpy(filepath, blendfile_path, sizeof(filepath));
BLI_path_extension_replace(filepath, sizeof(filepath), ""); /* strip '.blend' */
}
RNA_string_set(op->ptr, "filepath", filepath);
diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c
index 125b345a1ed..6e69c82ba67 100644
--- a/source/blender/editors/screen/workspace_edit.c
+++ b/source/blender/editors/screen/workspace_edit.c
@@ -495,7 +495,7 @@ static void WORKSPACE_OT_reorder_to_back(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Workspace Reorder to Back";
- ot->description = "Reorder workspace to be first in the list";
+ ot->description = "Reorder workspace to be last in the list";
ot->idname = "WORKSPACE_OT_reorder_to_back";
/* api callbacks */
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index b826ff8701d..b15b6784d34 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -27,6 +27,7 @@ set(INC
../../gpu
../../imbuf
../../makesdna
+ ../../nodes
../../makesrna
../../render
../../windowmanager
@@ -59,6 +60,7 @@ set(SRC
sculpt.c
sculpt_automasking.c
sculpt_boundary.c
+ sculpt_brush_types.c
sculpt_cloth.c
sculpt_detail.c
sculpt_dyntopo.c
@@ -71,6 +73,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_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index 265746e27cd..4010b87a2ed 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -47,6 +47,8 @@
#include "BKE_object.h"
#include "BKE_paint.h"
+#include "NOD_texture.h"
+
#include "WM_api.h"
#include "wm_cursors.h"
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index dc2eaacca0c..a912bb5cf3b 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -56,6 +56,8 @@
#include "BKE_paint.h"
#include "BKE_undo_system.h"
+#include "NOD_texture.h"
+
#include "DEG_depsgraph.h"
#include "UI_interface.h"
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 7df5848e068..ca012f20f01 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -414,6 +414,7 @@ typedef struct ProjPaintState {
int totvert_eval;
const MVert *mvert_eval;
+ const float (*vert_normals)[3];
const MEdge *medge_eval;
const MPoly *mpoly_eval;
const MLoop *mloop_eval;
@@ -1718,10 +1719,10 @@ static float project_paint_uvpixel_mask(const ProjPaintState *ps,
float no[3], angle_cos;
if (mp->flag & ME_SMOOTH) {
- const short *no1, *no2, *no3;
- no1 = ps->mvert_eval[lt_vtri[0]].no;
- no2 = ps->mvert_eval[lt_vtri[1]].no;
- no3 = ps->mvert_eval[lt_vtri[2]].no;
+ const float *no1, *no2, *no3;
+ no1 = ps->vert_normals[lt_vtri[0]];
+ no2 = ps->vert_normals[lt_vtri[1]];
+ no3 = ps->vert_normals[lt_vtri[2]];
no[0] = w[0] * no1[0] + w[1] * no2[0] + w[2] * no3[0];
no[1] = w[0] * no1[1] + w[1] * no2[1] + w[2] * no3[1];
@@ -3871,7 +3872,6 @@ static void proj_paint_state_screen_coords_init(ProjPaintState *ps, const int di
static void proj_paint_state_cavity_init(ProjPaintState *ps)
{
- const MVert *mv;
const MEdge *me;
float *cavities;
int a;
@@ -3891,13 +3891,11 @@ static void proj_paint_state_cavity_init(ProjPaintState *ps)
sub_v3_v3(edges[me->v1], e);
counter[me->v1]++;
}
- for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++) {
+ for (a = 0; a < ps->totvert_eval; a++) {
if (counter[a] > 0) {
- float no[3];
mul_v3_fl(edges[a], 1.0f / counter[a]);
- normal_short_to_float_v3(no, mv->no);
/* Augment the difference. */
- cavities[a] = saacos(10.0f * dot_v3v3(no, edges[a])) * (float)M_1_PI;
+ cavities[a] = saacos(10.0f * dot_v3v3(ps->vert_normals[a], edges[a])) * (float)M_1_PI;
}
else {
cavities[a] = 0.0;
@@ -3964,7 +3962,7 @@ static void proj_paint_state_vert_flags_init(ProjPaintState *ps)
ps->vertFlags = MEM_callocN(sizeof(char) * ps->totvert_eval, "paint-vertFlags");
for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++) {
- normal_short_to_float_v3(no, mv->no);
+ copy_v3_v3(no, ps->vert_normals[a]);
if (UNLIKELY(ps->is_flip_object)) {
negate_v3(no);
}
@@ -4064,6 +4062,7 @@ static bool proj_paint_state_mesh_eval_init(const bContext *C, ProjPaintState *p
ps->mat_array[totmat - 1] = NULL;
ps->mvert_eval = ps->me_eval->mvert;
+ ps->vert_normals = BKE_mesh_vertex_normals_ensure(ps->me_eval);
if (ps->do_mask_cavity) {
ps->medge_eval = ps->me_eval->medge;
}
@@ -6567,7 +6566,7 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
nodeSetActive(ntree, imanode);
- /* Connect to first available principled bsdf node. */
+ /* Connect to first available principled BSDF node. */
bNode *in_node = ntreeFindType(ntree, SH_NODE_BSDF_PRINCIPLED);
bNode *out_node = imanode;
@@ -6623,7 +6622,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..d31390bbb42 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"
@@ -150,10 +152,7 @@ unsigned int vpaint_get_current_col(struct Scene *scene, struct VPaint *vp, bool
/**
* \note weight-paint has an equivalent function: #ED_wpaint_blend_tool
*/
-unsigned int ED_vpaint_blend_tool(const int tool,
- const uint col,
- const uint paintcol,
- const int alpha_i);
+unsigned int ED_vpaint_blend_tool(int tool, uint col, uint paintcol, int alpha_i);
/**
* Apply callback to each vertex of the active vertex color layer.
*/
@@ -171,10 +170,7 @@ bool ED_vpaint_color_transform(struct Object *ob,
*
* \note vertex-paint has an equivalent function: #ED_vpaint_blend_tool
*/
-float ED_wpaint_blend_tool(const int tool,
- const float weight,
- const float paintval,
- const float alpha);
+float ED_wpaint_blend_tool(int tool, float weight, float paintval, float alpha);
/* Utility for tools to ensure vertex groups exist before they begin. */
enum eWPaintFlag {
WPAINT_ENSURE_MIRROR = (1 << 0),
@@ -191,7 +187,7 @@ bool ED_wpaint_ensure_data(struct bContext *C,
enum eWPaintFlag flag,
struct WPaintVGroupIndex *vgroup_index);
/** Return -1 when invalid. */
-int ED_wpaint_mirror_vgroup_ensure(struct Object *ob, const int vgroup_active);
+int ED_wpaint_mirror_vgroup_ensure(struct Object *ob, int vgroup_active);
/* paint_vertex_color_ops.c */
@@ -244,7 +240,7 @@ void paint_2d_stroke_done(void *ps);
void paint_2d_stroke(void *ps,
const float prev_mval[2],
const float mval[2],
- const bool eraser,
+ bool eraser,
float pressure,
float distance,
float size);
@@ -267,7 +263,7 @@ void paint_proj_stroke(const struct bContext *C,
void *ps_handle_p,
const float prev_pos[2],
const float pos[2],
- const bool eraser,
+ bool eraser,
float pressure,
float distance,
float size);
@@ -331,8 +327,8 @@ typedef struct CurveMaskCache {
void paint_curve_mask_cache_free_data(CurveMaskCache *curve_mask_cache);
void paint_curve_mask_cache_update(CurveMaskCache *curve_mask_cache,
const struct Brush *brush,
- const int diameter,
- const float radius,
+ int diameter,
+ float radius,
const float cursor_position[2]);
/* sculpt_uv.c */
@@ -404,8 +400,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/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 23e03f3e576..75d4237d157 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -32,6 +32,7 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rect.h"
+#include "BLI_string.h"
#include "BLI_task.h"
#include "DNA_brush_types.h"
@@ -43,9 +44,11 @@
#include "RNA_access.h"
#include "BKE_brush.h"
+#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_layer.h"
+#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
@@ -1470,14 +1473,48 @@ struct WPaintData {
bool precomputed_weight_ready;
};
+static void smooth_brush_toggle_on(const bContext *C, Paint *paint, StrokeCache *cache)
+{
+ Scene *scene = CTX_data_scene(C);
+ Brush *brush = paint->brush;
+ int cur_brush_size = BKE_brush_size_get(scene, brush);
+
+ BLI_strncpy(
+ cache->saved_active_brush_name, brush->id.name + 2, sizeof(cache->saved_active_brush_name));
+
+ /* Switch to the blur (smooth) brush. */
+ brush = BKE_paint_toolslots_brush_get(paint, WPAINT_TOOL_BLUR);
+ if (brush) {
+ BKE_paint_brush_set(paint, brush);
+ cache->saved_smooth_size = BKE_brush_size_get(scene, brush);
+ BKE_brush_size_set(scene, brush, cur_brush_size);
+ BKE_curvemapping_init(brush->curve);
+ }
+}
+
+static void smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache *cache)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Brush *brush = BKE_paint_brush(paint);
+ /* The current brush should match with what we have stored in the cache. */
+ BLI_assert(brush == cache->brush);
+
+ /* Try to switch back to the saved/previous brush. */
+ BKE_brush_size_set(scene, brush, cache->saved_smooth_size);
+ brush = (Brush *)BKE_libblock_find_name(bmain, ID_BR, cache->saved_active_brush_name);
+ if (brush) {
+ BKE_paint_brush_set(paint, brush);
+ }
+}
+
/* Initialize the stroke cache invariants from operator properties */
static void vwpaint_update_cache_invariants(
- bContext *C, const VPaint *vp, SculptSession *ss, wmOperator *op, const float mouse[2])
+ bContext *C, VPaint *vp, SculptSession *ss, wmOperator *op, const float mouse[2])
{
StrokeCache *cache;
Scene *scene = CTX_data_scene(C);
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
- const Brush *brush = vp->paint.brush;
ViewContext *vc = paint_stroke_view_context(op->customdata);
Object *ob = CTX_data_active_object(C);
float mat[3][3];
@@ -1513,7 +1550,12 @@ static void vwpaint_update_cache_invariants(
ups->draw_inverted = false;
}
+ if (cache->alt_smooth) {
+ smooth_brush_toggle_on(C, &vp->paint, cache);
+ }
+
copy_v2_v2(cache->mouse, cache->initial_mouse);
+ Brush *brush = vp->paint.brush;
/* Truly temporary data that isn't stored in properties */
cache->vc = vc;
cache->brush = brush;
@@ -1715,15 +1757,15 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
wpd->mirror.lock = tmpflags;
}
- if (ELEM(vp->paint.brush->weightpaint_tool, WPAINT_TOOL_SMEAR, WPAINT_TOOL_BLUR)) {
- wpd->precomputed_weight = MEM_mallocN(sizeof(float) * me->totvert, __func__);
- }
-
/* If not previously created, create vertex/weight paint mode session data */
vertex_paint_init_stroke(depsgraph, ob);
vwpaint_update_cache_invariants(C, vp, ss, op, mouse);
vertex_paint_init_session_data(ts, ob);
+ if (ELEM(vp->paint.brush->weightpaint_tool, WPAINT_TOOL_SMEAR, WPAINT_TOOL_BLUR)) {
+ wpd->precomputed_weight = MEM_mallocN(sizeof(float) * me->totvert, __func__);
+ }
+
if (ob->sculpt->mode.wpaint.dvert_prev != NULL) {
MDeformVert *dv = ob->sculpt->mode.wpaint.dvert_prev;
for (int i = 0; i < me->totvert; i++, dv++) {
@@ -1735,13 +1777,6 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
return true;
}
-static float dot_vf3vs3(const float brushNormal[3], const short vertexNormal[3])
-{
- float normal[3];
- normal_short_to_float_v3(normal, vertexNormal);
- return dot_v3v3(brushNormal, normal);
-}
-
static void get_brush_alpha_data(const Scene *scene,
const SculptSession *ss,
const Brush *brush,
@@ -1868,7 +1903,7 @@ static void do_wpaint_brush_blur_task_cb_ex(void *__restrict userdata,
if (total_hit_loops != 0) {
float brush_strength = cache->bstrength;
const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) :
+ dot_v3v3(sculpt_normal_frontface, vd.no) :
1.0f;
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
@@ -1948,7 +1983,7 @@ static void do_wpaint_brush_smear_task_cb_ex(void *__restrict userdata,
if (!(use_face_sel || use_vert_sel) || mv_curr->flag & SELECT) {
float brush_strength = cache->bstrength;
const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) :
+ dot_v3v3(sculpt_normal_frontface, vd.no) :
1.0f;
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
@@ -2054,9 +2089,8 @@ static void do_wpaint_brush_draw_task_cb_ex(void *__restrict userdata,
/* If the vertex is selected */
if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) {
float brush_strength = cache->bstrength;
- const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) :
- 1.0f;
+ const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
+ 1.0f;
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
view_angle_limits_apply_falloff(
@@ -2111,7 +2145,7 @@ static void do_wpaint_brush_calc_average_weight_cb_ex(
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
/* Test to see if the vertex coordinates are within the spherical brush region. */
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float angle_cos = (use_normal && vd.no) ? dot_vf3vs3(sculpt_normal_frontface, vd.no) :
+ const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
1.0f;
if (angle_cos > 0.0 &&
BKE_brush_curve_strength(data->brush, sqrtf(test.dist), cache->radius) > 0.0) {
@@ -2403,7 +2437,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
wpi.vgroup_validmap = wpd->vgroup_validmap;
wpi.vgroup_locked = wpd->vgroup_locked;
wpi.vgroup_unlocked = wpd->vgroup_unlocked;
- wpi.do_flip = RNA_boolean_get(itemptr, "pen_flip");
+ wpi.do_flip = RNA_boolean_get(itemptr, "pen_flip") || ss->cache->invert;
wpi.do_multipaint = wpd->do_multipaint;
wpi.do_auto_normalize = ((ts->auto_normalize != 0) && (wpi.vgroup_validmap != NULL) &&
(wpi.do_multipaint || wpi.vgroup_validmap[wpi.active.index]));
@@ -2488,6 +2522,14 @@ static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
MEM_freeN(wpd);
}
+ SculptSession *ss = ob->sculpt;
+
+ if (ss->cache->alt_smooth) {
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ VPaint *vp = ts->wpaint;
+ smooth_brush_toggle_off(C, &vp->paint, ss->cache);
+ }
+
/* and particles too */
if (ob->particlesystem.first) {
ParticleSystem *psys;
@@ -2895,9 +2937,8 @@ static void do_vpaint_brush_draw_task_cb_ex(void *__restrict userdata,
/* Calc the dot prod. between ray norm on surf and current vert
* (ie splash prevention factor), and only paint front facing verts. */
float brush_strength = cache->bstrength;
- const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) :
- 1.0f;
+ const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
+ 1.0f;
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
view_angle_limits_apply_falloff(
@@ -2990,9 +3031,8 @@ static void do_vpaint_brush_blur_task_cb_ex(void *__restrict userdata,
/* If the vertex is selected for painting. */
if (!use_vert_sel || mv->flag & SELECT) {
float brush_strength = cache->bstrength;
- const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) :
- 1.0f;
+ const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
+ 1.0f;
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
view_angle_limits_apply_falloff(
@@ -3116,7 +3156,7 @@ static void do_vpaint_brush_smear_task_cb_ex(void *__restrict userdata,
* (ie splash prevention factor), and only paint front facing verts. */
float brush_strength = cache->bstrength;
const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) :
+ dot_v3v3(sculpt_normal_frontface, vd.no) :
1.0f;
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
@@ -3443,6 +3483,14 @@ static void vpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
MEM_freeN(vpd->smear.color_curr);
}
+ SculptSession *ss = ob->sculpt;
+
+ if (ss->cache->alt_smooth) {
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ VPaint *vp = ts->vpaint;
+ smooth_brush_toggle_off(C, &vp->paint, ss->cache);
+ }
+
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
MEM_freeN(vpd);
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_proj.c b/source/blender/editors/sculpt_paint/paint_vertex_proj.c
index 85cd211367a..9d5fffdcfcc 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_proj.c
@@ -72,8 +72,10 @@ struct VertProjUpdate {
/* -------------------------------------------------------------------- */
/* Internal Init */
-static void vpaint_proj_dm_map_cosnos_init__map_cb(
- void *userData, int index, const float co[3], const float no_f[3], const short no_s[3])
+static void vpaint_proj_dm_map_cosnos_init__map_cb(void *userData,
+ int index,
+ const float co[3],
+ const float no[3])
{
struct VertProjHandle *vp_handle = userData;
CoNo *co_no = &vp_handle->vcosnos[index];
@@ -86,12 +88,7 @@ static void vpaint_proj_dm_map_cosnos_init__map_cb(
}
copy_v3_v3(co_no->co, co);
- if (no_f) {
- copy_v3_v3(co_no->no, no_f);
- }
- else {
- normal_short_to_float_v3(co_no->no, no_s);
- }
+ copy_v3_v3(co_no->no, no);
}
static void vpaint_proj_dm_map_cosnos_init(struct Depsgraph *depsgraph,
@@ -116,8 +113,10 @@ static void vpaint_proj_dm_map_cosnos_init(struct Depsgraph *depsgraph,
/* Same as init but take mouse location into account */
-static void vpaint_proj_dm_map_cosnos_update__map_cb(
- void *userData, int index, const float co[3], const float no_f[3], const short no_s[3])
+static void vpaint_proj_dm_map_cosnos_update__map_cb(void *userData,
+ int index,
+ const float co[3],
+ const float no[3])
{
struct VertProjUpdate *vp_update = userData;
struct VertProjHandle *vp_handle = vp_update->vp_handle;
@@ -148,12 +147,7 @@ static void vpaint_proj_dm_map_cosnos_update__map_cb(
/* continue with regular functionality */
copy_v3_v3(co_no->co, co);
- if (no_f) {
- copy_v3_v3(co_no->no, no_f);
- }
- else {
- normal_short_to_float_v3(co_no->no, no_s);
- }
+ copy_v3_v3(co_no->no, no);
}
static void vpaint_proj_dm_map_cosnos_update(struct Depsgraph *depsgraph,
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
index d10a56be866..1dfc4db6ac3 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
@@ -665,8 +665,7 @@ static void gradientVert_update(WPGradient_userData *grad_data, int index)
static void gradientVertUpdate__mapFunc(void *userData,
int index,
const float UNUSED(co[3]),
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
WPGradient_userData *grad_data = userData;
WPGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
@@ -681,8 +680,7 @@ static void gradientVertUpdate__mapFunc(void *userData,
static void gradientVertInit__mapFunc(void *userData,
int index,
const float co[3],
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
WPGradient_userData *grad_data = userData;
Mesh *me = grad_data->me;
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index aeeed094aab..2725fc1eae4 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -73,6 +73,8 @@
#include "BKE_subdiv_ccg.h"
#include "BKE_subsurf.h"
+#include "NOD_texture.h"
+
#include "DEG_depsgraph.h"
#include "IMB_colormanagement.h"
@@ -177,11 +179,11 @@ void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3])
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
if (ss->shapekey_active || ss->deform_modifiers_active) {
- const MVert *mverts = BKE_pbvh_get_verts(ss->pbvh);
- normal_short_to_float_v3(no, mverts[index].no);
+ const float(*vert_normals)[3] = BKE_pbvh_get_vert_normals(ss->pbvh);
+ copy_v3_v3(no, vert_normals[index]);
}
else {
- normal_short_to_float_v3(no, ss->mvert[index].no);
+ copy_v3_v3(no, ss->vert_normals[index]);
}
break;
}
@@ -1329,103 +1331,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
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -1484,10 +1389,10 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata,
if (orig_data.unode->type == SCULPT_UNDO_COORDS) {
copy_v3_v3(vd.co, orig_data.co);
if (vd.no) {
- copy_v3_v3_short(vd.no, orig_data.no);
+ copy_v3_v3(vd.no, orig_data.no);
}
else {
- normal_short_to_float_v3(vd.fno, orig_data.no);
+ copy_v3_v3(vd.fno, orig_data.no);
}
}
else if (orig_data.unode->type == SCULPT_UNDO_MASK) {
@@ -1786,7 +1691,7 @@ const float *SCULPT_brush_frontface_normal_from_falloff_shape(SculptSession *ss,
static float frontface(const Brush *br,
const float sculpt_normal[3],
- const short no[3],
+ const float no[3],
const float fno[3])
{
if (!(br->flag & BRUSH_FRONTFACE)) {
@@ -1795,10 +1700,7 @@ static float frontface(const Brush *br,
float dot;
if (no) {
- float tmp[3];
-
- normal_short_to_float_v3(tmp, no);
- dot = dot_v3v3(tmp, sculpt_normal);
+ dot = dot_v3v3(no, sculpt_normal);
}
else {
dot = dot_v3v3(fno, sculpt_normal);
@@ -1835,15 +1737,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 +1806,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.
* \{ */
@@ -2044,19 +1937,19 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
float co[3];
/* For bm_vert only. */
- short no_s[3];
+ float no_s[3];
if (use_original) {
if (unode->bm_entry) {
const float *temp_co;
- const short *temp_no_s;
+ const float *temp_no_s;
BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &temp_co, &temp_no_s);
copy_v3_v3(co, temp_co);
- copy_v3_v3_short(no_s, temp_no_s);
+ copy_v3_v3(no_s, temp_no_s);
}
else {
copy_v3_v3(co, unode->co[vd.i]);
- copy_v3_v3_short(no_s, unode->no[vd.i]);
+ copy_v3_v3(no_s, unode->no[vd.i]);
}
}
else {
@@ -2076,11 +1969,11 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
data->any_vertex_sampled = true;
if (use_original) {
- normal_short_to_float_v3(no, no_s);
+ copy_v3_v3(no, no_s);
}
else {
if (vd.no) {
- normal_short_to_float_v3(no, vd.no);
+ copy_v3_v3(no, vd.no);
}
else {
copy_v3_v3(no, vd.fno);
@@ -2137,7 +2030,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);
@@ -2234,11 +2127,7 @@ bool SCULPT_pbvh_calc_area_normal(const Brush *brush,
return data.any_vertex_sampled;
}
-/**
- * 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);
@@ -2460,7 +2349,7 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
const Brush *br,
const float brush_point[3],
const float len,
- const short vno[3],
+ const float vno[3],
const float fno[3],
const float mask,
const int vertex_index,
@@ -2633,9 +2522,23 @@ void SCULPT_clip(Sculpt *sd, SculptSession *ss, float co[3], const float val[3])
continue;
}
- if (ss->cache && (ss->cache->flag & (CLIP_X << i)) &&
- (fabsf(co[i]) <= ss->cache->clip_tolerance[i])) {
- co[i] = 0.0f;
+ bool do_clip = false;
+ float co_clip[3];
+ if (ss->cache && (ss->cache->flag & (CLIP_X << i))) {
+ /* Take possible mirror object into account. */
+ mul_v3_m4v3(co_clip, ss->cache->clip_mirror_mtx, co);
+
+ if (fabsf(co_clip[i]) <= ss->cache->clip_tolerance[i]) {
+ co_clip[i] = 0.0f;
+ float imtx[4][4];
+ invert_m4_m4(imtx, ss->cache->clip_mirror_mtx);
+ mul_m4_v3(imtx, co_clip);
+ do_clip = true;
+ }
+ }
+
+ if (do_clip) {
+ co[i] = co_clip[i];
}
else {
co[i] = val[i];
@@ -2856,10 +2759,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 +2784,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 +2867,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 +2881,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 +2926,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 +2951,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);
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -5773,7 +3030,7 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Sculpt Prush Utilities
+/** \name Sculpt Brush Utilities
* \{ */
void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3])
@@ -5980,14 +3237,22 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
}
}
- /* Initialize automasking cache. For anchored brushes with spherical falloff, we start off with
- * zero radius, thus we have no pbvh nodes on the first brush step. */
+ /* For anchored brushes with spherical falloff, we start off with zero radius, thus we have no
+ * PBVH nodes on the first brush step. */
if (totnode ||
((brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) && (brush->flag & BRUSH_ANCHORED))) {
if (SCULPT_stroke_is_first_brush_step(ss->cache)) {
+ /* Initialize auto-masking cache. */
if (SCULPT_is_automasking_enabled(sd, ss, brush)) {
ss->cache->automasking = SCULPT_automasking_cache_init(sd, brush, ob);
}
+ /* Initialize surface smooth cache. */
+ if ((brush->sculpt_tool == SCULPT_TOOL_SMOOTH) &&
+ (brush->smooth_deform_type == BRUSH_SMOOTH_DEFORM_SURFACE)) {
+ BLI_assert(ss->cache->surface_smooth_laplacian_disp == NULL);
+ ss->cache->surface_smooth_laplacian_disp = MEM_callocN(
+ sizeof(float[3]) * SCULPT_vertex_count_get(ss), "HC smooth laplacian b");
+ }
}
}
@@ -6036,7 +3301,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 +3312,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 +3397,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 +3422,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. */
@@ -6386,11 +3651,6 @@ void SCULPT_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_used)
}
MEM_SAFE_FREE(nodes);
-
- /* Modifiers could depend on mesh normals, so we should update them.
- * NOTE: then if sculpting happens on locked key, normals should be re-calculate after applying
- * coords from key-block on base mesh. */
- BKE_mesh_calc_normals(me);
}
else if (ss->shapekey_active) {
sculpt_update_keyblock(ob);
@@ -6701,8 +3961,7 @@ static const char *sculpt_tool_name(Sculpt *sd)
return "Sculpting";
}
-/**
- * Operator for applying a stroke (various attributes including mouse path)
+/* Operator for applying a stroke (various attributes including mouse path)
* using the current brush. */
void SCULPT_cache_free(StrokeCache *cache)
@@ -6737,6 +3996,8 @@ static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss)
{
ModifierData *md;
+ unit_m4(ss->cache->clip_mirror_mtx);
+
for (md = ob->modifiers.first; md; md = md->next) {
if (!(md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime))) {
continue;
@@ -6758,6 +4019,73 @@ static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss)
if (mmd->tolerance > ss->cache->clip_tolerance[i]) {
ss->cache->clip_tolerance[i] = mmd->tolerance;
}
+
+ /* Store matrix for mirror object clipping. */
+ if (mmd->mirror_ob) {
+ float imtx_mirror_ob[4][4];
+ invert_m4_m4(imtx_mirror_ob, mmd->mirror_ob->obmat);
+ mul_m4_m4m4(ss->cache->clip_mirror_mtx, imtx_mirror_ob, ob->obmat);
+ }
+ }
+ }
+}
+
+static void smooth_brush_toggle_on(const bContext *C, Paint *paint, StrokeCache *cache)
+{
+ Scene *scene = CTX_data_scene(C);
+ Brush *brush = paint->brush;
+
+ if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
+ cache->saved_mask_brush_tool = brush->mask_tool;
+ brush->mask_tool = BRUSH_MASK_SMOOTH;
+ }
+ else if (ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_SLIDE_RELAX,
+ SCULPT_TOOL_DRAW_FACE_SETS,
+ SCULPT_TOOL_PAINT,
+ SCULPT_TOOL_SMEAR)) {
+ /* Do nothing, this tool has its own smooth mode. */
+ }
+ else {
+ int cur_brush_size = BKE_brush_size_get(scene, brush);
+
+ BLI_strncpy(cache->saved_active_brush_name,
+ brush->id.name + 2,
+ sizeof(cache->saved_active_brush_name));
+
+ /* Switch to the smooth brush. */
+ brush = BKE_paint_toolslots_brush_get(paint, SCULPT_TOOL_SMOOTH);
+ if (brush) {
+ BKE_paint_brush_set(paint, brush);
+ cache->saved_smooth_size = BKE_brush_size_get(scene, brush);
+ BKE_brush_size_set(scene, brush, cur_brush_size);
+ BKE_curvemapping_init(brush->curve);
+ }
+ }
+}
+
+static void smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache *cache)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Brush *brush = BKE_paint_brush(paint);
+
+ if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
+ brush->mask_tool = cache->saved_mask_brush_tool;
+ }
+ else if (ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_SLIDE_RELAX,
+ SCULPT_TOOL_DRAW_FACE_SETS,
+ SCULPT_TOOL_PAINT,
+ SCULPT_TOOL_SMEAR)) {
+ /* Do nothing. */
+ }
+ else {
+ /* Try to switch back to the saved/previous brush. */
+ BKE_brush_size_set(scene, brush, cache->saved_smooth_size);
+ brush = (Brush *)BKE_libblock_find_name(bmain, ID_BR, cache->saved_active_brush_name);
+ if (brush) {
+ BKE_paint_brush_set(paint, brush);
}
}
}
@@ -6767,8 +4095,6 @@ static void sculpt_update_cache_invariants(
bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mouse[2])
{
StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache");
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
Brush *brush = BKE_paint_brush(&sd->paint);
ViewContext *vc = paint_stroke_view_context(op->customdata);
@@ -6833,35 +4159,9 @@ static void sculpt_update_cache_invariants(
/* Alt-Smooth. */
if (cache->alt_smooth) {
- if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
- cache->saved_mask_brush_tool = brush->mask_tool;
- brush->mask_tool = BRUSH_MASK_SMOOTH;
- }
- else if (ELEM(brush->sculpt_tool,
- SCULPT_TOOL_SLIDE_RELAX,
- SCULPT_TOOL_DRAW_FACE_SETS,
- SCULPT_TOOL_PAINT,
- SCULPT_TOOL_SMEAR)) {
- /* Do nothing, this tool has its own smooth mode. */
- }
- else {
- Paint *p = &sd->paint;
- Brush *br;
- int size = BKE_brush_size_get(scene, brush);
-
- BLI_strncpy(cache->saved_active_brush_name,
- brush->id.name + 2,
- sizeof(cache->saved_active_brush_name));
-
- br = (Brush *)BKE_libblock_find_name(bmain, ID_BR, "Smooth");
- if (br) {
- BKE_paint_brush_set(p, br);
- brush = br;
- cache->saved_smooth_size = BKE_brush_size_get(scene, brush);
- BKE_brush_size_set(scene, brush, size);
- BKE_curvemapping_init(brush->curve);
- }
- }
+ smooth_brush_toggle_on(C, &sd->paint, cache);
+ /* Refresh the brush pointer in case we switched brush in the toggle function. */
+ brush = BKE_paint_brush(&sd->paint);
}
copy_v2_v2(cache->mouse, cache->initial_mouse);
@@ -6869,9 +4169,7 @@ static void sculpt_update_cache_invariants(
copy_v2_v2(ups->tex_mouse, cache->initial_mouse);
/* Truly temporary data that isn't stored in properties. */
-
cache->vc = vc;
-
cache->brush = brush;
/* Cache projection matrix. */
@@ -6946,7 +4244,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:
@@ -7989,9 +5287,7 @@ static void sculpt_brush_exit_tex(Sculpt *sd)
static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(stroke))
{
- Main *bmain = CTX_data_main(C);
Object *ob = CTX_data_active_object(C);
- Scene *scene = CTX_data_scene(C);
SculptSession *ss = ob->sculpt;
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -8009,23 +5305,9 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
/* Alt-Smooth. */
if (ss->cache->alt_smooth) {
- if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
- brush->mask_tool = ss->cache->saved_mask_brush_tool;
- }
- else if (ELEM(brush->sculpt_tool,
- SCULPT_TOOL_SLIDE_RELAX,
- SCULPT_TOOL_DRAW_FACE_SETS,
- SCULPT_TOOL_PAINT,
- SCULPT_TOOL_SMEAR)) {
- /* Do nothing. */
- }
- else {
- BKE_brush_size_set(scene, brush, ss->cache->saved_smooth_size);
- brush = (Brush *)BKE_libblock_find_name(bmain, ID_BR, ss->cache->saved_active_brush_name);
- if (brush) {
- BKE_paint_brush_set(&sd->paint, brush);
- }
- }
+ smooth_brush_toggle_off(C, &sd->paint, ss->cache);
+ /* Refresh the brush pointer in case we switched brush in the toggle function. */
+ brush = BKE_paint_brush(&sd->paint);
}
if (SCULPT_is_automasking_enabled(sd, ss, brush)) {
@@ -8131,7 +5413,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 +5441,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 +5716,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_boundary.c b/source/blender/editors/sculpt_paint/sculpt_boundary.c
index e238fafb063..1e41c5cdbdf 100644
--- a/source/blender/editors/sculpt_paint/sculpt_boundary.c
+++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c
@@ -772,12 +772,10 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata,
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index);
- float normal[3];
- normal_short_to_float_v3(normal, orig_data.no);
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
madd_v3_v3v3fl(target_co,
orig_data.co,
- normal,
+ orig_data.no,
boundary->edit_info[vd.index].strength_factor * disp * mask * automask *
strength);
diff --git a/source/blender/editors/sculpt_paint/sculpt_brush_types.c b/source/blender/editors/sculpt_paint/sculpt_brush_types.c
new file mode 100644
index 00000000000..c2acc361a79
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_brush_types.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 {
+ copy_v3_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 {
+ copy_v3_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];
+ copy_v3_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_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c
index dcfd7f7bcdc..3ac57d73d37 100644
--- a/source/blender/editors/sculpt_paint/sculpt_cloth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c
@@ -560,13 +560,6 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
thread_id);
float brush_disp[3];
- float normal[3];
- if (vd.no) {
- normal_short_to_float_v3(normal, vd.no);
- }
- else {
- copy_v3_v3(normal, vd.fno);
- }
switch (brush->cloth_deform_type) {
case BRUSH_CLOTH_DEFORM_DRAG:
@@ -621,7 +614,7 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
mul_v3_v3fl(force, disp_center, fade);
} break;
case BRUSH_CLOTH_DEFORM_INFLATE:
- mul_v3_v3fl(force, normal, fade);
+ mul_v3_v3fl(force, vd.no ? vd.no : vd.fno, fade);
break;
case BRUSH_CLOTH_DEFORM_EXPAND:
cloth_sim->length_constraint_tweak[vd.index] += fade * 0.1f;
diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c
index 9082408b8dd..f00b24d690a 100644
--- a/source/blender/editors/sculpt_paint/sculpt_detail.c
+++ b/source/blender/editors/sculpt_paint/sculpt_detail.c
@@ -248,8 +248,10 @@ static int sample_detail(bContext *C, int mx, int my, int mode)
{
/* Find 3D view to pick from. */
bScreen *screen = CTX_wm_screen(C);
- ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, mx, my);
- ARegion *region = (area) ? BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my) : NULL;
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, (const int[2]){mx, my});
+ ARegion *region = (area) ?
+ BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my}) :
+ NULL;
if (region == NULL) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
index 10f141e2311..cf45e25142b 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
@@ -334,14 +334,7 @@ static float neighbor_dirty_mask(SculptSession *ss, PBVHVertexIter *vd)
if (total > 0) {
mul_v3_fl(avg, 1.0f / total);
- float normal[3];
- if (vd->no) {
- normal_short_to_float_v3(normal, vd->no);
- }
- else {
- copy_v3_v3(normal, vd->fno);
- }
- float dot = dot_v3v3(avg, normal);
+ float dot = dot_v3v3(avg, vd->no ? vd->no : vd->fno);
float angle = max_ff(saacosf(dot), 0.0f);
return angle;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
index ff1a8935ba0..2d8bdc4e4ac 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
@@ -303,7 +303,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
- float orig_co[3], val[3], avg[3], normal[3], disp[3], disp2[3], transform[3][3], final_pos[3];
+ float orig_co[3], val[3], avg[3], disp[3], disp2[3], transform[3][3], final_pos[3];
float fade = vd.mask ? *vd.mask : 0.0f;
fade = 1.0f - fade;
fade *= data->filter_strength;
@@ -339,8 +339,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
sub_v3_v3v3(disp, val, orig_co);
break;
case MESH_FILTER_INFLATE:
- normal_short_to_float_v3(normal, orig_data.no);
- mul_v3_v3fl(disp, normal, fade);
+ mul_v3_v3fl(disp, orig_data.no, fade);
break;
case MESH_FILTER_SCALE:
unit_m3(transform);
@@ -372,7 +371,8 @@ static void mesh_filter_task_cb(void *__restrict userdata,
mid_v3_v3v3(disp, disp, disp2);
break;
case MESH_FILTER_RANDOM: {
- normal_short_to_float_v3(normal, orig_data.no);
+ float normal[3];
+ copy_v3_v3(normal, orig_data.no);
/* Index is not unique for multires, so hash by vertex coordinates. */
const uint *hash_co = (const uint *)orig_co;
const uint hash = BLI_hash_int_2d(hash_co[0], hash_co[1]) ^
@@ -432,7 +432,6 @@ static void mesh_filter_task_cb(void *__restrict userdata,
/* Intensify details. */
if (ss->filter_cache->sharpen_intensify_detail_strength > 0.0f) {
float detail_strength[3];
- normal_short_to_float_v3(detail_strength, orig_data.no);
copy_v3_v3(detail_strength, ss->filter_cache->detail_directions[vd.index]);
madd_v3_v3fl(disp,
detail_strength,
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 4dd2a786922..8de9fa3763b 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;
@@ -44,18 +44,12 @@ struct bContext;
enum ePaintSymmetryFlags;
-bool SCULPT_mode_poll(struct bContext *C);
-bool SCULPT_mode_poll_view3d(struct bContext *C);
-/**
- * Checks for a brush, not just sculpt mode.
- */
-bool SCULPT_poll(struct bContext *C);
-bool SCULPT_poll_view3d(struct bContext *C);
-
-bool SCULPT_vertex_colors_poll(struct bContext *C);
-
/* Updates */
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Types
+ * \{ */
+
typedef enum SculptUpdateType {
SCULPT_UPDATE_COORDS = 1 << 0,
SCULPT_UPDATE_MASK = 1 << 1,
@@ -63,86 +57,14 @@ typedef enum SculptUpdateType {
SCULPT_UPDATE_COLOR = 1 << 3,
} SculptUpdateType;
-void SCULPT_flush_update_step(bContext *C, SculptUpdateType update_flags);
-void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType update_flags);
-/**
- * Flush displacement from deformed PBVH to original layer.
- */
-void SCULPT_flush_stroke_deform(struct Sculpt *sd, Object *ob, bool is_proxy_used);
-
-/**
- * Should be used after modifying the mask or Face Sets IDs.
- */
-void SCULPT_tag_update_overlays(bContext *C);
-
-/* Stroke */
-
typedef struct SculptCursorGeometryInfo {
float location[3];
float normal[3];
float active_vertex_co[3];
} SculptCursorGeometryInfo;
-/**
- * Do a ray-cast in the tree to find the 3d brush location
- * (This allows us to ignore the GL depth buffer)
- * Returns 0 if the ray doesn't hit the mesh, non-zero otherwise.
- */
-bool SCULPT_stroke_get_location(struct bContext *C, float out[3], const float mouse[2]);
-/**
- * Gets the normal, location and active vertex location of the geometry under the cursor. This also
- * updates the active vertex and cursor related data of the SculptSession using the mouse position
- */
-bool SCULPT_cursor_geometry_info_update(bContext *C,
- SculptCursorGeometryInfo *out,
- const float mouse[2],
- bool use_sampled_normal);
-void SCULPT_geometry_preview_lines_update(bContext *C, struct SculptSession *ss, float radius);
-
-void SCULPT_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush);
-float SCULPT_raycast_init(struct ViewContext *vc,
- const float mouse[2],
- float ray_start[3],
- float ray_end[3],
- float ray_normal[3],
- bool original);
-
-/* Symmetry */
-char SCULPT_mesh_symmetry_xyz_get(Object *object);
-
-/* Sculpt PBVH abstraction API */
-
-void SCULPT_vertex_random_access_ensure(struct SculptSession *ss);
-
-int SCULPT_vertex_count_get(struct SculptSession *ss);
-const float *SCULPT_vertex_co_get(struct SculptSession *ss, int index);
-void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3]);
-float SCULPT_vertex_mask_get(struct SculptSession *ss, int index);
-const float *SCULPT_vertex_color_get(SculptSession *ss, int index);
-
-const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, int index);
-void SCULPT_vertex_persistent_normal_get(SculptSession *ss, int index, float no[3]);
-
-/**
- * Coordinates used for manipulating the base mesh when Grab Active Vertex is enabled.
- */
-const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, int index);
-
-/**
- * Returns the info of the limit surface when multi-res is available,
- * otherwise it returns the current coordinate of the vertex.
- */
-void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3]);
-
-/**
- * Returns the pointer to the coordinates that should be edited from a brush tool iterator
- * depending on the given deformation target.
- */
-float *SCULPT_brush_deform_target_vertex_co_get(SculptSession *ss,
- const int deform_target,
- PBVHVertexIter *iter);
-
#define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256
+
typedef struct SculptVertexNeighborIter {
/* Storage */
int *neighbors;
@@ -159,531 +81,33 @@ typedef struct SculptVertexNeighborIter {
bool is_duplicate;
} SculptVertexNeighborIter;
-void SCULPT_vertex_neighbors_get(struct SculptSession *ss,
- const int index,
- const bool include_duplicates,
- SculptVertexNeighborIter *iter);
-
-/* Iterator over neighboring vertices. */
-#define SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN(ss, v_index, neighbor_iterator) \
- SCULPT_vertex_neighbors_get(ss, v_index, false, &neighbor_iterator); \
- for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \
- neighbor_iterator.i++) { \
- neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i];
-
-/* Iterate over neighboring and duplicate vertices (for PBVH_GRIDS). Duplicates come
- * first since they are nearest for floodfill. */
-#define SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN(ss, v_index, neighbor_iterator) \
- SCULPT_vertex_neighbors_get(ss, v_index, true, &neighbor_iterator); \
- for (neighbor_iterator.i = neighbor_iterator.size - 1; neighbor_iterator.i >= 0; \
- neighbor_iterator.i--) { \
- neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i]; \
- neighbor_iterator.is_duplicate = (neighbor_iterator.i >= \
- neighbor_iterator.size - neighbor_iterator.num_duplicates);
-
-#define SCULPT_VERTEX_NEIGHBORS_ITER_END(neighbor_iterator) \
- } \
- if (neighbor_iterator.neighbors != neighbor_iterator.neighbors_fixed) { \
- MEM_freeN(neighbor_iterator.neighbors); \
- } \
- ((void)0)
-
-int SCULPT_active_vertex_get(SculptSession *ss);
-const float *SCULPT_active_vertex_co_get(SculptSession *ss);
-void SCULPT_active_vertex_normal_get(SculptSession *ss, float normal[3]);
-
-/* Returns PBVH deformed vertices array if shape keys or deform modifiers are used, otherwise
- * returns mesh original vertices array. */
-struct MVert *SCULPT_mesh_deformed_mverts_get(SculptSession *ss);
-
-/* Fake Neighbors */
-
-#define FAKE_NEIGHBOR_NONE -1
-
-void SCULPT_fake_neighbors_ensure(struct Sculpt *sd, Object *ob, const float max_dist);
-void SCULPT_fake_neighbors_enable(Object *ob);
-void SCULPT_fake_neighbors_disable(Object *ob);
-void SCULPT_fake_neighbors_free(struct Object *ob);
-
-/* Vertex Info. */
-void SCULPT_boundary_info_ensure(Object *object);
-/* Boundary Info needs to be initialized in order to use this function. */
-bool SCULPT_vertex_is_boundary(const SculptSession *ss, const int index);
-
-void SCULPT_connected_components_ensure(Object *ob);
-
-/* Sculpt Visibility API */
-
-void SCULPT_vertex_visible_set(SculptSession *ss, int index, bool visible);
-bool SCULPT_vertex_visible_get(SculptSession *ss, int index);
-
-void SCULPT_visibility_sync_all_face_sets_to_vertices(struct Object *ob);
-void SCULPT_visibility_sync_all_vertex_to_face_sets(struct SculptSession *ss);
-
-/* Face Sets API */
-
-int SCULPT_active_face_set_get(SculptSession *ss);
-int SCULPT_vertex_face_set_get(SculptSession *ss, int index);
-void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set);
-
-bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set);
-bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index);
-
-int SCULPT_face_set_next_available_get(SculptSession *ss);
-
-void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visible);
-bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, int index);
-bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index);
-
-void SCULPT_face_sets_visibility_invert(SculptSession *ss);
-void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible);
-
-/**
- * Returns true when the step belongs to the stroke that is directly performed by the brush and
- * not by one of the symmetry passes.
- */
-bool SCULPT_stroke_is_main_symmetry_pass(struct StrokeCache *cache);
-/**
- * Return true only once per stroke on the first symmetry pass, regardless of the symmetry passes
- * enabled.
- *
- * This should be used for functionality that needs to be computed once per stroke of a particular
- * tool (allocating memory, updating random seeds...).
- */
-bool SCULPT_stroke_is_first_brush_step(struct StrokeCache *cache);
-/**
- * Returns true on the first brush step of each symmetry pass.
- */
-bool SCULPT_stroke_is_first_brush_step_of_symmetry_pass(struct StrokeCache *cache);
-
/* Sculpt Original Data */
typedef struct {
struct BMLog *bm_log;
struct SculptUndoNode *unode;
float (*coords)[3];
- short (*normals)[3];
+ float (*normals)[3];
const float *vmasks;
float (*colors)[4];
/* Original coordinate, normal, and mask. */
const float *co;
- const short *no;
+ const float *no;
float mask;
const float *col;
} SculptOrigVertData;
-/**
- * Initialize a #SculptOrigVertData for accessing original vertex data;
- * handles #BMesh, #Mesh, and multi-resolution.
- */
-void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *node);
-/**
- * Update a #SculptOrigVertData for a particular vertex from the PBVH iterator.
- */
-void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter *iter);
-/**
- * Initialize a #SculptOrigVertData for accessing original vertex data;
- * handles #BMesh, #Mesh, and multi-resolution.
- */
-void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data,
- Object *ob,
- struct SculptUndoNode *unode);
-
-/* Utils. */
-void SCULPT_calc_brush_plane(struct Sculpt *sd,
- struct Object *ob,
- struct PBVHNode **nodes,
- int totnode,
- float r_area_no[3],
- float r_area_co[3]);
-
-void SCULPT_calc_area_normal(
- Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3]);
-
-int SCULPT_nearest_vertex_get(struct Sculpt *sd,
- struct Object *ob,
- const float co[3],
- float max_distance,
- bool use_original);
-
-int SCULPT_plane_point_side(const float co[3], const float plane[4]);
-int SCULPT_plane_trim(const struct StrokeCache *cache,
- const struct Brush *brush,
- const float val[3]);
-/**
- * Handles clipping against a mirror modifier and #SCULPT_LOCK_X/Y/Z axis flags.
- */
-void SCULPT_clip(Sculpt *sd, SculptSession *ss, float co[3], const float val[3]);
-
-float SCULPT_brush_plane_offset_get(Sculpt *sd, SculptSession *ss);
-
-ePaintSymmetryAreas SCULPT_get_vertex_symm_area(const float co[3]);
-bool SCULPT_check_vertex_pivot_symmetry(const float vco[3], const float pco[3], const char symm);
-/**
- * Checks if a vertex is inside the brush radius from any of its mirrored axis.
- */
-bool SCULPT_is_vertex_inside_brush_radius_symm(const float vertex[3],
- const float br_co[3],
- float radius,
- char symm);
-bool SCULPT_is_symmetry_iteration_valid(char i, char symm);
-void SCULPT_flip_v3_by_symm_area(float v[3],
- const ePaintSymmetryFlags symm,
- const ePaintSymmetryAreas symmarea,
- const float pivot[3]);
-void SCULPT_flip_quat_by_symm_area(float quat[4],
- const ePaintSymmetryFlags symm,
- const ePaintSymmetryAreas symmarea,
- const float pivot[3]);
-
/* Flood Fill. */
typedef struct {
GSQueue *queue;
BLI_bitmap *visited_vertices;
} SculptFloodFill;
-void SCULPT_floodfill_init(struct SculptSession *ss, SculptFloodFill *flood);
-void SCULPT_floodfill_add_active(struct Sculpt *sd,
- struct Object *ob,
- struct SculptSession *ss,
- SculptFloodFill *flood,
- float radius);
-void SCULPT_floodfill_add_initial_with_symmetry(struct Sculpt *sd,
- struct Object *ob,
- struct SculptSession *ss,
- SculptFloodFill *flood,
- int index,
- float radius);
-void SCULPT_floodfill_add_initial(SculptFloodFill *flood, int index);
-void SCULPT_floodfill_add_and_skip_initial(SculptFloodFill *flood, int index);
-void SCULPT_floodfill_execute(
- struct SculptSession *ss,
- SculptFloodFill *flood,
- bool (*func)(SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata),
- void *userdata);
-void SCULPT_floodfill_free(SculptFloodFill *flood);
-
-/* Dynamic topology */
-
-enum eDynTopoWarnFlag {
- DYNTOPO_WARN_VDATA = (1 << 0),
- DYNTOPO_WARN_EDATA = (1 << 1),
- DYNTOPO_WARN_LDATA = (1 << 2),
- DYNTOPO_WARN_MODIFIER = (1 << 3),
-};
-
-void SCULPT_dynamic_topology_enable_ex(struct Main *bmain,
- struct Depsgraph *depsgraph,
- Scene *scene,
- Object *ob);
-void SCULPT_dynamic_topology_disable(bContext *C, struct SculptUndoNode *unode);
-void sculpt_dynamic_topology_disable_with_undo(struct Main *bmain,
- struct Depsgraph *depsgraph,
- Scene *scene,
- Object *ob);
-
-/**
- * Returns true if the stroke will use dynamic topology, false
- * otherwise.
- *
- * Factors: some brushes like grab cannot do dynamic topology.
- * Others, like smooth, are better without.
- * Same goes for alt-key smoothing.
- */
-bool SCULPT_stroke_is_dynamic_topology(const SculptSession *ss, const Brush *brush);
-
-void SCULPT_dynamic_topology_triangulate(struct BMesh *bm);
-void SCULPT_dyntopo_node_layers_add(struct SculptSession *ss);
-
-enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob);
-
-void SCULPT_pbvh_clear(Object *ob);
-
-/* Auto-masking. */
-float SCULPT_automasking_factor_get(struct AutomaskingCache *automasking,
- SculptSession *ss,
- int vert);
-
-/* Returns the automasking cache depending on the active tool. Used for code that can run both for
- * brushes and filter. */
-struct AutomaskingCache *SCULPT_automasking_active_cache_get(SculptSession *ss);
-
-struct AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object *ob);
-void SCULPT_automasking_cache_free(struct AutomaskingCache *automasking);
-
-bool SCULPT_is_automasking_mode_enabled(const Sculpt *sd,
- const Brush *br,
- const eAutomasking_flag mode);
-bool SCULPT_is_automasking_enabled(const Sculpt *sd, const SculptSession *ss, const Brush *br);
-
typedef enum eBoundaryAutomaskMode {
AUTOMASK_INIT_BOUNDARY_EDGES = 1,
AUTOMASK_INIT_BOUNDARY_FACE_SETS = 2,
} eBoundaryAutomaskMode;
-float *SCULPT_boundary_automasking_init(Object *ob,
- eBoundaryAutomaskMode mode,
- int propagation_steps,
- float *automask_factor);
-
-/* Geodesic distances. */
-
-/**
- * Returns an array indexed by vertex index containing the geodesic distance to the closest vertex
- * in the initial vertex set. The caller is responsible for freeing the array.
- * Geodesic distances will only work when used with PBVH_FACES, for other types of PBVH it will
- * fallback to euclidean distances to one of the initial vertices in the set.
- */
-float *SCULPT_geodesic_distances_create(struct Object *ob,
- struct GSet *initial_vertices,
- const float limit_radius);
-float *SCULPT_geodesic_from_vertex_and_symm(struct Sculpt *sd,
- struct Object *ob,
- const int vertex,
- const float limit_radius);
-float *SCULPT_geodesic_from_vertex(Object *ob, const int vertex, const float limit_radius);
-
-/* Filters. */
-void SCULPT_filter_cache_init(struct bContext *C, Object *ob, Sculpt *sd, const int undo_type);
-void SCULPT_filter_cache_free(SculptSession *ss);
-
-void SCULPT_mask_filter_smooth_apply(
- Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, const int smooth_iterations);
-
-/* Brushes. */
-
-/* Cloth Brush. */
-
-/**
- * Main Brush Function.
- */
-void SCULPT_do_cloth_brush(struct Sculpt *sd,
- struct Object *ob,
- struct PBVHNode **nodes,
- int totnode);
-
-void SCULPT_cloth_simulation_free(struct SculptClothSimulation *cloth_sim);
-
-/* Public functions. */
-
-struct SculptClothSimulation *SCULPT_cloth_brush_simulation_create(
- struct SculptSession *ss,
- const float cloth_mass,
- const float cloth_damping,
- const float cloth_softbody_strength,
- const bool use_collisions,
- const bool needs_deform_coords);
-void SCULPT_cloth_brush_simulation_init(struct SculptSession *ss,
- struct SculptClothSimulation *cloth_sim);
-
-void SCULPT_cloth_sim_activate_nodes(struct SculptClothSimulation *cloth_sim,
- PBVHNode **nodes,
- int totnode);
-
-void SCULPT_cloth_brush_store_simulation_state(struct SculptSession *ss,
- struct SculptClothSimulation *cloth_sim);
-
-void SCULPT_cloth_brush_do_simulation_step(struct Sculpt *sd,
- struct Object *ob,
- struct SculptClothSimulation *cloth_sim,
- struct PBVHNode **nodes,
- int totnode);
-
-void SCULPT_cloth_brush_ensure_nodes_constraints(struct Sculpt *sd,
- struct Object *ob,
- struct PBVHNode **nodes,
- int totnode,
- struct SculptClothSimulation *cloth_sim,
- float initial_location[3],
- const float radius);
-
-/**
- * Cursor drawing function.
- */
-void SCULPT_cloth_simulation_limits_draw(const uint gpuattr,
- const struct Brush *brush,
- const float location[3],
- const float normal[3],
- const float rds,
- const float line_width,
- const float outline_col[3],
- const float alpha);
-void SCULPT_cloth_plane_falloff_preview_draw(const uint gpuattr,
- struct SculptSession *ss,
- const float outline_col[3],
- float outline_alpha);
-
-PBVHNode **SCULPT_cloth_brush_affected_nodes_gather(SculptSession *ss,
- Brush *brush,
- int *r_totnode);
-
-BLI_INLINE bool SCULPT_is_cloth_deform_brush(const Brush *brush)
-{
- return (brush->sculpt_tool == SCULPT_TOOL_CLOTH && ELEM(brush->cloth_deform_type,
- BRUSH_CLOTH_DEFORM_GRAB,
- BRUSH_CLOTH_DEFORM_SNAKE_HOOK)) ||
- /* All brushes that are not the cloth brush deform the simulation using softbody
- * constraints instead of applying forces. */
- (brush->sculpt_tool != SCULPT_TOOL_CLOTH &&
- brush->deform_target == BRUSH_DEFORM_TARGET_CLOTH_SIM);
-}
-
-BLI_INLINE bool SCULPT_tool_needs_all_pbvh_nodes(const Brush *brush)
-{
- if (brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) {
- /* Elastic deformations in any brush need all nodes to avoid artifacts as the effect
- * of the Kelvinlet is not constrained by the radius. */
- return true;
- }
-
- if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
- /* Pose needs all nodes because it applies all symmetry iterations at the same time
- * and the IK chain can grow to any area of the model. */
- /* TODO: This can be optimized by filtering the nodes after calculating the chain. */
- return true;
- }
-
- if (brush->sculpt_tool == SCULPT_TOOL_BOUNDARY) {
- /* Boundary needs all nodes because it is not possible to know where the boundary
- * deformation is going to be propagated before calculating it. */
- /* TODO: after calculating the boundary info in the first iteration, it should be
- * possible to get the nodes that have vertices included in any boundary deformation
- * and cache them. */
- return true;
- }
-
- if (brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK &&
- brush->snake_hook_deform_type == BRUSH_SNAKE_HOOK_DEFORM_ELASTIC) {
- /* Snake hook in elastic deform type has same requirements as the elastic deform tool. */
- return true;
- }
- return false;
-}
-
-/* Pose Brush. */
-
-/**
- * Main Brush Function.
- */
-void SCULPT_do_pose_brush(struct Sculpt *sd,
- struct Object *ob,
- struct PBVHNode **nodes,
- int totnode);
-/**
- * Calculate the pose origin and (Optionally the pose factor)
- * that is used when using the pose brush.
- *
- * \param r_pose_origin: Must be a valid pointer.
- * \param r_pose_factor: Optional, when set to NULL it won't be calculated.
- */
-void SCULPT_pose_calc_pose_data(struct Sculpt *sd,
- struct Object *ob,
- struct SculptSession *ss,
- float initial_location[3],
- float radius,
- float pose_offset,
- float *r_pose_origin,
- float *r_pose_factor);
-void SCULPT_pose_brush_init(struct Sculpt *sd,
- struct Object *ob,
- struct SculptSession *ss,
- struct Brush *br);
-struct SculptPoseIKChain *SCULPT_pose_ik_chain_init(struct Sculpt *sd,
- struct Object *ob,
- struct SculptSession *ss,
- struct Brush *br,
- const float initial_location[3],
- const float radius);
-void SCULPT_pose_ik_chain_free(struct SculptPoseIKChain *ik_chain);
-
-/* Boundary Brush. */
-
-/**
- * Main function to get #SculptBoundary data both for brush deformation and viewport preview.
- * Can return NULL if there is no boundary from the given vertex using the given radius.
- */
-struct SculptBoundary *SCULPT_boundary_data_init(Object *object,
- Brush *brush,
- const int initial_vertex,
- const float radius);
-void SCULPT_boundary_data_free(struct SculptBoundary *boundary);
-/* Main Brush Function. */
-void SCULPT_do_boundary_brush(struct Sculpt *sd,
- struct Object *ob,
- struct PBVHNode **nodes,
- int totnode);
-
-void SCULPT_boundary_edges_preview_draw(const uint gpuattr,
- struct SculptSession *ss,
- const float outline_col[3],
- const float outline_alpha);
-void SCULPT_boundary_pivot_line_preview_draw(const uint gpuattr, struct SculptSession *ss);
-
-/* Multi-plane Scrape Brush. */
-/* Main Brush Function. */
-void SCULPT_do_multiplane_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
-void SCULPT_multiplane_scrape_preview_draw(const uint gpuattr,
- Brush *brush,
- SculptSession *ss,
- const float outline_col[3],
- const float outline_alpha);
-/* Draw Face Sets Brush. */
-void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
-
-/* Paint Brush. */
-void SCULPT_do_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
-
-/* Smear Brush. */
-void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
-
-/* Smooth Brush. */
-
-/**
- * For bmesh: Average surrounding verts based on an orthogonality measure.
- * Naturally converges to a quad-like structure.
- */
-void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], struct BMVert *v);
-
-void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int index);
-float SCULPT_neighbor_mask_average(SculptSession *ss, int index);
-void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index);
-
-/**
- * Mask the mesh boundaries smoothing only the mesh surface without using auto-masking.
- */
-void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3], int index);
-
-void SCULPT_smooth(Sculpt *sd,
- Object *ob,
- PBVHNode **nodes,
- const int totnode,
- float bstrength,
- const bool smooth_mask);
-void SCULPT_do_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
-
-/* Surface Smooth Brush. */
-
-void SCULPT_surface_smooth_laplacian_step(SculptSession *ss,
- float *disp,
- const float co[3],
- float (*laplacian_disp)[3],
- const int v_index,
- const float origco[3],
- const float alpha);
-void SCULPT_surface_smooth_displace_step(SculptSession *ss,
- float *co,
- float (*laplacian_disp)[3],
- const int v_index,
- const float beta,
- const float fade);
-void SCULPT_do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
-
-/* Slide/Relax */
-void SCULPT_relax_vertex(struct SculptSession *ss,
- struct PBVHVertexIter *vd,
- float factor,
- bool filter_boundary_face_sets,
- float *r_final_pos);
/* Undo */
@@ -726,7 +150,7 @@ typedef struct SculptUndoNode {
float (*co)[3];
float (*orig_co)[3];
- short (*no)[3];
+ float (*no)[3];
float (*col)[4];
float *mask;
int totvert;
@@ -782,7 +206,13 @@ struct SculptRakeData {
float follow_co[3];
};
-/* Single struct used by all BLI_task threaded callbacks, let's avoid adding 10's of those... */
+/*
+Generic thread data. The size of this struct
+has gotten a little out of hand; normally we would
+split it up, but it might be better to see if we can't
+eliminate it altogether after moving to C++ (where
+we'll be able to use lambdas).
+*/
typedef struct SculptThreadedTaskData {
struct bContext *C;
struct Sculpt *sd;
@@ -939,70 +369,12 @@ typedef struct {
struct DistRayAABB_Precalc *dist_ray_to_aabb_precalc;
} SculptSearchCircleData;
-void SCULPT_brush_test_init(struct SculptSession *ss, SculptBrushTest *test);
-bool SCULPT_brush_test_sphere(SculptBrushTest *test, const float co[3]);
-bool SCULPT_brush_test_sphere_sq(SculptBrushTest *test, const float co[3]);
-bool SCULPT_brush_test_sphere_fast(const SculptBrushTest *test, const float co[3]);
-bool SCULPT_brush_test_cube(SculptBrushTest *test,
- const float co[3],
- const float local[4][4],
- const float roundness);
-bool SCULPT_brush_test_circle_sq(SculptBrushTest *test, const float co[3]);
-/**
- * Test AABB against sphere.
- */
-bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v);
-/**
- * 2D projection (distance to line).
- */
-bool SCULPT_search_circle_cb(PBVHNode *node, void *data_v);
-
-SculptBrushTestFn SCULPT_brush_test_init_with_falloff_shape(SculptSession *ss,
- SculptBrushTest *test,
- char falloff_shape);
-const float *SCULPT_brush_frontface_normal_from_falloff_shape(SculptSession *ss,
- char falloff_shape);
-
-/**
- * Return a multiplier for brush strength on a particular vertex.
- */
-float SCULPT_brush_strength_factor(struct SculptSession *ss,
- const struct Brush *br,
- const float point[3],
- const float len,
- const short vno[3],
- const float fno[3],
- const float mask,
- const int vertex_index,
- const int thread_id);
-
-/**
- * Tilts a normal by the x and y tilt values using the view axis.
- */
-void SCULPT_tilt_apply_to_normal(float r_normal[3],
- struct StrokeCache *cache,
- const float tilt_strength);
-
-/**
- * Get effective surface normal with pen tilt and tilt strength applied to it.
- */
-void SCULPT_tilt_effective_normal_get(const SculptSession *ss, const Brush *brush, float r_no[3]);
-
-/**
- * Expose 'calc_area_normal' externally (just for vertex paint).
- */
-bool SCULPT_pbvh_calc_area_normal(const struct Brush *brush,
- Object *ob,
- PBVHNode **nodes,
- int totnode,
- bool use_threading,
- float r_area_no[3]);
-
-/* Cache stroke properties. Used because
- * RNA property lookup isn't particularly fast.
- *
- * For descriptions of these settings, check the operator properties.
- */
+/* Sculpt Filters */
+typedef enum SculptFilterOrientation {
+ SCULPT_FILTER_ORIENTATION_LOCAL = 0,
+ SCULPT_FILTER_ORIENTATION_WORLD = 1,
+ SCULPT_FILTER_ORIENTATION_VIEW = 2,
+} SculptFilterOrientation;
#define SCULPT_CLAY_STABILIZER_LEN 10
@@ -1019,12 +391,74 @@ typedef struct AutomaskingCache {
float *factor;
} AutomaskingCache;
+typedef struct FilterCache {
+ bool enabled_axis[3];
+ bool enabled_force_axis[3];
+ int random_seed;
+
+ /* Used for alternating between filter operations in filters that need to apply different ones to
+ * achieve certain effects. */
+ int iteration_count;
+
+ /* Stores the displacement produced by the laplacian step of HC smooth. */
+ float (*surface_smooth_laplacian_disp)[3];
+ float surface_smooth_shape_preservation;
+ float surface_smooth_current_vertex;
+
+ /* Sharpen mesh filter. */
+ float sharpen_smooth_ratio;
+ float sharpen_intensify_detail_strength;
+ int sharpen_curvature_smooth_iterations;
+ float *sharpen_factor;
+ float (*detail_directions)[3];
+
+ /* Filter orientation. */
+ SculptFilterOrientation orientation;
+ float obmat[4][4];
+ float obmat_inv[4][4];
+ float viewmat[4][4];
+ float viewmat_inv[4][4];
+
+ /* Displacement eraser. */
+ float (*limit_surface_co)[3];
+
+ /* unmasked nodes */
+ PBVHNode **nodes;
+ int totnode;
+
+ /* Cloth filter. */
+ SculptClothSimulation *cloth_sim;
+ float cloth_sim_pinch_point[3];
+
+ /* mask expand iteration caches */
+ int mask_update_current_it;
+ int mask_update_last_it;
+ int *mask_update_it;
+ float *normal_factor;
+ float *edge_factor;
+ float *prev_mask;
+ float mask_expand_initial_co[3];
+
+ int new_face_set;
+ int *prev_face_set;
+
+ int active_face_set;
+
+ /* Auto-masking. */
+ AutomaskingCache *automasking;
+} FilterCache;
+
+/**
+ * This structure contains all the temporary data
+ * needed for individual brush strokes.
+ */
typedef struct StrokeCache {
/* Invariants */
float initial_radius;
float scale[3];
int flag;
float clip_tolerance[3];
+ float clip_mirror_mtx[4][4];
float initial_mouse[2];
/* Variants */
@@ -1181,27 +615,10 @@ typedef struct StrokeCache {
} StrokeCache;
-/* Sculpt Filters */
-typedef enum SculptFilterOrientation {
- SCULPT_FILTER_ORIENTATION_LOCAL = 0,
- SCULPT_FILTER_ORIENTATION_WORLD = 1,
- SCULPT_FILTER_ORIENTATION_VIEW = 2,
-} SculptFilterOrientation;
-
-/* Defines how transform tools are going to apply its displacement. */
-typedef enum SculptTransformDisplacementMode {
- /* Displaces the elements from their original coordinates. */
- SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL = 0,
- /* Displaces the elements incrementally from their previous position. */
- SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL = 1,
-} SculptTransformDisplacementMode;
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Expand
+ * \{ */
-/* Filter orientation utils. */
-void SCULPT_filter_to_orientation_space(float r_v[3], struct FilterCache *filter_cache);
-void SCULPT_filter_to_object_space(float r_v[3], struct FilterCache *filter_cache);
-void SCULPT_filter_zero_disabled_axis_components(float r_v[3], struct FilterCache *filter_cache);
-
-/* Sculpt Expand. */
typedef enum eSculptExpandFalloffType {
SCULPT_EXPAND_FALLOFF_GEODESIC,
SCULPT_EXPAND_FALLOFF_TOPOLOGY,
@@ -1349,83 +766,676 @@ typedef struct ExpandCache {
int *original_face_sets;
float (*original_colors)[4];
} ExpandCache;
+/** \} */
-typedef struct FilterCache {
- bool enabled_axis[3];
- bool enabled_force_axis[3];
- int random_seed;
+/** \} */
- /* Used for alternating between filter operations in filters that need to apply different ones to
- * achieve certain effects. */
- int iteration_count;
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Poll Functions
+ * \{ */
- /* Stores the displacement produced by the laplacian step of HC smooth. */
- float (*surface_smooth_laplacian_disp)[3];
- float surface_smooth_shape_preservation;
- float surface_smooth_current_vertex;
+bool SCULPT_mode_poll(struct bContext *C);
+bool SCULPT_mode_poll_view3d(struct bContext *C);
+/**
+ * Checks for a brush, not just sculpt mode.
+ */
+bool SCULPT_poll(struct bContext *C);
+bool SCULPT_poll_view3d(struct bContext *C);
- /* Sharpen mesh filter. */
- float sharpen_smooth_ratio;
- float sharpen_intensify_detail_strength;
- int sharpen_curvature_smooth_iterations;
- float *sharpen_factor;
- float (*detail_directions)[3];
+bool SCULPT_vertex_colors_poll(struct bContext *C);
- /* Filter orientation. */
- SculptFilterOrientation orientation;
- float obmat[4][4];
- float obmat_inv[4][4];
- float viewmat[4][4];
- float viewmat_inv[4][4];
+/** \} */
- /* Displacement eraser. */
- float (*limit_surface_co)[3];
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Update Functions
+ * \{ */
- /* unmasked nodes */
- PBVHNode **nodes;
- int totnode;
+void SCULPT_flush_update_step(bContext *C, SculptUpdateType update_flags);
+void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType update_flags);
- /* Cloth filter. */
- SculptClothSimulation *cloth_sim;
- float cloth_sim_pinch_point[3];
+void SCULPT_pbvh_clear(Object *ob);
- /* mask expand iteration caches */
- int mask_update_current_it;
- int mask_update_last_it;
- int *mask_update_it;
- float *normal_factor;
- float *edge_factor;
- float *prev_mask;
- float mask_expand_initial_co[3];
+/**
+ * Flush displacement from deformed PBVH to original layer.
+ */
+void SCULPT_flush_stroke_deform(struct Sculpt *sd, Object *ob, bool is_proxy_used);
- int new_face_set;
- int *prev_face_set;
+/**
+ * Should be used after modifying the mask or Face Sets IDs.
+ */
+void SCULPT_tag_update_overlays(bContext *C);
+/** \} */
- int active_face_set;
+/* -------------------------------------------------------------------- */
+/** \name Stroke Functions
+ * \{ */
- /* Transform. */
- SculptTransformDisplacementMode transform_displacement_mode;
+/* Stroke */
- /* Auto-masking. */
- AutomaskingCache *automasking;
-} FilterCache;
+/**
+ * Do a ray-cast in the tree to find the 3d brush location
+ * (This allows us to ignore the GL depth buffer)
+ * Returns 0 if the ray doesn't hit the mesh, non-zero otherwise.
+ */
+bool SCULPT_stroke_get_location(struct bContext *C, float out[3], const float mouse[2]);
+/**
+ * Gets the normal, location and active vertex location of the geometry under the cursor. This also
+ * updates the active vertex and cursor related data of the SculptSession using the mouse position
+ */
+bool SCULPT_cursor_geometry_info_update(bContext *C,
+ SculptCursorGeometryInfo *out,
+ const float mouse[2],
+ bool use_sampled_normal);
+void SCULPT_geometry_preview_lines_update(bContext *C, struct SculptSession *ss, float radius);
+
+void SCULPT_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush);
+float SCULPT_raycast_init(struct ViewContext *vc,
+ const float mouse[2],
+ float ray_start[3],
+ float ray_end[3],
+ float ray_normal[3],
+ bool original);
+
+/* Symmetry */
+char SCULPT_mesh_symmetry_xyz_get(Object *object);
+
+/**
+ * Returns true when the step belongs to the stroke that is directly performed by the brush and
+ * not by one of the symmetry passes.
+ */
+bool SCULPT_stroke_is_main_symmetry_pass(struct StrokeCache *cache);
+/**
+ * Return true only once per stroke on the first symmetry pass, regardless of the symmetry passes
+ * enabled.
+ *
+ * This should be used for functionality that needs to be computed once per stroke of a particular
+ * tool (allocating memory, updating random seeds...).
+ */
+bool SCULPT_stroke_is_first_brush_step(struct StrokeCache *cache);
+/**
+ * Returns true on the first brush step of each symmetry pass.
+ */
+bool SCULPT_stroke_is_first_brush_step_of_symmetry_pass(struct StrokeCache *cache);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt mesh accessor API
+ * \{ */
+
+/** Ensure random access; required for PBVH_BMESH */
+void SCULPT_vertex_random_access_ensure(struct SculptSession *ss);
+
+int SCULPT_vertex_count_get(struct SculptSession *ss);
+const float *SCULPT_vertex_co_get(struct SculptSession *ss, int index);
+
+/** Get the normal for a given sculpt vertex; do not modify the result */
+void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3]);
+
+float SCULPT_vertex_mask_get(struct SculptSession *ss, int index);
+const float *SCULPT_vertex_color_get(SculptSession *ss, int index);
+
+const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, int index);
+void SCULPT_vertex_persistent_normal_get(SculptSession *ss, int index, float no[3]);
+
+/**
+ * Coordinates used for manipulating the base mesh when Grab Active Vertex is enabled.
+ */
+const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, int index);
+
+/**
+ * Returns the info of the limit surface when multi-res is available,
+ * otherwise it returns the current coordinate of the vertex.
+ */
+void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3]);
+
+/**
+ * Returns the pointer to the coordinates that should be edited from a brush tool iterator
+ * depending on the given deformation target.
+ */
+float *SCULPT_brush_deform_target_vertex_co_get(SculptSession *ss,
+ int deform_target,
+ PBVHVertexIter *iter);
+
+void SCULPT_vertex_neighbors_get(struct SculptSession *ss,
+ int index,
+ bool include_duplicates,
+ SculptVertexNeighborIter *iter);
+
+/** Iterator over neighboring vertices. */
+#define SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN(ss, v_index, neighbor_iterator) \
+ SCULPT_vertex_neighbors_get(ss, v_index, false, &neighbor_iterator); \
+ for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \
+ neighbor_iterator.i++) { \
+ neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i];
+
+/** Iterate over neighboring and duplicate vertices (for PBVH_GRIDS). Duplicates come
+ * first since they are nearest for floodfill. */
+#define SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN(ss, v_index, neighbor_iterator) \
+ SCULPT_vertex_neighbors_get(ss, v_index, true, &neighbor_iterator); \
+ for (neighbor_iterator.i = neighbor_iterator.size - 1; neighbor_iterator.i >= 0; \
+ neighbor_iterator.i--) { \
+ neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i]; \
+ neighbor_iterator.is_duplicate = (neighbor_iterator.i >= \
+ neighbor_iterator.size - neighbor_iterator.num_duplicates);
+
+#define SCULPT_VERTEX_NEIGHBORS_ITER_END(neighbor_iterator) \
+ } \
+ if (neighbor_iterator.neighbors != neighbor_iterator.neighbors_fixed) { \
+ MEM_freeN(neighbor_iterator.neighbors); \
+ } \
+ ((void)0)
+
+int SCULPT_active_vertex_get(SculptSession *ss);
+const float *SCULPT_active_vertex_co_get(SculptSession *ss);
+void SCULPT_active_vertex_normal_get(SculptSession *ss, float normal[3]);
+
+/* Returns PBVH deformed vertices array if shape keys or deform modifiers are used, otherwise
+ * returns mesh original vertices array. */
+struct MVert *SCULPT_mesh_deformed_mverts_get(SculptSession *ss);
+
+/* Fake Neighbors */
+
+#define FAKE_NEIGHBOR_NONE -1
+
+void SCULPT_fake_neighbors_ensure(struct Sculpt *sd, Object *ob, float max_dist);
+void SCULPT_fake_neighbors_enable(Object *ob);
+void SCULPT_fake_neighbors_disable(Object *ob);
+void SCULPT_fake_neighbors_free(struct Object *ob);
+
+/* Vertex Info. */
+void SCULPT_boundary_info_ensure(Object *object);
+/* Boundary Info needs to be initialized in order to use this function. */
+bool SCULPT_vertex_is_boundary(const SculptSession *ss, int index);
+
+void SCULPT_connected_components_ensure(Object *ob);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Visibility API
+ * \{ */
+
+void SCULPT_vertex_visible_set(SculptSession *ss, int index, bool visible);
+bool SCULPT_vertex_visible_get(SculptSession *ss, int index);
+
+void SCULPT_visibility_sync_all_face_sets_to_vertices(struct Object *ob);
+void SCULPT_visibility_sync_all_vertex_to_face_sets(struct SculptSession *ss);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Face Sets API
+ * \{ */
+
+int SCULPT_active_face_set_get(SculptSession *ss);
+int SCULPT_vertex_face_set_get(SculptSession *ss, int index);
+void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set);
+
+bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set);
+bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index);
+
+int SCULPT_face_set_next_available_get(SculptSession *ss);
+
+void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visible);
+bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, int index);
+bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index);
+
+void SCULPT_face_sets_visibility_invert(SculptSession *ss);
+void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Original Data API
+ * \{ */
+
+/**
+ * Initialize a #SculptOrigVertData for accessing original vertex data;
+ * handles #BMesh, #Mesh, and multi-resolution.
+ */
+void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *node);
+/**
+ * Update a #SculptOrigVertData for a particular vertex from the PBVH iterator.
+ */
+void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter *iter);
+/**
+ * Initialize a #SculptOrigVertData for accessing original vertex data;
+ * handles #BMesh, #Mesh, and multi-resolution.
+ */
+void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data,
+ Object *ob,
+ struct SculptUndoNode *unode);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Brush Utilities.
+ * \{ */
+
+BLI_INLINE bool SCULPT_tool_needs_all_pbvh_nodes(const Brush *brush)
+{
+ if (brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) {
+ /* Elastic deformations in any brush need all nodes to avoid artifacts as the effect
+ * of the Kelvinlet is not constrained by the radius. */
+ return true;
+ }
+
+ if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
+ /* Pose needs all nodes because it applies all symmetry iterations at the same time
+ * and the IK chain can grow to any area of the model. */
+ /* TODO: This can be optimized by filtering the nodes after calculating the chain. */
+ return true;
+ }
+
+ if (brush->sculpt_tool == SCULPT_TOOL_BOUNDARY) {
+ /* Boundary needs all nodes because it is not possible to know where the boundary
+ * deformation is going to be propagated before calculating it. */
+ /* TODO: after calculating the boundary info in the first iteration, it should be
+ * possible to get the nodes that have vertices included in any boundary deformation
+ * and cache them. */
+ return true;
+ }
+
+ if (brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK &&
+ brush->snake_hook_deform_type == BRUSH_SNAKE_HOOK_DEFORM_ELASTIC) {
+ /* Snake hook in elastic deform type has same requirements as the elastic deform tool. */
+ return true;
+ }
+ return false;
+}
+
+void SCULPT_calc_brush_plane(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode,
+ float r_area_no[3],
+ float r_area_co[3]);
+
+void SCULPT_calc_area_normal(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3]);
+/**
+ * This calculates flatten center and area normal together,
+ * amortizing the memory bandwidth and loop overhead to calculate both at the same time.
+ */
+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,
+ const float co[3],
+ float max_distance,
+ bool use_original);
+
+int SCULPT_plane_point_side(const float co[3], const float plane[4]);
+int SCULPT_plane_trim(const struct StrokeCache *cache,
+ const struct Brush *brush,
+ const float val[3]);
+/**
+ * Handles clipping against a mirror modifier and #SCULPT_LOCK_X/Y/Z axis flags.
+ */
+void SCULPT_clip(Sculpt *sd, SculptSession *ss, float co[3], const float val[3]);
+
+float SCULPT_brush_plane_offset_get(Sculpt *sd, SculptSession *ss);
+
+ePaintSymmetryAreas SCULPT_get_vertex_symm_area(const float co[3]);
+bool SCULPT_check_vertex_pivot_symmetry(const float vco[3], const float pco[3], char symm);
+/**
+ * Checks if a vertex is inside the brush radius from any of its mirrored axis.
+ */
+bool SCULPT_is_vertex_inside_brush_radius_symm(const float vertex[3],
+ const float br_co[3],
+ float radius,
+ char symm);
+bool SCULPT_is_symmetry_iteration_valid(char i, char symm);
+void SCULPT_flip_v3_by_symm_area(float v[3],
+ ePaintSymmetryFlags symm,
+ ePaintSymmetryAreas symmarea,
+ const float pivot[3]);
+void SCULPT_flip_quat_by_symm_area(float quat[4],
+ ePaintSymmetryFlags symm,
+ ePaintSymmetryAreas symmarea,
+ const float pivot[3]);
+
+/**
+ * Initialize a point-in-brush test
+ */
+void SCULPT_brush_test_init(struct SculptSession *ss, SculptBrushTest *test);
+
+bool SCULPT_brush_test_sphere(SculptBrushTest *test, const float co[3]);
+bool SCULPT_brush_test_sphere_sq(SculptBrushTest *test, const float co[3]);
+bool SCULPT_brush_test_sphere_fast(const SculptBrushTest *test, const float co[3]);
+bool SCULPT_brush_test_cube(SculptBrushTest *test,
+ const float co[3],
+ const float local[4][4],
+ float roundness);
+bool SCULPT_brush_test_circle_sq(SculptBrushTest *test, const float co[3]);
+/**
+ * Test AABB against sphere.
+ */
+bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v);
+/**
+ * 2D projection (distance to line).
+ */
+bool SCULPT_search_circle_cb(PBVHNode *node, void *data_v);
+
+/**
+ * Initialize a point-in-brush test with a given falloff shape
+ *
+ * \param falloff_shape PAINT_FALLOFF_SHAPE_SPHERE or PAINT_FALLOFF_SHAPE_TUBE
+ * \return The brush falloff function
+ */
+SculptBrushTestFn SCULPT_brush_test_init_with_falloff_shape(SculptSession *ss,
+ SculptBrushTest *test,
+ char falloff_shape);
+const float *SCULPT_brush_frontface_normal_from_falloff_shape(SculptSession *ss,
+ char falloff_shape);
+
+/**
+ * Return a multiplier for brush strength on a particular vertex.
+ */
+float SCULPT_brush_strength_factor(struct SculptSession *ss,
+ const struct Brush *br,
+ const float point[3],
+ float len,
+ const float vno[3],
+ const float fno[3],
+ float mask,
+ int vertex_index,
+ int thread_id);
+
+/**
+ * Tilts a normal by the x and y tilt values using the view axis.
+ */
+void SCULPT_tilt_apply_to_normal(float r_normal[3],
+ struct StrokeCache *cache,
+ float tilt_strength);
+
+/**
+ * Get effective surface normal with pen tilt and tilt strength applied to it.
+ */
+void SCULPT_tilt_effective_normal_get(const SculptSession *ss, const Brush *brush, float r_no[3]);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Flood Fill
+ * \{ */
+
+void SCULPT_floodfill_init(struct SculptSession *ss, SculptFloodFill *flood);
+void SCULPT_floodfill_add_active(struct Sculpt *sd,
+ struct Object *ob,
+ struct SculptSession *ss,
+ SculptFloodFill *flood,
+ float radius);
+void SCULPT_floodfill_add_initial_with_symmetry(struct Sculpt *sd,
+ struct Object *ob,
+ struct SculptSession *ss,
+ SculptFloodFill *flood,
+ int index,
+ float radius);
+void SCULPT_floodfill_add_initial(SculptFloodFill *flood, int index);
+void SCULPT_floodfill_add_and_skip_initial(SculptFloodFill *flood, int index);
+void SCULPT_floodfill_execute(
+ struct SculptSession *ss,
+ SculptFloodFill *flood,
+ bool (*func)(SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata),
+ void *userdata);
+void SCULPT_floodfill_free(SculptFloodFill *flood);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dynamic topology
+ * \{ */
+
+enum eDynTopoWarnFlag {
+ DYNTOPO_WARN_VDATA = (1 << 0),
+ DYNTOPO_WARN_EDATA = (1 << 1),
+ DYNTOPO_WARN_LDATA = (1 << 2),
+ DYNTOPO_WARN_MODIFIER = (1 << 3),
+};
+
+/** Enable dynamic topology; mesh will be triangulated */
+void SCULPT_dynamic_topology_enable_ex(struct Main *bmain,
+ struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob);
+void SCULPT_dynamic_topology_disable(bContext *C, struct SculptUndoNode *unode);
+void sculpt_dynamic_topology_disable_with_undo(struct Main *bmain,
+ struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob);
+
+/**
+ * Returns true if the stroke will use dynamic topology, false
+ * otherwise.
+ *
+ * Factors: some brushes like grab cannot do dynamic topology.
+ * Others, like smooth, are better without.
+ * Same goes for alt-key smoothing.
+ */
+bool SCULPT_stroke_is_dynamic_topology(const SculptSession *ss, const Brush *brush);
+
+void SCULPT_dynamic_topology_triangulate(struct BMesh *bm);
+void SCULPT_dyntopo_node_layers_add(struct SculptSession *ss);
+
+enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Auto-masking.
+ * \{ */
+
+float SCULPT_automasking_factor_get(struct AutomaskingCache *automasking,
+ SculptSession *ss,
+ int vert);
+
+/* Returns the automasking cache depending on the active tool. Used for code that can run both for
+ * brushes and filter. */
+struct AutomaskingCache *SCULPT_automasking_active_cache_get(SculptSession *ss);
+
+struct AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object *ob);
+void SCULPT_automasking_cache_free(struct AutomaskingCache *automasking);
+
+bool SCULPT_is_automasking_mode_enabled(const Sculpt *sd, const Brush *br, eAutomasking_flag mode);
+bool SCULPT_is_automasking_enabled(const Sculpt *sd, const SculptSession *ss, const Brush *br);
+
+float *SCULPT_boundary_automasking_init(Object *ob,
+ eBoundaryAutomaskMode mode,
+ int propagation_steps,
+ float *automask_factor);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Geodesic distances.
+ * \{ */
+
+/**
+ * Returns an array indexed by vertex index containing the geodesic distance to the closest vertex
+ * in the initial vertex set. The caller is responsible for freeing the array.
+ * Geodesic distances will only work when used with PBVH_FACES, for other types of PBVH it will
+ * fallback to euclidean distances to one of the initial vertices in the set.
+ */
+float *SCULPT_geodesic_distances_create(struct Object *ob,
+ struct GSet *initial_vertices,
+ float limit_radius);
+float *SCULPT_geodesic_from_vertex_and_symm(struct Sculpt *sd,
+ struct Object *ob,
+ int vertex,
+ float limit_radius);
+float *SCULPT_geodesic_from_vertex(Object *ob, int vertex, float limit_radius);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Filter API
+ * \{ */
+
+void SCULPT_filter_cache_init(struct bContext *C, Object *ob, Sculpt *sd, int undo_type);
+void SCULPT_filter_cache_free(SculptSession *ss);
+
+void SCULPT_mask_filter_smooth_apply(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, int smooth_iterations);
+
+/* Filter orientation utils. */
+void SCULPT_filter_to_orientation_space(float r_v[3], struct FilterCache *filter_cache);
+void SCULPT_filter_to_object_space(float r_v[3], struct FilterCache *filter_cache);
+void SCULPT_filter_zero_disabled_axis_components(float r_v[3], struct FilterCache *filter_cache);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Cloth Simulation.
+ * \{ */
+
+/* Main cloth brush function */
+void SCULPT_do_cloth_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+
+void SCULPT_cloth_simulation_free(struct SculptClothSimulation *cloth_sim);
+
+/* Public functions. */
+
+struct SculptClothSimulation *SCULPT_cloth_brush_simulation_create(struct SculptSession *ss,
+ float cloth_mass,
+ float cloth_damping,
+ float cloth_softbody_strength,
+ bool use_collisions,
+ bool needs_deform_coords);
+void SCULPT_cloth_brush_simulation_init(struct SculptSession *ss,
+ struct SculptClothSimulation *cloth_sim);
+
+void SCULPT_cloth_sim_activate_nodes(struct SculptClothSimulation *cloth_sim,
+ PBVHNode **nodes,
+ int totnode);
+
+void SCULPT_cloth_brush_store_simulation_state(struct SculptSession *ss,
+ struct SculptClothSimulation *cloth_sim);
+
+void SCULPT_cloth_brush_do_simulation_step(struct Sculpt *sd,
+ struct Object *ob,
+ struct SculptClothSimulation *cloth_sim,
+ struct PBVHNode **nodes,
+ int totnode);
+
+void SCULPT_cloth_brush_ensure_nodes_constraints(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode,
+ struct SculptClothSimulation *cloth_sim,
+ float initial_location[3],
+ float radius);
+
+/**
+ * Cursor drawing function.
+ */
+void SCULPT_cloth_simulation_limits_draw(uint gpuattr,
+ const struct Brush *brush,
+ const float location[3],
+ const float normal[3],
+ float rds,
+ float line_width,
+ const float outline_col[3],
+ float alpha);
+void SCULPT_cloth_plane_falloff_preview_draw(uint gpuattr,
+ struct SculptSession *ss,
+ const float outline_col[3],
+ float outline_alpha);
+
+PBVHNode **SCULPT_cloth_brush_affected_nodes_gather(SculptSession *ss,
+ Brush *brush,
+ int *r_totnode);
+
+BLI_INLINE bool SCULPT_is_cloth_deform_brush(const Brush *brush)
+{
+ return (brush->sculpt_tool == SCULPT_TOOL_CLOTH && ELEM(brush->cloth_deform_type,
+ BRUSH_CLOTH_DEFORM_GRAB,
+ BRUSH_CLOTH_DEFORM_SNAKE_HOOK)) ||
+ /* All brushes that are not the cloth brush deform the simulation using softbody
+ * constraints instead of applying forces. */
+ (brush->sculpt_tool != SCULPT_TOOL_CLOTH &&
+ brush->deform_target == BRUSH_DEFORM_TARGET_CLOTH_SIM);
+}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Smoothing API
+ * \{ */
+
+/**
+ * For bmesh: Average surrounding verts based on an orthogonality measure.
+ * Naturally converges to a quad-like structure.
+ */
+void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], struct BMVert *v);
+
+void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int index);
+float SCULPT_neighbor_mask_average(SculptSession *ss, int index);
+void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index);
+
+/**
+ * Mask the mesh boundaries smoothing only the mesh surface without using auto-masking.
+ */
+void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3], int index);
+
+void SCULPT_smooth(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float bstrength, bool smooth_mask);
+void SCULPT_do_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
+
+/* Surface Smooth Brush. */
+
+void SCULPT_surface_smooth_laplacian_step(SculptSession *ss,
+ float *disp,
+ const float co[3],
+ float (*laplacian_disp)[3],
+ int v_index,
+ const float origco[3],
+ float alpha);
+void SCULPT_surface_smooth_displace_step(
+ SculptSession *ss, float *co, float (*laplacian_disp)[3], int v_index, float beta, float fade);
+void SCULPT_do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
+
+/* Slide/Relax */
+void SCULPT_relax_vertex(struct SculptSession *ss,
+ struct PBVHVertexIter *vd,
+ float factor,
+ bool filter_boundary_face_sets,
+ float *r_final_pos);
+
+/** \} */
+
+/**
+ * Expose 'calc_area_normal' externally (just for vertex paint).
+ */
+bool SCULPT_pbvh_calc_area_normal(const struct Brush *brush,
+ Object *ob,
+ PBVHNode **nodes,
+ int totnode,
+ bool use_threading,
+ float r_area_no[3]);
/**
* Flip all the edit-data across the axis/axes specified by \a symm.
* Used to calculate multiple modifications to the mesh when symmetry is enabled.
*/
-void SCULPT_cache_calc_brushdata_symm(StrokeCache *cache,
- const char symm,
- const char axis,
- const float angle);
+void SCULPT_cache_calc_brushdata_symm(StrokeCache *cache, char symm, char axis, float angle);
void SCULPT_cache_free(StrokeCache *cache);
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Undo
+ * \{ */
+
SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType type);
SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node);
SculptUndoNode *SCULPT_undo_get_first_node(void);
void SCULPT_undo_push_begin(struct Object *ob, const char *name);
void SCULPT_undo_push_end(void);
-void SCULPT_undo_push_end_ex(const bool use_nested_undo);
+void SCULPT_undo_push_end_ex(bool use_nested_undo);
+
+/** \} */
void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3]);
@@ -1444,12 +1454,17 @@ bool SCULPT_get_redraw_rect(struct ARegion *region,
/* Operators. */
-/* Expand. */
+/* -------------------------------------------------------------------- */
+/** \name Expand Operator
+ * \{ */
void SCULPT_OT_expand(struct wmOperatorType *ot);
void sculpt_expand_modal_keymap(struct wmKeyConfig *keyconf);
+/** \} */
-/* Gestures. */
+/* -------------------------------------------------------------------- */
+/** \name Gesture Operators
+ * \{ */
void SCULPT_OT_face_set_lasso_gesture(struct wmOperatorType *ot);
void SCULPT_OT_face_set_box_gesture(struct wmOperatorType *ot);
@@ -1458,8 +1473,11 @@ void SCULPT_OT_trim_lasso_gesture(struct wmOperatorType *ot);
void SCULPT_OT_trim_box_gesture(struct wmOperatorType *ot);
void SCULPT_OT_project_line_gesture(struct wmOperatorType *ot);
+/** \} */
-/* Face Sets. */
+/* -------------------------------------------------------------------- */
+/** \name Face Set Operators
+ * \{ */
void SCULPT_OT_face_sets_randomize_colors(struct wmOperatorType *ot);
void SCULPT_OT_face_sets_change_visibility(struct wmOperatorType *ot);
@@ -1467,9 +1485,18 @@ void SCULPT_OT_face_sets_init(struct wmOperatorType *ot);
void SCULPT_OT_face_sets_create(struct wmOperatorType *ot);
void SCULPT_OT_face_sets_edit(struct wmOperatorType *ot);
-/* Transform. */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Transform Operators
+ * \{ */
void SCULPT_OT_set_pivot_position(struct wmOperatorType *ot);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Filter Operators
+ * \{ */
/* Mesh Filter. */
@@ -1483,6 +1510,12 @@ void SCULPT_OT_cloth_filter(struct wmOperatorType *ot);
void SCULPT_OT_color_filter(struct wmOperatorType *ot);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Interactive Mask Operators
+ * \{ */
+
/* Mask filter and Dirty Mask. */
void SCULPT_OT_mask_filter(struct wmOperatorType *ot);
@@ -1495,14 +1528,210 @@ void SCULPT_OT_mask_expand(struct wmOperatorType *ot);
/* Mask Init. */
void SCULPT_OT_mask_init(struct wmOperatorType *ot);
+/** \} */
/* Detail size. */
+/* -------------------------------------------------------------------- */
+/** \name Dyntopo/Retopology Operators
+ * \{ */
+
void SCULPT_OT_detail_flood_fill(struct wmOperatorType *ot);
void SCULPT_OT_sample_detail_size(struct wmOperatorType *ot);
void SCULPT_OT_set_detail_size(struct wmOperatorType *ot);
void SCULPT_OT_dyntopo_detail_size_edit(struct wmOperatorType *ot);
+/** \} */
/* Dyntopo. */
void SCULPT_OT_dynamic_topology_toggle(struct wmOperatorType *ot);
+
+/* sculpt_brush_types.c */
+
+/* -------------------------------------------------------------------- */
+/** \name Brushes
+ * \{ */
+
+/* Pose Brush. */
+
+/**
+ * Main Brush Function.
+ */
+void SCULPT_do_pose_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+/**
+ * Calculate the pose origin and (Optionally the pose factor)
+ * that is used when using the pose brush.
+ *
+ * \param r_pose_origin: Must be a valid pointer.
+ * \param r_pose_factor: Optional, when set to NULL it won't be calculated.
+ */
+void SCULPT_pose_calc_pose_data(struct Sculpt *sd,
+ struct Object *ob,
+ struct SculptSession *ss,
+ float initial_location[3],
+ float radius,
+ float pose_offset,
+ float *r_pose_origin,
+ float *r_pose_factor);
+void SCULPT_pose_brush_init(struct Sculpt *sd,
+ struct Object *ob,
+ struct SculptSession *ss,
+ struct Brush *br);
+struct SculptPoseIKChain *SCULPT_pose_ik_chain_init(struct Sculpt *sd,
+ struct Object *ob,
+ struct SculptSession *ss,
+ struct Brush *br,
+ const float initial_location[3],
+ float radius);
+void SCULPT_pose_ik_chain_free(struct SculptPoseIKChain *ik_chain);
+
+/* Boundary Brush. */
+
+/**
+ * Main function to get #SculptBoundary data both for brush deformation and viewport preview.
+ * Can return NULL if there is no boundary from the given vertex using the given radius.
+ */
+struct SculptBoundary *SCULPT_boundary_data_init(Object *object,
+ Brush *brush,
+ int initial_vertex,
+ float radius);
+void SCULPT_boundary_data_free(struct SculptBoundary *boundary);
+/* Main Brush Function. */
+void SCULPT_do_boundary_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+
+void SCULPT_boundary_edges_preview_draw(uint gpuattr,
+ struct SculptSession *ss,
+ const float outline_col[3],
+ float outline_alpha);
+void SCULPT_boundary_pivot_line_preview_draw(uint gpuattr, struct SculptSession *ss);
+
+/* Multi-plane Scrape Brush. */
+/* Main Brush Function. */
+void SCULPT_do_multiplane_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
+void SCULPT_multiplane_scrape_preview_draw(uint gpuattr,
+ Brush *brush,
+ SculptSession *ss,
+ const float outline_col[3],
+ float outline_alpha);
+/* Draw Face Sets Brush. */
+void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
+
+/* Paint Brush. */
+void SCULPT_do_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
+
+/* Smear Brush. */
+void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
+
+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, int totnode, float bstrength);
+
+/* end sculpt_brush_types.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_multiplane_scrape.c b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
index 05db799cb00..0fec7a9c4bd 100644
--- a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
+++ b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
@@ -92,12 +92,7 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata,
}
float local_co[3];
float normal[3];
- if (vd.no) {
- normal_short_to_float_v3(normal, vd.no);
- }
- else {
- copy_v3_v3(normal, vd.fno);
- }
+ copy_v3_v3(normal, vd.no ? vd.no : vd.fno);
mul_v3_m4v3(local_co, mat, vd.co);
/* Use the brush falloff to weight the sampled normals. */
const float fade = SCULPT_brush_strength_factor(ss,
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/sculpt_paint/sculpt_smooth.c b/source/blender/editors/sculpt_paint/sculpt_smooth.c
index 847f42fe9e8..c65489548b7 100644
--- a/source/blender/editors/sculpt_paint/sculpt_smooth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_smooth.c
@@ -538,13 +538,6 @@ static void SCULPT_do_surface_smooth_brush_displace_task_cb_ex(
void SCULPT_do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
Brush *brush = BKE_paint_brush(&sd->paint);
- SculptSession *ss = ob->sculpt;
-
- if (SCULPT_stroke_is_first_brush_step(ss->cache)) {
- BLI_assert(ss->cache->surface_smooth_laplacian_disp == NULL);
- ss->cache->surface_smooth_laplacian_disp = MEM_callocN(
- sizeof(float[3]) * SCULPT_vertex_count_get(ss), "HC smooth laplacian b");
- }
/* Threaded loop over nodes. */
SculptThreadedTaskData data = {
diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c
index bfbe545d1ef..b91e05f226e 100644
--- a/source/blender/editors/sculpt_paint/sculpt_transform.c
+++ b/source/blender/editors/sculpt_paint/sculpt_transform.c
@@ -70,10 +70,6 @@ void ED_sculpt_init_transform(struct bContext *C, Object *ob)
copy_v4_v4(ss->init_pivot_rot, ss->pivot_rot);
copy_v3_v3(ss->init_pivot_scale, ss->pivot_scale);
- copy_v3_v3(ss->prev_pivot_pos, ss->pivot_pos);
- copy_v4_v4(ss->prev_pivot_rot, ss->pivot_rot);
- copy_v3_v3(ss->prev_pivot_scale, ss->pivot_scale);
-
SCULPT_undo_push_begin(ob, "Transform");
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
@@ -81,13 +77,10 @@ void ED_sculpt_init_transform(struct bContext *C, Object *ob)
SCULPT_vertex_random_access_ensure(ss);
SCULPT_filter_cache_init(C, ob, sd, SCULPT_UNDO_COORDS);
-
- ss->filter_cache->transform_displacement_mode = SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL;
}
static void sculpt_transform_matrices_init(SculptSession *ss,
const char symm,
- const SculptTransformDisplacementMode t_mode,
float r_transform_mats[8][4][4])
{
@@ -96,18 +89,9 @@ static void sculpt_transform_matrices_init(SculptSession *ss,
transform_mat[4][4];
float start_pivot_pos[3], start_pivot_rot[4], start_pivot_scale[3];
- switch (t_mode) {
- case SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL:
- copy_v3_v3(start_pivot_pos, ss->init_pivot_pos);
- copy_v4_v4(start_pivot_rot, ss->init_pivot_rot);
- copy_v3_v3(start_pivot_scale, ss->init_pivot_scale);
- break;
- case SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL:
- copy_v3_v3(start_pivot_pos, ss->prev_pivot_pos);
- copy_v4_v4(start_pivot_rot, ss->prev_pivot_rot);
- copy_v3_v3(start_pivot_scale, ss->prev_pivot_scale);
- break;
- }
+ copy_v3_v3(start_pivot_pos, ss->init_pivot_pos);
+ copy_v4_v4(start_pivot_rot, ss->init_pivot_rot);
+ copy_v3_v3(start_pivot_scale, ss->init_pivot_scale);
for (int i = 0; i < PAINT_SYMM_AREAS; i++) {
ePaintSymmetryAreas v_symm = i;
@@ -167,25 +151,15 @@ static void sculpt_transform_task_cb(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
float transformed_co[3], orig_co[3], disp[3];
- float *start_co;
float fade = vd.mask ? *vd.mask : 0.0f;
copy_v3_v3(orig_co, orig_data.co);
char symm_area = SCULPT_get_vertex_symm_area(orig_co);
- switch (ss->filter_cache->transform_displacement_mode) {
- case SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL:
- start_co = orig_co;
- break;
- case SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL:
- start_co = vd.co;
- break;
- }
-
- copy_v3_v3(transformed_co, start_co);
+ copy_v3_v3(transformed_co, orig_co);
mul_m4_v3(data->transform_mats[(int)symm_area], transformed_co);
- sub_v3_v3v3(disp, transformed_co, start_co);
+ sub_v3_v3v3(disp, transformed_co, orig_co);
mul_v3_fl(disp, 1.0f - fade);
- add_v3_v3v3(vd.co, start_co, disp);
+ add_v3_v3v3(vd.co, orig_co, disp);
if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
@@ -207,8 +181,7 @@ static void sculpt_transform_all_vertices(Sculpt *sd, Object *ob)
.nodes = ss->filter_cache->nodes,
};
- sculpt_transform_matrices_init(
- ss, symm, ss->filter_cache->transform_displacement_mode, data.transform_mats);
+ sculpt_transform_matrices_init(ss, symm, data.transform_mats);
/* Regular transform applies all symmetry passes at once as it is split by symmetry areas
* (each vertex can only be transformed once by the transform matrix of its area). */
@@ -229,10 +202,6 @@ void ED_sculpt_update_modal_transform(struct bContext *C, Object *ob)
sculpt_transform_all_vertices(sd, ob);
- copy_v3_v3(ss->prev_pivot_pos, ss->pivot_pos);
- copy_v4_v4(ss->prev_pivot_rot, ss->pivot_rot);
- copy_v3_v3(ss->prev_pivot_scale, ss->pivot_scale);
-
if (ss->deform_modifiers_active || ss->shapekey_active) {
SCULPT_flush_stroke_deform(sd, ob, true);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 4a88b75cf25..8819496c168 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -1107,10 +1107,10 @@ static void sculpt_undo_store_coords(Object *ob, SculptUndoNode *unode)
BKE_pbvh_vertex_iter_begin (ss->pbvh, unode->node, vd, PBVH_ITER_ALL) {
copy_v3_v3(unode->co[vd.i], vd.co);
if (vd.no) {
- copy_v3_v3_short(unode->no[vd.i], vd.no);
+ copy_v3_v3(unode->no[vd.i], vd.no);
}
else {
- normal_float_to_short_v3(unode->no[vd.i], vd.fno);
+ copy_v3_v3(unode->no[vd.i], vd.fno);
}
if (ss->deform_modifiers_active) {
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index f68446b1cae..184d715a347 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -642,6 +642,10 @@ static int actkeys_paste_exec(bContext *C, wmOperator *op)
}
}
+ /* Grease Pencil needs extra update to refresh the added keyframes. */
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
+ }
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index 4463856f40a..ba96ac52f1f 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -36,6 +36,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_lib_remap.h"
#include "BKE_nla.h"
#include "BKE_screen.h"
@@ -814,20 +815,15 @@ static void action_refresh(const bContext *C, ScrArea *area)
/* XXX re-sizing y-extents of tot should go here? */
}
-static void action_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void action_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceAction *sact = (SpaceAction *)slink;
- if ((ID *)sact->action == old_id) {
- sact->action = (bAction *)new_id;
- }
-
- if ((ID *)sact->ads.filter_grp == old_id) {
- sact->ads.filter_grp = (Collection *)new_id;
- }
- if ((ID *)sact->ads.source == old_id) {
- sact->ads.source = new_id;
- }
+ BKE_id_remapper_apply(mappings, (ID **)&sact->action, ID_REMAP_APPLY_DEFAULT);
+ BKE_id_remapper_apply(mappings, (ID **)&sact->ads.filter_grp, ID_REMAP_APPLY_DEFAULT);
+ BKE_id_remapper_apply(mappings, &sact->ads.source, ID_REMAP_APPLY_DEFAULT);
}
/**
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index 035bc7e297d..f8adba30547 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -72,7 +72,7 @@
void ED_spacetypes_init(void)
{
- /* UI unit is a variable, may be used in some space type inits. */
+ /* UI unit is a variable, may be used in some space type initialization. */
U.widget_unit = 20;
/* Create space types. */
@@ -248,15 +248,16 @@ void *ED_region_draw_cb_activate(ARegionType *art,
return rdc;
}
-void ED_region_draw_cb_exit(ARegionType *art, void *handle)
+bool ED_region_draw_cb_exit(ARegionType *art, void *handle)
{
LISTBASE_FOREACH (RegionDrawCB *, rdc, &art->drawcalls) {
if (rdc == (RegionDrawCB *)handle) {
BLI_remlink(&art->drawcalls, rdc);
MEM_freeN(rdc);
- return;
+ return true;
}
}
+ return false;
}
static void ed_region_draw_cb_draw(const bContext *C, ARegion *region, ARegionType *art, int type)
diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c
index 554edf680be..5dd7c3d240e 100644
--- a/source/blender/editors/space_buttons/buttons_texture.c
+++ b/source/blender/editors/space_buttons/buttons_texture.c
@@ -155,10 +155,10 @@ static void buttons_texture_users_find_nodetree(ListBase *users,
for (node = ntree->nodes.first; node; node = node->next) {
if (node->typeinfo->nclass == NODE_CLASS_TEXTURE) {
PointerRNA ptr;
- /* PropertyRNA *prop; */ /* UNUSED */
+ // PropertyRNA *prop; /* UNUSED */
RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr);
- /* prop = RNA_struct_find_property(&ptr, "texture"); */ /* UNUSED */
+ // prop = RNA_struct_find_property(&ptr, "texture"); /* UNUSED */
buttons_texture_user_node_add(
users, id, ntree, node, category, RNA_struct_ui_icon(ptr.type), node->name);
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 007a9105c76..cf1e7788ff8 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -32,6 +32,7 @@
#include "BKE_context.h"
#include "BKE_gpencil_modifier.h" /* Types for registering panels. */
+#include "BKE_lib_remap.h"
#include "BKE_modifier.h"
#include "BKE_screen.h"
#include "BKE_shader_fx.h"
@@ -860,54 +861,53 @@ static void buttons_area_listener(const wmSpaceTypeListenerParams *params)
}
}
-static void buttons_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void buttons_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceProperties *sbuts = (SpaceProperties *)slink;
- if (sbuts->pinid == old_id) {
- sbuts->pinid = new_id;
- if (new_id == NULL) {
- sbuts->flag &= ~SB_PIN_CONTEXT;
- }
+ if (BKE_id_remapper_apply(mappings, &sbuts->pinid, ID_REMAP_APPLY_DEFAULT) ==
+ ID_REMAP_RESULT_SOURCE_UNASSIGNED) {
+ sbuts->flag &= ~SB_PIN_CONTEXT;
}
if (sbuts->path) {
ButsContextPath *path = sbuts->path;
+ for (int i = 0; i < path->len; i++) {
+ switch (BKE_id_remapper_apply(mappings, &path->ptr[i].owner_id, ID_REMAP_APPLY_DEFAULT)) {
+ case ID_REMAP_RESULT_SOURCE_UNASSIGNED: {
+ if (i == 0) {
+ MEM_SAFE_FREE(sbuts->path);
+ }
+ else {
+ memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
+ path->len = i;
+ }
+ break;
+ }
+ case ID_REMAP_RESULT_SOURCE_REMAPPED: {
+ RNA_id_pointer_create(path->ptr[i].owner_id, &path->ptr[i]);
+ /* There is no easy way to check/make path downwards valid, just nullify it.
+ * Next redraw will rebuild this anyway. */
+ i++;
+ memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
+ path->len = i;
+ break;
+ }
- int i;
- for (i = 0; i < path->len; i++) {
- if (path->ptr[i].owner_id == old_id) {
- break;
- }
- }
-
- if (i == path->len) {
- /* pass */
- }
- else if (new_id == NULL) {
- if (i == 0) {
- MEM_SAFE_FREE(sbuts->path);
- }
- else {
- memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
- path->len = i;
+ case ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE:
+ case ID_REMAP_RESULT_SOURCE_UNAVAILABLE: {
+ /* Nothing to do. */
+ break;
+ }
}
}
- else {
- RNA_id_pointer_create(new_id, &path->ptr[i]);
- /* There is no easy way to check/make path downwards valid, just nullify it.
- * Next redraw will rebuild this anyway. */
- i++;
- memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
- path->len = i;
- }
}
if (sbuts->texuser) {
ButsContextTexture *ct = sbuts->texuser;
- if ((ID *)ct->texture == old_id) {
- ct->texture = (Tex *)new_id;
- }
+ BKE_id_remapper_apply(mappings, (ID **)&ct->texture, ID_REMAP_APPLY_DEFAULT);
BLI_freelistN(&ct->users);
ct->user = NULL;
}
diff --git a/source/blender/editors/space_clip/CMakeLists.txt b/source/blender/editors/space_clip/CMakeLists.txt
index 8c7f59d61dd..db881dafa6b 100644
--- a/source/blender/editors/space_clip/CMakeLists.txt
+++ b/source/blender/editors/space_clip/CMakeLists.txt
@@ -31,6 +31,9 @@ set(INC
../../windowmanager
../../../../intern/glew-mx
../../../../intern/guardedalloc
+
+ # dna_type_offsets.h
+ ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern
)
set(SRC
@@ -69,4 +72,8 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+
blender_add_lib(bf_editor_space_clip "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+# Needed so we can use dna_type_offsets.h for defaults initialization.
+add_dependencies(bf_editor_space_clip bf_dna)
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index 5a999b1fad7..d22e4864ecf 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -34,6 +34,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_defaults.h"
#include "DNA_mask_types.h"
#include "BLI_fileops.h"
@@ -646,7 +647,7 @@ void ED_space_clip_set_mask(bContext *C, SpaceClip *sc, Mask *mask)
* \{ */
typedef struct PrefetchJob {
- /* Clip into which cache the frames will be prefetched into. */
+ /** Clip into which cache the frames will be pre-fetched into. */
MovieClip *clip;
/* Local copy of the clip which is used to decouple reading in a way which does not require
@@ -686,7 +687,7 @@ static bool check_prefetch_break(void)
static uchar *prefetch_read_file_to_memory(
MovieClip *clip, int current_frame, short render_size, short render_flag, size_t *r_size)
{
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
user.framenr = current_frame;
user.render_size = render_size;
user.render_flag = render_flag;
@@ -733,7 +734,7 @@ static int prefetch_find_uncached_frame(MovieClip *clip,
short direction)
{
int current_frame;
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
user.render_size = render_size;
user.render_flag = render_flag;
@@ -833,7 +834,7 @@ static void prefetch_task_func(TaskPool *__restrict pool, void *task_data)
while ((mem = prefetch_thread_next_frame(queue, clip, &size, &current_frame))) {
ImBuf *ibuf;
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
int flag = IB_rect | IB_multilayer | IB_alphamode_detect | IB_metadata;
int result;
char *colorspace_name = NULL;
@@ -915,7 +916,7 @@ static bool prefetch_movie_frame(MovieClip *clip,
short render_flag,
short *stop)
{
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
if (check_prefetch_break() || *stop) {
return false;
diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h
index 20cc6e3da15..15f905f3157 100644
--- a/source/blender/editors/space_clip/clip_intern.h
+++ b/source/blender/editors/space_clip/clip_intern.h
@@ -184,7 +184,7 @@ void clip_delete_plane_track(struct bContext *C,
* Calculate space clip offset to be centered at the given point.
*/
void clip_view_offset_for_center_to_point(
- SpaceClip *sc, const float x, const float y, float *r_offset_x, float *r_offset_y);
+ SpaceClip *sc, float x, float y, float *r_offset_x, float *r_offset_y);
void clip_view_center_to_point(SpaceClip *sc, float x, float y);
bool clip_view_calculate_view_selection(
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index 0aa7e35aed6..03b6d8c7381 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -33,6 +33,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_defaults.h"
#include "DNA_scene_types.h" /* min/max frames */
#include "DNA_userdef_types.h"
@@ -1321,7 +1322,7 @@ static uchar *proxy_thread_next_frame(ProxyQueue *queue,
BLI_spin_lock(&queue->spin);
if (!*queue->stop && queue->cfra <= queue->efra) {
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
char name[FILE_MAX];
size_t size;
int file;
@@ -1559,7 +1560,8 @@ static int clip_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
clip->proxy.build_size_flag,
clip->proxy.quality,
true,
- NULL);
+ NULL,
+ false);
}
WM_jobs_customdata_set(wm_job, pj, proxy_freejob);
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index 91083fa9682..da1d2dea653 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -24,6 +24,8 @@
#include <stdio.h>
#include <string.h>
+#include "DNA_defaults.h"
+
#include "DNA_mask_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_scene_types.h"
@@ -37,6 +39,7 @@
#include "BKE_context.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_remap.h"
#include "BKE_movieclip.h"
#include "BKE_screen.h"
#include "BKE_tracking.h"
@@ -239,14 +242,7 @@ static SpaceLink *clip_create(const ScrArea *area, const Scene *scene)
ARegion *region;
SpaceClip *sc;
- sc = MEM_callocN(sizeof(SpaceClip), "initclip");
- sc->spacetype = SPACE_CLIP;
- sc->flag = SC_SHOW_MARKER_PATTERN | SC_SHOW_TRACK_PATH | SC_SHOW_GRAPH_TRACKS_MOTION |
- SC_SHOW_GRAPH_FRAMES | SC_SHOW_ANNOTATION;
- sc->zoom = 1.0f;
- sc->path_length = 20;
- sc->scopes.track_preview_height = 120;
- sc->around = V3D_AROUND_CENTER_MEDIAN;
+ sc = DNA_struct_default_alloc(SpaceClip);
/* header */
region = MEM_callocN(sizeof(ARegion), "header for clip");
@@ -1079,6 +1075,9 @@ static void graph_region_draw(const bContext *C, ARegion *region)
/* time-scrubbing */
ED_time_scrub_draw(region, scene, sc->flag & SC_SHOW_SECONDS, true);
+ /* current frame indicator */
+ ED_time_scrub_draw_current_frame(region, scene, sc->flag & SC_SHOW_SECONDS);
+
/* scrollers */
UI_view2d_scrollers_draw(v2d, NULL);
@@ -1126,6 +1125,9 @@ static void dopesheet_region_draw(const bContext *C, ARegion *region)
/* time-scrubbing */
ED_time_scrub_draw(region, scene, sc->flag & SC_SHOW_SECONDS, true);
+ /* current frame indicator */
+ ED_time_scrub_draw_current_frame(region, scene, sc->flag & SC_SHOW_SECONDS);
+
/* scrollers */
UI_view2d_scrollers_draw(v2d, NULL);
}
@@ -1316,23 +1318,18 @@ static void clip_properties_region_listener(const wmRegionListenerParams *params
/********************* registration ********************/
-static void clip_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void clip_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceClip *sclip = (SpaceClip *)slink;
- if (!ELEM(GS(old_id->name), ID_MC, ID_MSK)) {
+ if (!BKE_id_remapper_has_mapping_for(mappings, FILTER_ID_MC | FILTER_ID_MSK)) {
return;
}
- if ((ID *)sclip->clip == old_id) {
- sclip->clip = (MovieClip *)new_id;
- id_us_ensure_real(new_id);
- }
-
- if ((ID *)sclip->mask_info.mask == old_id) {
- sclip->mask_info.mask = (Mask *)new_id;
- id_us_ensure_real(new_id);
- }
+ BKE_id_remapper_apply(mappings, (ID **)&sclip->clip, ID_REMAP_APPLY_ENSURE_REAL);
+ BKE_id_remapper_apply(mappings, (ID **)&sclip->mask_info.mask, ID_REMAP_APPLY_ENSURE_REAL);
}
void ED_spacetype_clip(void)
diff --git a/source/blender/editors/space_file/CMakeLists.txt b/source/blender/editors/space_file/CMakeLists.txt
index 1651269869e..cbeb2e6f529 100644
--- a/source/blender/editors/space_file/CMakeLists.txt
+++ b/source/blender/editors/space_file/CMakeLists.txt
@@ -16,8 +16,8 @@
# ***** END GPL LICENSE BLOCK *****
set(INC
- ../include
../asset
+ ../include
../../blenfont
../../blenkernel
../../blenlib
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..4107669630f 100644
--- a/source/blender/editors/space_file/asset_catalog_tree_view.cc
+++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc
@@ -325,7 +325,7 @@ void AssetCatalogTreeViewItem::build_context_menu(bContext &C, uiLayout &column)
/* Doesn't actually exist right now, but could be defined in Python. Reason that this isn't done
* in Python yet is that catalogs are not exposed in BPY, and we'd somehow pass the clicked on
- * catalog to the menu draw callback (via context probably).*/
+ * catalog to the menu draw callback (via context probably). */
MenuType *mt = WM_menutype_find("ASSETBROWSER_MT_catalog_context_menu", true);
if (!mt) {
return;
@@ -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_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 44e9735866d..14c786e5dea 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -240,6 +240,7 @@ static void file_draw_string(int sx,
UI_fontstyle_draw(&fs,
&rect,
fname,
+ sizeof(fname),
col,
&(struct uiFontStyleDraw_Params){
.align = align,
@@ -289,12 +290,12 @@ static void file_draw_string_multiline(int sx,
UI_fontstyle_draw_ex(&style->widget,
&rect,
string,
+ len,
text_col,
&(struct uiFontStyleDraw_Params){
.align = UI_STYLE_TEXT_LEFT,
.word_wrap = true,
},
- len,
NULL,
NULL,
&result);
@@ -402,19 +403,19 @@ static void file_draw_preview(const SpaceFile *sfile,
}
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- immDrawPixelsTexScaled(&state,
- (float)xco,
- (float)yco,
- imb->x,
- imb->y,
- GPU_RGBA8,
- true,
- imb->rect,
- scale,
- scale,
- 1.0f,
- 1.0f,
- col);
+ immDrawPixelsTexTiled_scaling(&state,
+ (float)xco,
+ (float)yco,
+ imb->x,
+ imb->y,
+ GPU_RGBA8,
+ true,
+ imb->rect,
+ scale,
+ scale,
+ 1.0f,
+ 1.0f,
+ col);
GPU_blend(GPU_BLEND_ALPHA);
@@ -905,7 +906,8 @@ void file_draw_list(const bContext *C, ARegion *region)
* since it's filelist_file_cache_block() and filelist_cache_previews_update()
* which controls previews task. */
{
- const bool previews_running = filelist_cache_previews_running(files);
+ const bool previews_running = filelist_cache_previews_running(files) &&
+ !filelist_cache_previews_done(files);
// printf("%s: preview task: %d\n", __func__, previews_running);
if (previews_running && !sfile->previews_timer) {
sfile->previews_timer = WM_event_add_timer_notifier(
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index 3fe48157a09..bd55e6f78ab 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -34,11 +34,11 @@ extern "C" {
struct ARegion;
struct ARegionType;
struct AssetLibrary;
-struct FileSelectParams;
struct FileAssetSelectParams;
+struct FileSelectParams;
struct SpaceFile;
-struct uiLayout;
struct View2D;
+struct uiLayout;
/* file_draw.c */
@@ -128,7 +128,7 @@ void fileselect_refresh_params(struct SpaceFile *sfile);
/**
* Sets #FileSelectParams.file (name of selected file)
*/
-void fileselect_file_set(SpaceFile *sfile, const int index);
+void fileselect_file_set(SpaceFile *sfile, int index);
bool file_attribute_column_type_enabled(const FileSelectParams *params,
FileAttributeColumnType column);
/**
@@ -204,7 +204,7 @@ void file_tools_region_panels_register(struct ARegionType *art);
/* file_utils.c */
-void file_tile_boundbox(const ARegion *region, FileLayout *layout, const int file, rcti *r_bounds);
+void file_tile_boundbox(const ARegion *region, FileLayout *layout, int file, rcti *r_bounds);
/**
* If \a path leads to a .blend, remove the trailing slash (if needed).
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 76a0e4f42e7..a1472a2c1b3 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -2463,9 +2463,10 @@ static void file_expand_directory(bContext *C)
if (params) {
if (BLI_path_is_rel(params->dir)) {
/* Use of 'default' folder here is just to avoid an error message on '//' prefix. */
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
BLI_path_abs(params->dir,
- G.relbase_valid ? BKE_main_blendfile_path(bmain) :
- BKE_appdir_folder_default_or_root());
+ (blendfile_path[0] != '\0') ? blendfile_path :
+ BKE_appdir_folder_default_or_root());
}
else if (params->dir[0] == '~') {
char tmpstr[sizeof(params->dir) - 1];
@@ -2623,7 +2624,8 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg
matches = file_select_match(sfile, params->file, matched_file);
/* *After* file_select_match! */
- BLI_filename_make_safe(params->file);
+ const bool allow_tokens = (params->flag & FILE_PATH_TOKENS_ALLOW) != 0;
+ BLI_filename_make_safe_ex(params->file, allow_tokens);
if (matches) {
/* replace the pattern (or filename that the user typed in,
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index e4ea832fe2f..2d31e8030a4 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -339,7 +339,10 @@ typedef struct FileListEntryCache {
/* Previews handling. */
TaskPool *previews_pool;
ThreadQueue *previews_done;
- size_t previews_todo_count;
+ /** Counter for previews that are not fully loaded and ready to display yet. So includes all
+ * previews either in `previews_pool` or `previews_done`. #filelist_cache_previews_update() makes
+ * previews in `preview_done` ready for display, so the counter is decremented there. */
+ int previews_todo_count;
} FileListEntryCache;
/* FileListCache.flags */
@@ -852,7 +855,8 @@ static bool is_filtered_hidden(const char *filename,
/**
* Apply the filter string as file path matching pattern.
- * \return true when the file should be in the result set, false if it should be filtered out. */
+ * \return true when the file should be in the result set, false if it should be filtered out.
+ */
static bool is_filtered_file_relpath(const FileListInternEntry *file, const FileListFilter *filter)
{
if (filter->filter_search[0] == '\0') {
@@ -1646,7 +1650,6 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdat
preview_taskdata->preview = NULL;
BLI_thread_queue_push(cache->previews_done, preview);
- atomic_fetch_and_sub_z(&cache->previews_todo_count, 1);
// printf("%s: End (%d)...\n", __func__, threadid);
}
@@ -1688,6 +1691,7 @@ static void filelist_cache_previews_clear(FileListEntryCache *cache)
}
MEM_freeN(preview);
}
+ cache->previews_todo_count = 0;
}
}
@@ -1758,7 +1762,6 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry
preview->icon_id = BKE_icon_imbuf_create(imbuf);
}
BLI_thread_queue_push(cache->previews_done, preview);
- atomic_fetch_and_sub_z(&cache->previews_todo_count, 1);
}
else {
if (entry->redirection_path) {
@@ -1779,6 +1782,7 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry
true,
filelist_cache_preview_freef);
}
+ cache->previews_todo_count++;
}
static void filelist_cache_init(FileListEntryCache *cache, size_t cache_size)
@@ -1876,8 +1880,6 @@ FileList *filelist_new(short type)
p->filelist.nbr_entries = FILEDIR_NBR_ENTRIES_UNSET;
filelist_settype(p, type);
- p->indexer = &file_indexer_noop;
-
return p;
}
@@ -1889,6 +1891,7 @@ void filelist_settype(FileList *filelist, short type)
filelist->type = type;
filelist->tags = 0;
+ filelist->indexer = &file_indexer_noop;
switch (filelist->type) {
case FILE_MAIN:
filelist->check_dir_fn = filelist_checkdir_main;
@@ -2064,7 +2067,7 @@ static char *fileentry_uiname(const char *root,
BLI_join_dirfile(abspath, sizeof(abspath), root, relpath);
name = BLF_display_name_from_file(abspath);
if (name) {
- /* Allocated string, so no need to BLI_strdup.*/
+ /* Allocated string, so no need to #BLI_strdup. */
return name;
}
}
@@ -2693,6 +2696,7 @@ bool filelist_cache_previews_update(FileList *filelist)
}
MEM_freeN(preview);
+ cache->previews_todo_count--;
}
return changed;
@@ -2714,7 +2718,7 @@ bool filelist_cache_previews_done(FileList *filelist)
}
return (cache->previews_pool == NULL) || (cache->previews_done == NULL) ||
- (cache->previews_todo_count == (size_t)BLI_thread_queue_len(cache->previews_done));
+ (cache->previews_todo_count == 0);
}
/* would recognize .blend as well */
@@ -3661,7 +3665,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib,
list_lib_options |= LIST_LIB_RECURSIVE;
}
/* Only load assets when browsing an asset library. For normal file browsing we return all
- * entries. `FLF_ASSETS_ONLY` filter can be enabled/disabled by the user.*/
+ * entries. `FLF_ASSETS_ONLY` filter can be enabled/disabled by the user. */
if (filelist->asset_library_ref) {
list_lib_options |= LIST_LIB_ASSETS_ONLY;
}
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index 0119a9b4f52..696986d4660 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -62,16 +62,16 @@ void folder_history_list_ensure_for_active_browse_mode(struct SpaceFile *sfile);
void folder_history_list_free(struct SpaceFile *sfile);
struct ListBase folder_history_list_duplicate(struct ListBase *listbase);
-void filelist_setsorting(struct FileList *filelist, const short sort, bool invert_sort);
+void filelist_setsorting(struct FileList *filelist, short sort, bool invert_sort);
void filelist_sort(struct FileList *filelist);
void filelist_setfilter_options(struct FileList *filelist,
- const bool do_filter,
- const bool hide_dot,
- const bool hide_parent,
- const uint64_t filter,
- const uint64_t filter_id,
- const bool filter_assets_only,
+ bool do_filter,
+ bool hide_dot,
+ bool hide_parent,
+ uint64_t filter,
+ uint64_t filter_id,
+ bool filter_assets_only,
const char *filter_glob,
const char *filter_search);
/**
@@ -98,19 +98,19 @@ void filelist_setlibrary(struct FileList *filelist,
void filelist_init_icons(void);
void filelist_free_icons(void);
-struct ImBuf *filelist_getimage(struct FileList *filelist, const int index);
+struct ImBuf *filelist_getimage(struct FileList *filelist, int index);
struct ImBuf *filelist_file_getimage(const FileDirEntry *file);
struct ImBuf *filelist_geticon_image_ex(const FileDirEntry *file);
-struct ImBuf *filelist_geticon_image(struct FileList *filelist, const int index);
-int filelist_geticon(struct FileList *filelist, const int index, const bool is_main);
+struct ImBuf *filelist_geticon_image(struct FileList *filelist, int index);
+int filelist_geticon(struct FileList *filelist, int index, bool is_main);
struct FileList *filelist_new(short type);
void filelist_settype(struct FileList *filelist, short type);
void filelist_clear(struct FileList *filelist);
void filelist_clear_ex(struct FileList *filelist,
- const bool do_asset_library,
- const bool do_cache,
- const bool do_selection);
+ bool do_asset_library,
+ bool do_cache,
+ bool do_selection);
/**
* A "smarter" version of #filelist_clear() that calls partial clearing based on the filelist
* force-reset flags.
@@ -156,7 +156,7 @@ void filelist_file_cache_slidingwindow_set(struct FileList *filelist, size_t win
/**
* Load in cache all entries "around" given index (as much as block cache may hold).
*/
-bool filelist_file_cache_block(struct FileList *filelist, const int index);
+bool filelist_file_cache_block(struct FileList *filelist, int index);
bool filelist_needs_force_reset(struct FileList *filelist);
void filelist_tag_force_reset(struct FileList *filelist);
@@ -171,7 +171,7 @@ unsigned int filelist_entry_select_set(const struct FileList *filelist,
unsigned int flag,
FileCheckType check);
void filelist_entry_select_index_set(struct FileList *filelist,
- const int index,
+ int index,
FileSelType select,
unsigned int flag,
FileCheckType check);
@@ -184,9 +184,9 @@ unsigned int filelist_entry_select_get(struct FileList *filelist,
struct FileDirEntry *entry,
FileCheckType check);
unsigned int filelist_entry_select_index_get(struct FileList *filelist,
- const int index,
+ int index,
FileCheckType check);
-bool filelist_entry_is_selected(struct FileList *filelist, const int index);
+bool filelist_entry_is_selected(struct FileList *filelist, int index);
/**
* Set selection of the '..' parent entry, but only if it's actually visible.
*/
@@ -195,7 +195,7 @@ void filelist_entry_parent_select_set(struct FileList *filelist,
unsigned int flag,
FileCheckType check);
-void filelist_setrecursion(struct FileList *filelist, const int recursion_level);
+void filelist_setrecursion(struct FileList *filelist, int recursion_level);
struct AssetLibrary *filelist_asset_library(struct FileList *filelist);
@@ -213,7 +213,7 @@ void filelist_readjob_stop(struct FileList *filelist, struct wmWindowManager *wm
int filelist_readjob_running(struct FileList *filelist, struct wmWindowManager *wm);
bool filelist_cache_previews_update(struct FileList *filelist);
-void filelist_cache_previews_set(struct FileList *filelist, const bool use_previews);
+void filelist_cache_previews_set(struct FileList *filelist, bool use_previews);
bool filelist_cache_previews_running(struct FileList *filelist);
bool filelist_cache_previews_done(struct FileList *filelist);
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index e3ac5840da3..f9783d1b19f 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -275,6 +275,9 @@ static FileSelectParams *fileselect_ensure_updated_file_params(SpaceFile *sfile)
if ((prop = RNA_struct_find_property(op->ptr, "filter_usd"))) {
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_USD : 0;
}
+ if ((prop = RNA_struct_find_property(op->ptr, "filter_obj"))) {
+ params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_OBJECT_IO : 0;
+ }
if ((prop = RNA_struct_find_property(op->ptr, "filter_volume"))) {
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_VOLUME : 0;
}
@@ -318,6 +321,10 @@ static FileSelectParams *fileselect_ensure_updated_file_params(SpaceFile *sfile)
params->flag |= RNA_boolean_get(op->ptr, "active_collection") ? FILE_ACTIVE_COLLECTION : 0;
}
+ if ((prop = RNA_struct_find_property(op->ptr, "allow_path_tokens"))) {
+ params->flag |= RNA_property_boolean_get(op->ptr, prop) ? FILE_PATH_TOKENS_ALLOW : 0;
+ }
+
if ((prop = RNA_struct_find_property(op->ptr, "display_type"))) {
params->display = RNA_property_enum_get(op->ptr, prop);
}
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index 97f22ca7d89..14f596ae7bf 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -185,8 +185,8 @@ static void fsmenu_xdg_user_dirs_free(GHash *xdg_map)
/**
* Add fsmenu entry for system folders on linux.
- * - Check if a path is stored in the GHash generated from user-dirs.dirs
- * - If not, check for a default path in $HOME
+ * - Check if a path is stored in the #GHash generated from `user-dirs.dirs`.
+ * - If not, check for a default path in `$HOME`.
*
* \param key: Use `user-dirs.dirs` format "XDG_EXAMPLE_DIR"
* \param default_path: Directory name to check in $HOME, also used for the menu entry name.
diff --git a/source/blender/editors/space_file/fsmenu.h b/source/blender/editors/space_file/fsmenu.h
index 6296314d40a..0915c9a5a2f 100644
--- a/source/blender/editors/space_file/fsmenu.h
+++ b/source/blender/editors/space_file/fsmenu.h
@@ -42,7 +42,7 @@ void fsmenu_insert_entry(struct FSMenu *fsmenu,
const char *path,
const char *name,
int icon,
- const enum FSMenuInsert flag);
+ enum FSMenuInsert flag);
/** Refresh 'valid' status of given menu entry */
void fsmenu_entry_refresh_valid(struct FSMenuEntry *fsentry);
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index bbf3c6f768c..470128f61bd 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -33,6 +33,7 @@
#include "BKE_appdir.h"
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_lib_remap.h"
#include "BKE_main.h"
#include "BKE_screen.h"
@@ -57,14 +58,11 @@
#include "UI_view2d.h"
#include "GPU_framebuffer.h"
+#include "file_indexer.h"
#include "file_intern.h" /* own include */
#include "filelist.h"
#include "fsmenu.h"
-/* Enable asset indexing. Currently disabled as ID properties aren't indexed yet and is needed for
- * object snapping. See {D12990}. */
-//#define SPACE_FILE_ENABLE_ASSET_INDEXING
-
static ARegion *file_ui_region_ensure(ScrArea *area, ARegion *region_prev)
{
ARegion *region;
@@ -359,11 +357,11 @@ static void file_refresh(const bContext *C, ScrArea *area)
sfile->files, asset_params->asset_catalog_visibility, &asset_params->catalog_id);
}
-#ifdef SPACE_FILE_ENABLE_ASSET_INDEXING
if (ED_fileselect_is_asset_browser(sfile)) {
- filelist_setindexer(sfile->files, &file_indexer_asset);
+ const bool use_asset_indexer = !USER_EXPERIMENTAL_TEST(&U, no_asset_indexing);
+ filelist_setindexer(sfile->files,
+ use_asset_indexer ? &file_indexer_asset : &file_indexer_noop);
}
-#endif
/* Update the active indices of bookmarks & co. */
sfile->systemnr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_SYSTEM, params->dir);
@@ -992,7 +990,7 @@ static int /*eContextResult*/ file_context(const bContext *C,
return CTX_RESULT_MEMBER_NOT_FOUND;
}
-static void file_id_remap(ScrArea *area, SpaceLink *sl, ID *UNUSED(old_id), ID *UNUSED(new_id))
+static void file_id_remap(ScrArea *area, SpaceLink *sl, const struct IDRemapper *UNUSED(mappings))
{
SpaceFile *sfile = (SpaceFile *)sl;
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index 2afee277847..9675901ead3 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -2353,6 +2353,103 @@ void GRAPH_OT_snap(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Equalize Handles Operator
+ * \{ */
+
+/* Defines for equalize handles tool. */
+static const EnumPropertyItem prop_graphkeys_equalize_handles_sides[] = {
+ {GRAPHKEYS_EQUALIZE_LEFT, "LEFT", 0, "Left", "Equalize selected keyframes' left handles"},
+ {GRAPHKEYS_EQUALIZE_RIGHT, "RIGHT", 0, "Right", "Equalize selected keyframes' right handles"},
+ {GRAPHKEYS_EQUALIZE_BOTH, "BOTH", 0, "Both", "Equalize both of a keyframe's handles"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+/* ------------------- */
+
+/* Equalize selected keyframes' bezier handles. */
+static void equalize_graph_keys(bAnimContext *ac, int mode, float handle_length, bool flatten)
+{
+ /* Filter data. */
+ const int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_NODUPLIS);
+ ListBase anim_data = {NULL, NULL};
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+
+ /* Equalize keyframes. */
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
+ ANIM_fcurve_equalize_keyframes_loop(ale->key_data, mode, handle_length, flatten);
+ ale->update |= ANIM_UPDATE_DEFAULT;
+ }
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
+}
+
+static int graphkeys_equalize_handles_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+
+ /* Get editor data. */
+ if (ANIM_animdata_get_context(C, &ac) == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Get equalize mode. */
+ int mode = RNA_enum_get(op->ptr, "side");
+ float handle_length = RNA_float_get(op->ptr, "handle_length");
+ bool flatten = RNA_boolean_get(op->ptr, "flatten");
+
+ /* Equalize graph keyframes. */
+ equalize_graph_keys(&ac, mode, handle_length, flatten);
+
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GRAPH_OT_equalize_handles(wmOperatorType *ot)
+{
+ /* Identifiers */
+ ot->name = "Equalize Handles";
+ ot->idname = "GRAPH_OT_equalize_handles";
+ ot->description =
+ "Ensure selected keyframes' handles have equal length, optionally making them horizontal";
+
+ /* API callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = graphkeys_equalize_handles_exec;
+ ot->poll = graphop_editable_keyframes_poll;
+
+ /* Flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* Properties */
+ ot->prop = RNA_def_enum(ot->srna,
+ "side",
+ prop_graphkeys_equalize_handles_sides,
+ 0,
+ "Side",
+ "Side of the keyframes' bezier handles to affect");
+ RNA_def_float(ot->srna,
+ "handle_length",
+ 5.0f,
+ 0.1f,
+ FLT_MAX,
+ "Handle Length",
+ "Length to make selected keyframes' bezier handles",
+ 1.0f,
+ 50.0f);
+ RNA_def_boolean(
+ ot->srna,
+ "flatten",
+ false,
+ "Flatten",
+ "Make the values of the selected keyframes' handles the same as their respective keyframes");
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Mirror Keyframes Operator
* \{ */
diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h
index 4db1eb5214e..a59fb63dd22 100644
--- a/source/blender/editors/space_graph/graph_intern.h
+++ b/source/blender/editors/space_graph/graph_intern.h
@@ -109,8 +109,8 @@ void get_graph_keyframe_extents(struct bAnimContext *ac,
float *xmax,
float *ymin,
float *ymax,
- const bool do_sel_only,
- const bool include_handles);
+ bool do_sel_only,
+ bool include_handles);
void GRAPH_OT_previewrange_set(struct wmOperatorType *ot);
void GRAPH_OT_view_all(struct wmOperatorType *ot);
@@ -126,6 +126,8 @@ void GRAPH_OT_paste(struct wmOperatorType *ot);
void GRAPH_OT_duplicate(struct wmOperatorType *ot);
void GRAPH_OT_delete(struct wmOperatorType *ot);
void GRAPH_OT_clean(struct wmOperatorType *ot);
+void GRAPH_OT_blend_to_neighbor(struct wmOperatorType *ot);
+void GRAPH_OT_breakdown(struct wmOperatorType *ot);
void GRAPH_OT_decimate(struct wmOperatorType *ot);
void GRAPH_OT_sample(struct wmOperatorType *ot);
void GRAPH_OT_bake(struct wmOperatorType *ot);
@@ -142,6 +144,7 @@ void GRAPH_OT_easing_type(struct wmOperatorType *ot);
void GRAPH_OT_frame_jump(struct wmOperatorType *ot);
void GRAPH_OT_snap_cursor_value(struct wmOperatorType *ot);
void GRAPH_OT_snap(struct wmOperatorType *ot);
+void GRAPH_OT_equalize_handles(struct wmOperatorType *ot);
void GRAPH_OT_mirror(struct wmOperatorType *ot);
/* defines for snap keyframes
@@ -156,6 +159,15 @@ enum eGraphKeys_Snap_Mode {
GRAPHKEYS_SNAP_VALUE,
};
+/* Defines for equalize keyframe handles.
+ * NOTE: Keep in sync with eEditKeyframes_Equalize (in ED_keyframes_edit.h).
+ */
+enum eGraphKeys_Equalize_Mode {
+ GRAPHKEYS_EQUALIZE_LEFT = 1,
+ GRAPHKEYS_EQUALIZE_RIGHT,
+ GRAPHKEYS_EQUALIZE_BOTH,
+};
+
/* defines for mirror keyframes
* NOTE: keep in sync with eEditKeyframes_Mirror (in ED_keyframes_edit.h)
*/
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index ecafc75fc06..7606dcc60cf 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -456,6 +456,7 @@ void graphedit_operatortypes(void)
/* editing */
WM_operatortype_append(GRAPH_OT_snap);
+ WM_operatortype_append(GRAPH_OT_equalize_handles);
WM_operatortype_append(GRAPH_OT_mirror);
WM_operatortype_append(GRAPH_OT_frame_jump);
WM_operatortype_append(GRAPH_OT_snap_cursor_value);
@@ -470,6 +471,8 @@ void graphedit_operatortypes(void)
WM_operatortype_append(GRAPH_OT_smooth);
WM_operatortype_append(GRAPH_OT_clean);
WM_operatortype_append(GRAPH_OT_decimate);
+ WM_operatortype_append(GRAPH_OT_blend_to_neighbor);
+ WM_operatortype_append(GRAPH_OT_breakdown);
WM_operatortype_append(GRAPH_OT_euler_filter);
WM_operatortype_append(GRAPH_OT_delete);
WM_operatortype_append(GRAPH_OT_duplicate);
diff --git a/source/blender/editors/space_graph/graph_slider_ops.c b/source/blender/editors/space_graph/graph_slider_ops.c
index 0bb5e8b8d9c..4b8c983a761 100644
--- a/source/blender/editors/space_graph/graph_slider_ops.c
+++ b/source/blender/editors/space_graph/graph_slider_ops.c
@@ -99,8 +99,10 @@ typedef struct tBeztCopyData {
/** \name Utility Functions
* \{ */
-/* Construct a list with the original bezt arrays so we can restore them during modal operation.
- * The data is stored on the struct that is passed.*/
+/**
+ * Construct a list with the original bezt arrays so we can restore them during modal operation.
+ * The data is stored on the struct that is passed.
+ */
static void store_original_bezt_arrays(tGraphSliderOp *gso)
{
ListBase anim_data = {NULL, NULL};
@@ -313,8 +315,7 @@ static int graph_slider_invoke(bContext *C, wmOperator *op, const wmEvent *event
ED_slider_init(gso->slider, event);
if (gso->bezt_arr_list.first == NULL) {
- WM_report(RPT_WARNING,
- "Fcurve Slider: Can't work on baked channels. Unbake them and try again.");
+ WM_report(RPT_ERROR, "Cannot find keys to operate on.");
graph_slider_exit(C, op);
return OPERATOR_CANCELLED;
}
@@ -552,3 +553,256 @@ void GRAPH_OT_decimate(wmOperatorType *ot)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Blend To Neighbor Operator
+ * \{ */
+
+static void blend_to_neighbor_graph_keys(bAnimContext *ac, float factor)
+{
+ ListBase anim_data = {NULL, NULL};
+ ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype);
+
+ bAnimListElem *ale;
+
+ /* Loop through filtered data and blend keys. */
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ FCurve *fcu = (FCurve *)ale->key_data;
+ ListBase segments = find_fcurve_segments(fcu);
+ LISTBASE_FOREACH (FCurveSegment *, segment, &segments) {
+ blend_to_neighbor_fcurve_segment(fcu, segment, factor);
+ }
+ BLI_freelistN(&segments);
+ ale->update |= ANIM_UPDATE_DEFAULT;
+ }
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
+}
+
+static void blend_to_neighbor_draw_status_header(bContext *C, tGraphSliderOp *gso)
+{
+ char status_str[UI_MAX_DRAW_STR];
+ char mode_str[32];
+ char slider_string[UI_MAX_DRAW_STR];
+
+ ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
+
+ strcpy(mode_str, TIP_("Blend To Neighbor"));
+
+ if (hasNumInput(&gso->num)) {
+ char str_ofs[NUM_STR_REP_LEN];
+
+ outputNumInput(&gso->num, str_ofs, &gso->scene->unit);
+
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
+ }
+ else {
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
+ }
+
+ ED_workspace_status_text(C, status_str);
+}
+
+static void blend_to_neighbor_modal_update(bContext *C, wmOperator *op)
+{
+ tGraphSliderOp *gso = op->customdata;
+
+ blend_to_neighbor_draw_status_header(C, gso);
+
+ /* Reset keyframe data to the state at invoke. */
+ reset_bezts(gso);
+
+ const float factor = ED_slider_factor_get(gso->slider);
+ RNA_property_float_set(op->ptr, gso->factor_prop, factor);
+ blend_to_neighbor_graph_keys(&gso->ac, factor);
+
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+}
+
+static int blend_to_neighbor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ const int invoke_result = graph_slider_invoke(C, op, event);
+
+ if (invoke_result == OPERATOR_CANCELLED) {
+ return invoke_result;
+ }
+
+ tGraphSliderOp *gso = op->customdata;
+ gso->modal_update = blend_to_neighbor_modal_update;
+ gso->factor_prop = RNA_struct_find_property(op->ptr, "factor");
+ blend_to_neighbor_draw_status_header(C, gso);
+
+ return invoke_result;
+}
+
+static int blend_to_neighbor_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+
+ if (ANIM_animdata_get_context(C, &ac) == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ const float factor = RNA_float_get(op->ptr, "factor");
+
+ blend_to_neighbor_graph_keys(&ac, factor);
+
+ /* Set notifier that keyframes have changed. */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GRAPH_OT_blend_to_neighbor(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Blend To Neighbor";
+ ot->idname = "GRAPH_OT_blend_to_neighbor";
+ ot->description = "Blend selected keyframes to their left or right neighbor";
+
+ /* API callbacks. */
+ ot->invoke = blend_to_neighbor_invoke;
+ ot->modal = graph_slider_modal;
+ ot->exec = blend_to_neighbor_exec;
+ ot->poll = graphop_editable_keyframes_poll;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_float_factor(ot->srna,
+ "factor",
+ 1.0f / 3.0f,
+ -FLT_MAX,
+ FLT_MAX,
+ "Blend",
+ "The blend factor with 0.5 being the current frame",
+ 0.0f,
+ 1.0f);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Breakdown Operator
+ * \{ */
+
+static void breakdown_graph_keys(bAnimContext *ac, float factor)
+{
+ ListBase anim_data = {NULL, NULL};
+ ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype);
+
+ bAnimListElem *ale;
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ FCurve *fcu = (FCurve *)ale->key_data;
+ ListBase segments = find_fcurve_segments(fcu);
+ LISTBASE_FOREACH (FCurveSegment *, segment, &segments) {
+ breakdown_fcurve_segment(fcu, segment, factor);
+ }
+ BLI_freelistN(&segments);
+ ale->update |= ANIM_UPDATE_DEFAULT;
+ }
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
+}
+
+static void breakdown_draw_status_header(bContext *C, tGraphSliderOp *gso)
+{
+ char status_str[UI_MAX_DRAW_STR];
+ char mode_str[32];
+ char slider_string[UI_MAX_DRAW_STR];
+
+ ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
+
+ strcpy(mode_str, TIP_("Breakdown"));
+
+ if (hasNumInput(&gso->num)) {
+ char str_ofs[NUM_STR_REP_LEN];
+
+ outputNumInput(&gso->num, str_ofs, &gso->scene->unit);
+
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
+ }
+ else {
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
+ }
+
+ ED_workspace_status_text(C, status_str);
+}
+
+static void breakdown_modal_update(bContext *C, wmOperator *op)
+{
+ tGraphSliderOp *gso = op->customdata;
+
+ breakdown_draw_status_header(C, gso);
+
+ /* Reset keyframe data to the state at invoke. */
+ reset_bezts(gso);
+ breakdown_graph_keys(&gso->ac, ED_slider_factor_get(gso->slider));
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+}
+
+static int breakdown_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ const int invoke_result = graph_slider_invoke(C, op, event);
+
+ if (invoke_result == OPERATOR_CANCELLED) {
+ return invoke_result;
+ }
+
+ tGraphSliderOp *gso = op->customdata;
+ gso->modal_update = breakdown_modal_update;
+ breakdown_draw_status_header(C, gso);
+
+ return invoke_result;
+}
+
+static int breakdown_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+
+ if (ANIM_animdata_get_context(C, &ac) == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ const float factor = RNA_float_get(op->ptr, "factor");
+
+ breakdown_graph_keys(&ac, factor);
+
+ /* Set notifier that keyframes have changed. */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GRAPH_OT_breakdown(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Breakdown";
+ ot->idname = "GRAPH_OT_breakdown";
+ ot->description = "Move selected keyframes to an inbetween position relative to adjacent keys";
+
+ /* API callbacks. */
+ ot->invoke = breakdown_invoke;
+ ot->modal = graph_slider_modal;
+ ot->exec = breakdown_exec;
+ ot->poll = graphop_editable_keyframes_poll;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_float_factor(ot->srna,
+ "factor",
+ 1.0f / 3.0f,
+ -FLT_MAX,
+ FLT_MAX,
+ "Factor",
+ "Favor either the left or the right key",
+ 0.0f,
+ 1.0f);
+}
+
+/** \} */
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index 40c95d4f382..7d5e8836490 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -36,6 +36,7 @@
#include "BKE_context.h"
#include "BKE_fcurve.h"
+#include "BKE_lib_remap.h"
#include "BKE_screen.h"
#include "ED_anim_api.h"
@@ -796,18 +797,17 @@ static void graph_refresh(const bContext *C, ScrArea *area)
graph_refresh_fcurve_colors(C);
}
-static void graph_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void graph_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceGraph *sgraph = (SpaceGraph *)slink;
-
- if (sgraph->ads) {
- if ((ID *)sgraph->ads->filter_grp == old_id) {
- sgraph->ads->filter_grp = (Collection *)new_id;
- }
- if ((ID *)sgraph->ads->source == old_id) {
- sgraph->ads->source = new_id;
- }
+ if (!sgraph->ads) {
+ return;
}
+
+ BKE_id_remapper_apply(mappings, (ID **)&sgraph->ads->filter_grp, ID_REMAP_APPLY_DEFAULT);
+ BKE_id_remapper_apply(mappings, (ID **)&sgraph->ads->source, ID_REMAP_APPLY_DEFAULT);
}
static int graph_space_subtype_get(ScrArea *area)
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index ade5993cdb9..8858df3323f 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -591,7 +591,7 @@ float ED_space_image_zoom_level(const View2D *v2d, const int grid_dimension)
* - Default grid size on startup, which is 256x256 pixels
* - How blend factor for grid lines is set up in the fragment shader `grid_frag.glsl`. */
float zoom_factor;
- zoom_factor = (xzoom + yzoom) / 2.0f; /* Average for accuracy. */
+ zoom_factor = (xzoom + yzoom) / 2.0f; /* Average for accuracy. */
zoom_factor *= 256.0f / (powf(grid_dimension, 2));
return zoom_factor;
}
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index f9160774c41..23d07c9b45b 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -1499,6 +1499,13 @@ static void image_open_draw(bContext *UNUSED(C), wmOperator *op)
}
}
+static void image_operator_prop_allow_tokens(wmOperatorType *ot)
+{
+ PropertyRNA *prop = RNA_def_boolean(
+ ot->srna, "allow_path_tokens", true, "", "Allow the path to contain substitution tokens");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+}
+
void IMAGE_OT_open(wmOperatorType *ot)
{
/* identifiers */
@@ -1516,6 +1523,7 @@ void IMAGE_OT_open(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
+ image_operator_prop_allow_tokens(ot);
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
FILE_SPECIAL,
@@ -1767,7 +1775,13 @@ static int image_save_options_init(Main *bmain,
opts->im_format.views_format = ima->views_format;
}
- BLI_strncpy(opts->filepath, ibuf->name, sizeof(opts->filepath));
+ if (ima->source == IMA_SRC_TILED) {
+ BLI_strncpy(opts->filepath, ima->filepath, sizeof(opts->filepath));
+ BLI_path_abs(opts->filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
+ }
+ else {
+ BLI_strncpy(opts->filepath, ibuf->name, sizeof(opts->filepath));
+ }
/* sanitize all settings */
@@ -1804,14 +1818,10 @@ static int image_save_options_init(Main *bmain,
BLI_path_abs(opts->filepath, is_prev_save ? G.ima : BKE_main_blendfile_path(bmain));
}
- /* append UDIM numbering if not present */
- if (ima->source == IMA_SRC_TILED) {
- char udim[6];
- ImageTile *tile = ima->tiles.first;
- BLI_snprintf(udim, sizeof(udim), ".%d", tile->tile_number);
-
+ /* append UDIM marker if not present */
+ if (ima->source == IMA_SRC_TILED && strstr(opts->filepath, "<UDIM>") == NULL) {
int len = strlen(opts->filepath);
- STR_CONCAT(opts->filepath, len, udim);
+ STR_CONCAT(opts->filepath, len, ".<UDIM>");
}
}
@@ -2070,6 +2080,7 @@ void IMAGE_OT_save_as(wmOperatorType *ot)
"Copy",
"Create a new image file without modifying the current image in blender");
+ image_operator_prop_allow_tokens(ot);
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
FILE_SPECIAL,
@@ -2584,6 +2595,11 @@ static int image_new_exec(bContext *C, wmOperator *op)
else if (sima) {
ED_space_image_set(bmain, sima, ima, false);
}
+ else {
+ /* #BKE_image_add_generated creates one user by default, remove it if image is not linked to
+ * anything. ref. T94599. */
+ id_us_min(&ima->id);
+ }
BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_USER_NEW_IMAGE);
diff --git a/source/blender/editors/space_image/image_sequence.c b/source/blender/editors/space_image/image_sequence.c
index 87bff913ff2..84b85b396fe 100644
--- a/source/blender/editors/space_image/image_sequence.c
+++ b/source/blender/editors/space_image/image_sequence.c
@@ -115,79 +115,17 @@ static int image_cmp_frame(const void *a, const void *b)
return 0;
}
-/*
- * Checks whether the given filepath refers to a UDIM texture.
- * If yes, the range from 1001 to the highest tile is returned, otherwise 0.
- *
- * If the result is positive, the filepath will be overwritten with that of
- * the 1001 tile.
- *
- * udim_tiles may get filled even if the result ultimately is false!
- */
-static bool image_get_udim(char *filepath, ListBase *udim_tiles, int *udim_start, int *udim_range)
-{
- char filename[FILE_MAX], dirname[FILE_MAXDIR];
- BLI_split_dirfile(filepath, dirname, filename, sizeof(dirname), sizeof(filename));
-
- ushort digits;
- char base_head[FILE_MAX], base_tail[FILE_MAX];
- int id = BLI_path_sequence_decode(filename, base_head, base_tail, &digits);
-
- if (id < 1001 || id > IMA_UDIM_MAX) {
- return false;
- }
-
- bool is_udim = true;
- int min_udim = IMA_UDIM_MAX + 1;
- int max_udim = 0;
-
- struct direntry *dir;
- uint totfile = BLI_filelist_dir_contents(dirname, &dir);
- for (int i = 0; i < totfile; i++) {
- if (!(dir[i].type & S_IFREG)) {
- continue;
- }
- char head[FILE_MAX], tail[FILE_MAX];
- id = BLI_path_sequence_decode(dir[i].relname, head, tail, &digits);
-
- if (digits > 4 || !(STREQLEN(base_head, head, FILE_MAX)) ||
- !(STREQLEN(base_tail, tail, FILE_MAX))) {
- continue;
- }
-
- if (id < 1001 || id > IMA_UDIM_MAX) {
- is_udim = false;
- break;
- }
-
- BLI_addtail(udim_tiles, BLI_genericNodeN(POINTER_FROM_INT(id)));
- min_udim = min_ii(min_udim, id);
- max_udim = max_ii(max_udim, id);
- }
- BLI_filelist_free(dir, totfile);
-
- if (is_udim && min_udim <= IMA_UDIM_MAX) {
- char primary_filename[FILE_MAX];
- BLI_path_sequence_encode(primary_filename, base_head, base_tail, digits, min_udim);
- BLI_join_dirfile(filepath, FILE_MAX, dirname, primary_filename);
-
- *udim_start = min_udim;
- *udim_range = max_udim - min_udim + 1;
- return true;
- }
- return false;
-}
-
/**
* From a list of frames, compute the start (offset) and length of the sequence
- * of contiguous frames. If UDIM is detect, it will return UDIM tiles as well.
+ * of contiguous frames. If `detect_udim` is set, it will return UDIM tiles as well.
*/
static void image_detect_frame_range(ImageFrameRange *range, const bool detect_udim)
{
/* UDIM */
if (detect_udim) {
int udim_start, udim_range;
- bool result = image_get_udim(range->filepath, &range->udim_tiles, &udim_start, &udim_range);
+ bool result = BKE_image_get_tile_info(
+ range->filepath, &range->udim_tiles, &udim_start, &udim_range);
if (result) {
range->offset = udim_start;
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index dad494e6984..eb5b6104a79 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -37,6 +37,7 @@
#include "BKE_context.h"
#include "BKE_image.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_remap.h"
#include "BKE_screen.h"
#include "RNA_access.h"
@@ -297,7 +298,7 @@ static void image_refresh(const bContext *C, ScrArea *area)
ima = ED_space_image(sima);
BKE_image_user_frame_calc(ima, &sima->iuser, scene->r.cfra);
- /* check if we have to set the image from the editmesh */
+ /* Check if we have to set the image from the edit-mesh. */
if (ima && (ima->source == IMA_SRC_VIEWER && sima->mode == SI_MODE_MASK)) {
if (scene->nodetree) {
Mask *mask = ED_space_image_get_mask(sima);
@@ -983,29 +984,19 @@ static void image_header_region_listener(const wmRegionListenerParams *params)
}
}
-static void image_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void image_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceImage *simg = (SpaceImage *)slink;
- if (!ELEM(GS(old_id->name), ID_IM, ID_GD, ID_MSK)) {
+ if (!BKE_id_remapper_has_mapping_for(mappings, FILTER_ID_IM | FILTER_ID_GD | FILTER_ID_MSK)) {
return;
}
- if ((ID *)simg->image == old_id) {
- simg->image = (Image *)new_id;
- id_us_ensure_real(new_id);
- }
-
- if ((ID *)simg->gpd == old_id) {
- simg->gpd = (bGPdata *)new_id;
- id_us_min(old_id);
- id_us_plus(new_id);
- }
-
- if ((ID *)simg->mask_info.mask == old_id) {
- simg->mask_info.mask = (Mask *)new_id;
- id_us_ensure_real(new_id);
- }
+ BKE_id_remapper_apply(mappings, (ID **)&simg->image, ID_REMAP_APPLY_ENSURE_REAL);
+ BKE_id_remapper_apply(mappings, (ID **)&simg->gpd, ID_REMAP_APPLY_UPDATE_REFCOUNT);
+ BKE_id_remapper_apply(mappings, (ID **)&simg->mask_info.mask, ID_REMAP_APPLY_ENSURE_REAL);
}
/**
diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c
index 8e37e5fe9a8..2a797fd1a78 100644
--- a/source/blender/editors/space_info/info_ops.c
+++ b/source/blender/editors/space_info/info_ops.c
@@ -408,13 +408,14 @@ void FILE_OT_unpack_item(wmOperatorType *ot)
static int make_paths_relative_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
- if (!G.relbase_valid) {
+ if (blendfile_path[0] == '\0') {
BKE_report(op->reports, RPT_WARNING, "Cannot set relative paths with an unsaved blend file");
return OPERATOR_CANCELLED;
}
- BKE_bpath_relative_convert(bmain, BKE_main_blendfile_path(bmain), op->reports);
+ BKE_bpath_relative_convert(bmain, blendfile_path, op->reports);
/* redraw everything so any changed paths register */
WM_main_add_notifier(NC_WINDOW, NULL);
@@ -445,13 +446,14 @@ void FILE_OT_make_paths_relative(wmOperatorType *ot)
static int make_paths_absolute_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
- if (!G.relbase_valid) {
+ if (blendfile_path[0] == '\0') {
BKE_report(op->reports, RPT_WARNING, "Cannot set absolute paths with an unsaved blend file");
return OPERATOR_CANCELLED;
}
- BKE_bpath_absolute_convert(bmain, BKE_main_blendfile_path(bmain), op->reports);
+ BKE_bpath_absolute_convert(bmain, blendfile_path, op->reports);
/* redraw everything so any changed paths register */
WM_main_add_notifier(NC_WINDOW, NULL);
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_info/textview.h b/source/blender/editors/space_info/textview.h
index 96f537b4b97..38c073a328a 100644
--- a/source/blender/editors/space_info/textview.h
+++ b/source/blender/editors/space_info/textview.h
@@ -81,7 +81,7 @@ typedef struct TextViewContext {
* Use for selection.
*/
int textview_draw(struct TextViewContext *tvc,
- const bool do_draw,
+ bool do_draw,
const int mval_init[2],
void **r_mval_pick_item,
int *r_mval_pick_offset);
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index 12f0011b499..7dfe0e89e90 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -324,7 +324,7 @@ static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc, uin
GPU_line_smooth(true);
GPU_blend(GPU_BLEND_ALPHA);
- /* Fully opaque line on selected strips. */
+ /* Fully opaque line on selected strips. */
if (strip->flag & NLASTRIP_FLAG_SELECT) {
/* TODO: Use theme setting. */
immUniformColor3f(1.0f, 1.0f, 1.0f);
diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c
index 0771153c5f5..962b5151661 100644
--- a/source/blender/editors/space_nla/space_nla.c
+++ b/source/blender/editors/space_nla/space_nla.c
@@ -33,6 +33,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_lib_remap.h"
#include "BKE_screen.h"
#include "ED_anim_api.h"
@@ -577,18 +578,17 @@ static void nla_listener(const wmSpaceTypeListenerParams *params)
}
}
-static void nla_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void nla_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceNla *snla = (SpaceNla *)slink;
- if (snla->ads) {
- if ((ID *)snla->ads->filter_grp == old_id) {
- snla->ads->filter_grp = (Collection *)new_id;
- }
- if ((ID *)snla->ads->source == old_id) {
- snla->ads->source = new_id;
- }
+ if (snla->ads == NULL) {
+ return;
}
+ BKE_id_remapper_apply(mappings, (ID **)&snla->ads->filter_grp, ID_REMAP_APPLY_DEFAULT);
+ BKE_id_remapper_apply(mappings, (ID **)&snla->ads->source, ID_REMAP_APPLY_DEFAULT);
}
void ED_spacetype_nla(void)
diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt
index e88d61fe880..41d6388c947 100644
--- a/source/blender/editors/space_node/CMakeLists.txt
+++ b/source/blender/editors/space_node/CMakeLists.txt
@@ -39,6 +39,7 @@ set(INC
set(SRC
drawnode.cc
+ link_drag_search.cc
node_add.cc
node_context_path.cc
node_draw.cc
@@ -50,7 +51,6 @@ set(SRC
node_relationships.cc
node_select.cc
node_templates.cc
- node_toolbar.cc
node_view.cc
space_node.cc
diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc
index 87f7bfdafb0..94da7d55e5d 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"
@@ -50,7 +51,9 @@
#include "GPU_immediate.h"
#include "GPU_matrix.h"
#include "GPU_platform.h"
+#include "GPU_shader_shared.h"
#include "GPU_state.h"
+#include "GPU_uniform_buffer.h"
#include "DRW_engine.h"
@@ -76,7 +79,7 @@
#include "NOD_texture.h"
#include "node_intern.hh" /* own include */
-using blender::float2;
+namespace blender::ed::space_node {
/* Default flags for uiItemR(). Name is kept short since this is used a lot in this file. */
#define DEFAULT_FLAGS UI_ITEM_R_SPLIT_EMPTY_NAME
@@ -135,24 +138,11 @@ static void node_buts_mix_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA
static void node_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
-#if 0
- /* XXX no context access here. */
- bNode *node = (bNode*)ptr->data;
- CurveMapping *cumap = node->storage;
-
- if (cumap) {
- cumap->flag |= CUMA_DRAW_CFRA;
- if (node->custom1 < node->custom2) {
- cumap->sample[0] = (float)(CFRA - node->custom1) / (float)(node->custom2 - node->custom1);
- }
- }
-#endif
-
uiTemplateCurveMapping(layout, ptr, "curve", 's', false, false, false, false);
- uiLayout *row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "frame_start", DEFAULT_FLAGS, IFACE_("Start"), ICON_NONE);
- uiItemR(row, ptr, "frame_end", DEFAULT_FLAGS, IFACE_("End"), ICON_NONE);
+ uiLayout *col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "frame_start", DEFAULT_FLAGS, IFACE_("Start"), ICON_NONE);
+ uiItemR(col, ptr, "frame_end", DEFAULT_FLAGS, IFACE_("End"), ICON_NONE);
}
static void node_buts_colorramp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -170,6 +160,8 @@ static void node_buts_curvefloat(uiLayout *layout, bContext *UNUSED(C), PointerR
uiTemplateCurveMapping(layout, ptr, "mapping", 0, false, false, false, false);
}
+} // namespace blender::ed::space_node
+
#define SAMPLE_FLT_ISNONE FLT_MAX
/* Bad bad, 2.5 will do better? ... no it won't! */
static float _sample_col[4] = {SAMPLE_FLT_ISNONE};
@@ -183,6 +175,8 @@ void ED_node_sample_set(const float col[4])
}
}
+namespace blender::ed::space_node {
+
static void node_buts_curvecol(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
bNode *node = (bNode *)ptr->data;
@@ -228,22 +222,6 @@ static void node_buts_texture(uiLayout *layout, bContext *UNUSED(C), PointerRNA
}
}
-static void node_shader_buts_clamp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "clamp_type", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(layout, ptr, "interpolation_type", DEFAULT_FLAGS, "", ICON_NONE);
- if (!ELEM(RNA_enum_get(ptr, "interpolation_type"),
- NODE_MAP_RANGE_SMOOTHSTEP,
- NODE_MAP_RANGE_SMOOTHERSTEP)) {
- uiItemR(layout, ptr, "clamp", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-
static void node_buts_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE);
@@ -392,40 +370,6 @@ static void node_buts_image_user(uiLayout *layout,
}
}
-static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "vector_type", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_shader_buts_vector_rotate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "rotation_type", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, nullptr, 0);
-}
-
-static void node_shader_buts_vect_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_vect_transform(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "vector_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "convert_from", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(layout, ptr, "convert_to", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_attribute(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "attribute_type", DEFAULT_FLAGS, IFACE_("Type"), ICON_NONE);
- uiItemR(layout, ptr, "attribute_name", DEFAULT_FLAGS, IFACE_("Name"), ICON_NONE);
-}
-
-static void node_shader_buts_wireframe(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "use_pixel_size", DEFAULT_FLAGS, nullptr, 0);
-}
-
static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
PointerRNA imaptr = RNA_pointer_get(ptr, "image");
@@ -495,375 +439,21 @@ static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, P
uiItemR(layout, ptr, "projection", DEFAULT_FLAGS, IFACE_("Projection"), ICON_NONE);
}
-static void node_shader_buts_tex_sky(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "sky_type", DEFAULT_FLAGS, "", ICON_NONE);
-
- if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_PREETHAM) {
- uiItemR(layout, ptr, "sun_direction", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(layout, ptr, "turbidity", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_HOSEK) {
- uiItemR(layout, ptr, "sun_direction", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(layout, ptr, "turbidity", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "ground_albedo", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_NISHITA) {
- Scene *scene = CTX_data_scene(C);
- if (BKE_scene_uses_blender_eevee(scene)) {
- uiItemL(layout, TIP_("Nishita not available in Eevee"), ICON_ERROR);
- }
- uiItemR(layout, ptr, "sun_disc", DEFAULT_FLAGS, nullptr, 0);
-
- uiLayout *col;
- if (RNA_boolean_get(ptr, "sun_disc")) {
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "sun_size", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "sun_intensity", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "sun_elevation", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "sun_rotation", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiItemR(layout, ptr, "altitude", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "air_density", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "dust_density", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "ozone_density", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-
-static void node_shader_buts_tex_gradient(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "gradient_type", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_tex_magic(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "turbulence_depth", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_shader_buts_tex_brick(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "offset", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, IFACE_("Offset"), ICON_NONE);
- uiItemR(col, ptr, "offset_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "squash", DEFAULT_FLAGS, IFACE_("Squash"), ICON_NONE);
- uiItemR(col, ptr, "squash_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE);
-}
-
-static void node_shader_buts_tex_wave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "wave_type", DEFAULT_FLAGS, "", ICON_NONE);
- int type = RNA_enum_get(ptr, "wave_type");
- if (type == SHD_WAVE_BANDS) {
- uiItemR(layout, ptr, "bands_direction", DEFAULT_FLAGS, "", ICON_NONE);
- }
- else { /* SHD_WAVE_RINGS */
- uiItemR(layout, ptr, "rings_direction", DEFAULT_FLAGS, "", ICON_NONE);
- }
-
- uiItemR(layout, ptr, "wave_profile", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_tex_musgrave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "musgrave_dimensions", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(layout, ptr, "musgrave_type", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_tex_voronoi(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "voronoi_dimensions", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(layout, ptr, "feature", DEFAULT_FLAGS, "", ICON_NONE);
- int feature = RNA_enum_get(ptr, "feature");
- if (!ELEM(feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS) &&
- RNA_enum_get(ptr, "voronoi_dimensions") != 1) {
- uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, "", ICON_NONE);
- }
-}
-
-static void node_shader_buts_tex_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "noise_dimensions", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_tex_pointdensity(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
- NodeShaderTexPointDensity *shader_point_density = (NodeShaderTexPointDensity *)node->storage;
- Object *ob = (Object *)node->id;
-
- PointerRNA ob_ptr, obdata_ptr;
- RNA_id_pointer_create((ID *)ob, &ob_ptr);
- RNA_id_pointer_create(ob ? (ID *)ob->data : nullptr, &obdata_ptr);
-
- uiItemR(layout, ptr, "point_source", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "object", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (node->id && shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) {
- PointerRNA dataptr;
- RNA_id_pointer_create((ID *)node->id, &dataptr);
- uiItemPointerR(
- layout, ptr, "particle_system", &dataptr, "particle_systems", nullptr, ICON_NONE);
- }
-
- uiItemR(layout, ptr, "space", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "radius", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "interpolation", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "resolution", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) {
- uiItemR(layout, ptr, "particle_color_source", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- else {
- uiItemR(layout, ptr, "vertex_color_source", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (shader_point_density->ob_color_source == SHD_POINTDENSITY_COLOR_VERTWEIGHT) {
- if (ob_ptr.data) {
- uiItemPointerR(
- layout, ptr, "vertex_attribute_name", &ob_ptr, "vertex_groups", "", ICON_NONE);
- }
- }
- if (shader_point_density->ob_color_source == SHD_POINTDENSITY_COLOR_VERTCOL) {
- if (obdata_ptr.data) {
- uiItemPointerR(
- layout, ptr, "vertex_attribute_name", &obdata_ptr, "vertex_colors", "", ICON_NONE);
- }
- }
- }
-}
-
-static void node_shader_buts_tex_coord(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "object", DEFAULT_FLAGS, nullptr, 0);
- uiItemR(layout, ptr, "from_instancer", DEFAULT_FLAGS, nullptr, 0);
-}
-
-static void node_shader_buts_bump(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, nullptr, 0);
-}
-
-static void node_shader_buts_uvmap(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "from_instancer", DEFAULT_FLAGS, nullptr, 0);
-
- if (!RNA_boolean_get(ptr, "from_instancer")) {
- PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
-
- if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
- PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
- uiItemPointerR(layout, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE);
- }
- }
-}
-
-static void node_shader_buts_vertex_color(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
- if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
- PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
-
- if (U.experimental.use_sculpt_vertex_colors &&
- RNA_collection_length(&dataptr, "sculpt_vertex_colors")) {
- uiItemPointerR(
- layout, ptr, "layer_name", &dataptr, "sculpt_vertex_colors", "", ICON_GROUP_VCOL);
- }
- else {
- uiItemPointerR(layout, ptr, "layer_name", &dataptr, "vertex_colors", "", ICON_GROUP_VCOL);
- }
- }
- else {
- uiItemL(layout, TIP_("No mesh in active object"), ICON_ERROR);
- }
-}
-
-static void node_shader_buts_uvalongstroke(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "use_tips", DEFAULT_FLAGS, nullptr, 0);
-}
-
-static void node_shader_buts_normal_map(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", 0);
-
- if (RNA_enum_get(ptr, "space") == SHD_SPACE_TANGENT) {
- PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
-
- if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
- PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
- uiItemPointerR(layout, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE);
- }
- else {
- uiItemR(layout, ptr, "uv_map", DEFAULT_FLAGS, "", 0);
- }
- }
-}
-
static void node_shader_buts_displacement(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", 0);
}
-static void node_shader_buts_tangent(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- uiLayout *split, *row;
-
- split = uiLayoutSplit(layout, 0.0f, false);
-
- uiItemR(split, ptr, "direction_type", DEFAULT_FLAGS, "", 0);
-
- row = uiLayoutRow(split, false);
-
- if (RNA_enum_get(ptr, "direction_type") == SHD_TANGENT_UVMAP) {
- PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
-
- if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
- PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
- uiItemPointerR(row, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE);
- }
- else {
- uiItemR(row, ptr, "uv_map", DEFAULT_FLAGS, "", 0);
- }
- }
- else {
- uiItemR(row, ptr, "axis", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, 0);
- }
-}
-
static void node_shader_buts_glossy(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "distribution", DEFAULT_FLAGS, "", ICON_NONE);
}
-static void node_shader_buts_principled(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "distribution", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(layout, ptr, "subsurface_method", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_anisotropic(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "distribution", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_subsurface(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "falloff", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_toon(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "component", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_hair(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "component", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_principled_hair(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "parametrization", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_ies(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *row;
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "mode", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
-
- row = uiLayoutRow(layout, true);
-
- if (RNA_enum_get(ptr, "mode") == NODE_IES_INTERNAL) {
- uiItemR(row, ptr, "ies", DEFAULT_FLAGS, "", ICON_NONE);
- }
- else {
- uiItemR(row, ptr, "filepath", DEFAULT_FLAGS, "", ICON_NONE);
- }
-}
-
-static void node_shader_buts_script(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *row;
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "mode", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
-
- row = uiLayoutRow(layout, true);
-
- if (RNA_enum_get(ptr, "mode") == NODE_SCRIPT_INTERNAL) {
- uiItemR(row, ptr, "script", DEFAULT_FLAGS, "", ICON_NONE);
- }
- else {
- uiItemR(row, ptr, "filepath", DEFAULT_FLAGS, "", ICON_NONE);
- }
-
- uiItemO(row, "", ICON_FILE_REFRESH, "node.shader_script_update");
-}
-
-static void node_shader_buts_script_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- uiItemS(layout);
-
- node_shader_buts_script(layout, C, ptr);
-
-#if 0 /* not implemented yet */
- if (RNA_enum_get(ptr, "mode") == NODE_SCRIPT_EXTERNAL) {
- uiItemR(layout, ptr, "use_auto_update", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-#endif
-}
-
static void node_buts_output_shader(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "target", DEFAULT_FLAGS, "", ICON_NONE);
}
-static void node_buts_output_linestyle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *row, *col;
-
- col = uiLayoutColumn(layout, false);
- row = uiLayoutRow(col, true);
- uiItemR(row, ptr, "blend_type", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(col, ptr, "use_clamp", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_shader_buts_bevel(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "samples", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_shader_buts_ambient_occlusion(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "samples", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "inside", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "only_local", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_shader_buts_white_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "noise_dimensions", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_output_aov(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "name", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
/* only once called */
static void node_shader_set_butfunc(bNodeType *ntype)
{
@@ -880,9 +470,6 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_CURVE_FLOAT:
ntype->draw_buttons = node_buts_curvefloat;
break;
- case SH_NODE_MAPPING:
- ntype->draw_buttons = node_shader_buts_mapping;
- break;
case SH_NODE_VALUE:
ntype->draw_buttons = node_buts_value;
break;
@@ -895,33 +482,9 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_VALTORGB:
ntype->draw_buttons = node_buts_colorramp;
break;
- case SH_NODE_CLAMP:
- ntype->draw_buttons = node_shader_buts_clamp;
- break;
- case SH_NODE_MAP_RANGE:
- ntype->draw_buttons = node_shader_buts_map_range;
- break;
case SH_NODE_MATH:
ntype->draw_buttons = node_buts_math;
break;
- case SH_NODE_VECTOR_MATH:
- ntype->draw_buttons = node_shader_buts_vect_math;
- break;
- case SH_NODE_VECTOR_ROTATE:
- ntype->draw_buttons = node_shader_buts_vector_rotate;
- break;
- case SH_NODE_VECT_TRANSFORM:
- ntype->draw_buttons = node_shader_buts_vect_transform;
- break;
- case SH_NODE_ATTRIBUTE:
- ntype->draw_buttons = node_shader_buts_attribute;
- break;
- case SH_NODE_WIREFRAME:
- ntype->draw_buttons = node_shader_buts_wireframe;
- break;
- case SH_NODE_TEX_SKY:
- ntype->draw_buttons = node_shader_buts_tex_sky;
- break;
case SH_NODE_TEX_IMAGE:
ntype->draw_buttons = node_shader_buts_tex_image;
ntype->draw_buttons_ex = node_shader_buts_tex_image_ex;
@@ -930,105 +493,20 @@ static void node_shader_set_butfunc(bNodeType *ntype)
ntype->draw_buttons = node_shader_buts_tex_environment;
ntype->draw_buttons_ex = node_shader_buts_tex_environment_ex;
break;
- case SH_NODE_TEX_GRADIENT:
- ntype->draw_buttons = node_shader_buts_tex_gradient;
- break;
- case SH_NODE_TEX_MAGIC:
- ntype->draw_buttons = node_shader_buts_tex_magic;
- break;
- case SH_NODE_TEX_BRICK:
- ntype->draw_buttons = node_shader_buts_tex_brick;
- break;
- case SH_NODE_TEX_WAVE:
- ntype->draw_buttons = node_shader_buts_tex_wave;
- break;
- case SH_NODE_TEX_MUSGRAVE:
- ntype->draw_buttons = node_shader_buts_tex_musgrave;
- break;
- case SH_NODE_TEX_VORONOI:
- ntype->draw_buttons = node_shader_buts_tex_voronoi;
- break;
- case SH_NODE_TEX_NOISE:
- ntype->draw_buttons = node_shader_buts_tex_noise;
- break;
- case SH_NODE_TEX_POINTDENSITY:
- ntype->draw_buttons = node_shader_buts_tex_pointdensity;
- break;
- case SH_NODE_TEX_COORD:
- ntype->draw_buttons = node_shader_buts_tex_coord;
- break;
- case SH_NODE_BUMP:
- ntype->draw_buttons = node_shader_buts_bump;
- break;
- case SH_NODE_NORMAL_MAP:
- ntype->draw_buttons = node_shader_buts_normal_map;
- break;
case SH_NODE_DISPLACEMENT:
case SH_NODE_VECTOR_DISPLACEMENT:
ntype->draw_buttons = node_shader_buts_displacement;
break;
- case SH_NODE_TANGENT:
- ntype->draw_buttons = node_shader_buts_tangent;
- break;
case SH_NODE_BSDF_GLOSSY:
case SH_NODE_BSDF_GLASS:
case SH_NODE_BSDF_REFRACTION:
ntype->draw_buttons = node_shader_buts_glossy;
break;
- case SH_NODE_BSDF_PRINCIPLED:
- ntype->draw_buttons = node_shader_buts_principled;
- break;
- case SH_NODE_BSDF_ANISOTROPIC:
- ntype->draw_buttons = node_shader_buts_anisotropic;
- break;
- case SH_NODE_SUBSURFACE_SCATTERING:
- ntype->draw_buttons = node_shader_buts_subsurface;
- break;
- case SH_NODE_BSDF_TOON:
- ntype->draw_buttons = node_shader_buts_toon;
- break;
- case SH_NODE_BSDF_HAIR:
- ntype->draw_buttons = node_shader_buts_hair;
- break;
- case SH_NODE_BSDF_HAIR_PRINCIPLED:
- ntype->draw_buttons = node_shader_buts_principled_hair;
- break;
- case SH_NODE_SCRIPT:
- ntype->draw_buttons = node_shader_buts_script;
- ntype->draw_buttons_ex = node_shader_buts_script_ex;
- break;
- case SH_NODE_UVMAP:
- ntype->draw_buttons = node_shader_buts_uvmap;
- break;
- case SH_NODE_VERTEX_COLOR:
- ntype->draw_buttons = node_shader_buts_vertex_color;
- break;
- case SH_NODE_UVALONGSTROKE:
- ntype->draw_buttons = node_shader_buts_uvalongstroke;
- break;
case SH_NODE_OUTPUT_MATERIAL:
case SH_NODE_OUTPUT_LIGHT:
case SH_NODE_OUTPUT_WORLD:
ntype->draw_buttons = node_buts_output_shader;
break;
- case SH_NODE_OUTPUT_LINESTYLE:
- ntype->draw_buttons = node_buts_output_linestyle;
- break;
- case SH_NODE_TEX_IES:
- ntype->draw_buttons = node_shader_buts_ies;
- break;
- case SH_NODE_BEVEL:
- ntype->draw_buttons = node_shader_buts_bevel;
- break;
- case SH_NODE_AMBIENT_OCCLUSION:
- ntype->draw_buttons = node_shader_buts_ambient_occlusion;
- break;
- case SH_NODE_TEX_WHITE_NOISE:
- ntype->draw_buttons = node_shader_buts_white_noise;
- break;
- case SH_NODE_OUTPUT_AOV:
- ntype->draw_buttons = node_shader_buts_output_aov;
- break;
}
}
@@ -1095,763 +573,6 @@ static void node_composit_buts_image_ex(uiLayout *layout, bContext *C, PointerRN
uiTemplateImage(layout, C, ptr, "image", &iuserptr, false, true);
}
-static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
- uiLayout *col, *row;
-
- uiTemplateID(layout,
- C,
- ptr,
- "scene",
- nullptr,
- nullptr,
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (!node->id) {
- return;
- }
-
- col = uiLayoutColumn(layout, false);
- row = uiLayoutRow(col, true);
- uiItemR(row, ptr, "layer", DEFAULT_FLAGS, "", ICON_NONE);
-
- PropertyRNA *prop = RNA_struct_find_property(ptr, "layer");
- const char *layer_name;
- if (!(RNA_property_enum_identifier(
- C, ptr, prop, RNA_property_enum_get(ptr, prop), &layer_name))) {
- return;
- }
-
- PointerRNA scn_ptr;
- char scene_name[MAX_ID_NAME - 2];
- scn_ptr = RNA_pointer_get(ptr, "scene");
- RNA_string_get(&scn_ptr, "name", scene_name);
-
- PointerRNA op_ptr;
- uiItemFullO(
- row, "RENDER_OT_render", "", ICON_RENDER_STILL, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
- RNA_string_set(&op_ptr, "layer", layer_name);
- RNA_string_set(&op_ptr, "scene", scene_name);
-}
-
-static void node_composit_buts_blur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col, *row;
-
- col = uiLayoutColumn(layout, false);
- const int filter = RNA_enum_get(ptr, "filter_type");
- const int reference = RNA_boolean_get(ptr, "use_variable_size");
-
- uiItemR(col, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
- if (filter != R_FILTER_FAST_GAUSS) {
- uiItemR(col, ptr, "use_variable_size", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (!reference) {
- uiItemR(col, ptr, "use_bokeh", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- uiItemR(col, ptr, "use_gamma_correction", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-
- uiItemR(col, ptr, "use_relative", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (RNA_boolean_get(ptr, "use_relative")) {
- uiItemL(col, IFACE_("Aspect Correction"), ICON_NONE);
- row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "aspect_correction", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "factor_x", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE);
- uiItemR(col, ptr, "factor_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE);
- }
- else {
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "size_x", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE);
- uiItemR(col, ptr, "size_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE);
- }
- uiItemR(col, ptr, "use_extended_bounds", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_dblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- uiItemR(layout, ptr, "iterations", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "use_wrap", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- uiItemL(col, IFACE_("Center:"), ICON_NONE);
- uiItemR(col, ptr, "center_x", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE);
- uiItemR(col, ptr, "center_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE);
-
- uiItemS(layout);
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "distance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "angle", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiItemS(layout);
-
- uiItemR(layout, ptr, "spin", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "zoom", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_bilateralblur(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "iterations", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "sigma_color", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "sigma_space", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- uiLayout *sub, *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemL(col, IFACE_("Bokeh Type:"), ICON_NONE);
- uiItemR(col, ptr, "bokeh", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(col, ptr, "angle", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiItemR(layout, ptr, "use_gamma_correction", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, false);
- uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_zbuffer") == true);
- uiItemR(col, ptr, "f_stop", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiItemR(layout, ptr, "blur_max", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "threshold", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "use_preview", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiTemplateID(layout,
- C,
- ptr,
- "scene",
- nullptr,
- nullptr,
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "use_zbuffer", DEFAULT_FLAGS, nullptr, ICON_NONE);
- sub = uiLayoutColumn(col, false);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_zbuffer") == false);
- uiItemR(sub, ptr, "z_scale", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_antialiasing(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
-
- uiItemR(col, ptr, "threshold", 0, nullptr, ICON_NONE);
- uiItemR(col, ptr, "contrast_limit", 0, nullptr, ICON_NONE);
- uiItemR(col, ptr, "corner_rounding", 0, nullptr, ICON_NONE);
-}
-
-/* glare node */
-static void node_composit_buts_glare(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "glare_type", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(layout, ptr, "quality", DEFAULT_FLAGS, "", ICON_NONE);
-
- if (RNA_enum_get(ptr, "glare_type") != 1) {
- uiItemR(layout, ptr, "iterations", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (RNA_enum_get(ptr, "glare_type") != 0) {
- uiItemR(
- layout, ptr, "color_modulation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- }
- }
-
- uiItemR(layout, ptr, "mix", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "threshold", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (RNA_enum_get(ptr, "glare_type") == 2) {
- uiItemR(layout, ptr, "streaks", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "angle_offset", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- if (RNA_enum_get(ptr, "glare_type") == 0 || RNA_enum_get(ptr, "glare_type") == 2) {
- uiItemR(layout, ptr, "fade", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- if (RNA_enum_get(ptr, "glare_type") == 0) {
- uiItemR(layout, ptr, "use_rotate_45", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- }
- if (RNA_enum_get(ptr, "glare_type") == 1) {
- uiItemR(layout, ptr, "size", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-
-static void node_composit_buts_tonemap(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "tonemap_type", DEFAULT_FLAGS, "", ICON_NONE);
- if (RNA_enum_get(ptr, "tonemap_type") == 0) {
- uiItemR(col, ptr, "key", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "offset", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "gamma", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- else {
- uiItemR(col, ptr, "intensity", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "adaptation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "correction", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- }
-}
-
-static void node_composit_buts_lensdist(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "use_projector", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(col, false);
- uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_projector") == false);
- uiItemR(col, ptr, "use_jitter", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "use_fit", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_vecblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "samples", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "factor", DEFAULT_FLAGS, IFACE_("Blur"), ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- uiItemL(col, IFACE_("Speed:"), ICON_NONE);
- uiItemR(col, ptr, "speed_min", DEFAULT_FLAGS, IFACE_("Min"), ICON_NONE);
- uiItemR(col, ptr, "speed_max", DEFAULT_FLAGS, IFACE_("Max"), ICON_NONE);
-
- uiItemR(layout, ptr, "use_curved", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_filter(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_flip(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "axis", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_crop(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- uiItemR(layout, ptr, "use_crop_size", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "relative", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- if (RNA_boolean_get(ptr, "relative")) {
- uiItemR(col, ptr, "rel_min_x", DEFAULT_FLAGS, IFACE_("Left"), ICON_NONE);
- uiItemR(col, ptr, "rel_max_x", DEFAULT_FLAGS, IFACE_("Right"), ICON_NONE);
- uiItemR(col, ptr, "rel_min_y", DEFAULT_FLAGS, IFACE_("Up"), ICON_NONE);
- uiItemR(col, ptr, "rel_max_y", DEFAULT_FLAGS, IFACE_("Down"), ICON_NONE);
- }
- else {
- uiItemR(col, ptr, "min_x", DEFAULT_FLAGS, IFACE_("Left"), ICON_NONE);
- uiItemR(col, ptr, "max_x", DEFAULT_FLAGS, IFACE_("Right"), ICON_NONE);
- uiItemR(col, ptr, "min_y", DEFAULT_FLAGS, IFACE_("Up"), ICON_NONE);
- uiItemR(col, ptr, "max_y", DEFAULT_FLAGS, IFACE_("Down"), ICON_NONE);
- }
-}
-
-static void node_composit_buts_splitviewer(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *row, *col;
-
- col = uiLayoutColumn(layout, false);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "axis", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
- uiItemR(col, ptr, "factor", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_double_edge_mask(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
-
- uiItemL(col, IFACE_("Inner Edge:"), ICON_NONE);
- uiItemR(col, ptr, "inner_mode", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemL(col, IFACE_("Buffer Edge:"), ICON_NONE);
- uiItemR(col, ptr, "edge_mode", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_clamp", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_map_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *sub, *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "offset", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "size", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_min", DEFAULT_FLAGS, nullptr, ICON_NONE);
- sub = uiLayoutColumn(col, false);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min"));
- uiItemR(sub, ptr, "min", DEFAULT_FLAGS, "", ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_max", DEFAULT_FLAGS, nullptr, ICON_NONE);
- sub = uiLayoutColumn(col, false);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max"));
- uiItemR(sub, ptr, "max", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_alphaover(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_premultiply", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "premul", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_zcombine(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_alpha", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "use_antialias_z", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_dilateerode(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- switch (RNA_enum_get(ptr, "mode")) {
- case CMP_NODE_DILATEERODE_DISTANCE_THRESH:
- uiItemR(layout, ptr, "edge", DEFAULT_FLAGS, nullptr, ICON_NONE);
- break;
- case CMP_NODE_DILATEERODE_DISTANCE_FEATHER:
- uiItemR(layout, ptr, "falloff", DEFAULT_FLAGS, nullptr, ICON_NONE);
- break;
- }
-}
-
-static void node_composit_buts_inpaint(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_despeckle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "threshold", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "threshold_neighbor", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_diff_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "falloff", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_distance_matte(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiLayout *col, *row;
-
- col = uiLayoutColumn(layout, true);
-
- uiItemL(layout, IFACE_("Color Space:"), ICON_NONE);
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
-
- uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "falloff", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_color_spill(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *row, *col;
-
- uiItemL(layout, IFACE_("Despill Channel:"), ICON_NONE);
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "limit_method", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (RNA_enum_get(ptr, "limit_method") == 0) {
- uiItemL(col, IFACE_("Limiting Channel:"), ICON_NONE);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "limit_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
- }
-
- uiItemR(col, ptr, "ratio", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "use_unspill", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (RNA_boolean_get(ptr, "use_unspill") == true) {
- uiItemR(col, ptr, "unspill_red", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "unspill_green", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "unspill_blue", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- }
-}
-
-static void node_composit_buts_chroma_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "threshold", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- /* Removed for now. */
- // uiItemR(col, ptr, "lift", UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- /* Removed for now. */
- // uiItemR(col, ptr, "shadow_adjust", UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_color_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "color_hue", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "color_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "color_value", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_channel_matte(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiLayout *col, *row;
-
- uiItemL(layout, IFACE_("Color Space:"), ICON_NONE);
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "color_space", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, false);
- uiItemL(col, IFACE_("Key Channel:"), ICON_NONE);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "matte_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, false);
-
- uiItemR(col, ptr, "limit_method", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (RNA_enum_get(ptr, "limit_method") == 0) {
- uiItemL(col, IFACE_("Limiting Channel:"), ICON_NONE);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "limit_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
- }
-
- uiItemR(col, ptr, "limit_max", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "limit_min", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_luma_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "limit_max", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "limit_min", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_map_uv(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "alpha", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_id_mask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "index", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "use_antialiasing", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- PointerRNA imfptr = RNA_pointer_get(ptr, "format");
- const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
-
- if (multilayer) {
- uiItemL(layout, IFACE_("Path:"), ICON_NONE);
- }
- else {
- uiItemL(layout, IFACE_("Base Path:"), ICON_NONE);
- }
- uiItemR(layout, ptr, "base_path", DEFAULT_FLAGS, "", ICON_NONE);
-}
-static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- Scene *scene = CTX_data_scene(C);
- PointerRNA imfptr = RNA_pointer_get(ptr, "format");
- PointerRNA active_input_ptr, op_ptr;
- uiLayout *row, *col;
- const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
- const bool is_exr = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_OPENEXR;
- const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
-
- node_composit_buts_file_output(layout, C, ptr);
- uiTemplateImageSettings(layout, &imfptr, false);
-
- /* disable stereo output for multilayer, too much work for something that no one will use */
- /* if someone asks for that we can implement it */
- if (is_multiview) {
- uiTemplateImageFormatViews(layout, &imfptr, nullptr);
- }
-
- uiItemS(layout);
-
- uiItemO(layout, IFACE_("Add Input"), ICON_ADD, "NODE_OT_output_file_add_socket");
-
- row = uiLayoutRow(layout, false);
- col = uiLayoutColumn(row, true);
-
- const int active_index = RNA_int_get(ptr, "active_input_index");
- /* using different collection properties if multilayer format is enabled */
- if (multilayer) {
- uiTemplateList(col,
- C,
- "UI_UL_list",
- "file_output_node",
- ptr,
- "layer_slots",
- ptr,
- "active_input_index",
- nullptr,
- 0,
- 0,
- 0,
- 0,
- UI_TEMPLATE_LIST_FLAG_NONE);
- RNA_property_collection_lookup_int(
- ptr, RNA_struct_find_property(ptr, "layer_slots"), active_index, &active_input_ptr);
- }
- else {
- uiTemplateList(col,
- C,
- "UI_UL_list",
- "file_output_node",
- ptr,
- "file_slots",
- ptr,
- "active_input_index",
- nullptr,
- 0,
- 0,
- 0,
- 0,
- UI_TEMPLATE_LIST_FLAG_NONE);
- RNA_property_collection_lookup_int(
- ptr, RNA_struct_find_property(ptr, "file_slots"), active_index, &active_input_ptr);
- }
- /* XXX collection lookup does not return the ID part of the pointer,
- * setting this manually here */
- active_input_ptr.owner_id = ptr->owner_id;
-
- col = uiLayoutColumn(row, true);
- wmOperatorType *ot = WM_operatortype_find("NODE_OT_output_file_move_active_socket", false);
- uiItemFullO_ptr(col, ot, "", ICON_TRIA_UP, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
- RNA_enum_set(&op_ptr, "direction", 1);
- uiItemFullO_ptr(col, ot, "", ICON_TRIA_DOWN, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
- RNA_enum_set(&op_ptr, "direction", 2);
-
- if (active_input_ptr.data) {
- if (multilayer) {
- col = uiLayoutColumn(layout, true);
-
- uiItemL(col, IFACE_("Layer:"), ICON_NONE);
- row = uiLayoutRow(col, false);
- uiItemR(row, &active_input_ptr, "name", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemFullO(row,
- "NODE_OT_output_file_remove_active_socket",
- "",
- ICON_X,
- nullptr,
- WM_OP_EXEC_DEFAULT,
- UI_ITEM_R_ICON_ONLY,
- nullptr);
- }
- else {
- col = uiLayoutColumn(layout, true);
-
- uiItemL(col, IFACE_("File Subpath:"), ICON_NONE);
- row = uiLayoutRow(col, false);
- uiItemR(row, &active_input_ptr, "path", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemFullO(row,
- "NODE_OT_output_file_remove_active_socket",
- "",
- ICON_X,
- nullptr,
- WM_OP_EXEC_DEFAULT,
- UI_ITEM_R_ICON_ONLY,
- nullptr);
-
- /* format details for individual files */
- imfptr = RNA_pointer_get(&active_input_ptr, "format");
-
- col = uiLayoutColumn(layout, true);
- uiItemL(col, IFACE_("Format:"), ICON_NONE);
- uiItemR(col, &active_input_ptr, "use_node_format", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- const bool is_socket_exr = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_OPENEXR;
- const bool use_node_format = RNA_boolean_get(&active_input_ptr, "use_node_format");
-
- if ((!is_exr && use_node_format) || (!is_socket_exr && !use_node_format)) {
- uiItemR(col, &active_input_ptr, "save_as_render", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-
- col = uiLayoutColumn(layout, false);
- uiLayoutSetActive(col, use_node_format == false);
- uiTemplateImageSettings(col, &imfptr, false);
-
- if (is_multiview) {
- uiTemplateImageFormatViews(layout, &imfptr, nullptr);
- }
- }
- }
-}
-
-static void node_composit_buts_scale(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", ICON_NONE);
-
- if (RNA_enum_get(ptr, "space") == CMP_SCALE_RENDERPERCENT) {
- uiLayout *row;
- uiItemR(layout, ptr, "frame_method", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
- row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "offset_x", DEFAULT_FLAGS, "X", ICON_NONE);
- uiItemR(row, ptr, "offset_y", DEFAULT_FLAGS, "Y", ICON_NONE);
- }
-}
-
-static void node_composit_buts_rotate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_invert(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "invert_rgb", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "invert_alpha", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_premulkey(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "mapping", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_view_levels(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "channel", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *split, *col, *row;
-
- uiItemR(layout, ptr, "correction_method", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (RNA_enum_get(ptr, "correction_method") == 0) {
-
- split = uiLayoutSplit(layout, 0.0f, false);
- col = uiLayoutColumn(split, false);
- uiTemplateColorPicker(col, ptr, "lift", true, true, false, true);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "lift", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(split, false);
- uiTemplateColorPicker(col, ptr, "gamma", true, true, true, true);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "gamma", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(split, false);
- uiTemplateColorPicker(col, ptr, "gain", true, true, true, true);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "gain", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- else {
-
- split = uiLayoutSplit(layout, 0.0f, false);
- col = uiLayoutColumn(split, false);
- uiTemplateColorPicker(col, ptr, "offset", true, true, false, true);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "offset", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "offset_basis", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(split, false);
- uiTemplateColorPicker(col, ptr, "power", true, true, false, true);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "power", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(split, false);
- uiTemplateColorPicker(col, ptr, "slope", true, true, false, true);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "slope", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-static void node_composit_buts_colorbalance_ex(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "correction_method", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (RNA_enum_get(ptr, "correction_method") == 0) {
-
- uiTemplateColorPicker(layout, ptr, "lift", true, true, false, true);
- uiItemR(layout, ptr, "lift", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiTemplateColorPicker(layout, ptr, "gamma", true, true, true, true);
- uiItemR(layout, ptr, "gamma", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiTemplateColorPicker(layout, ptr, "gain", true, true, true, true);
- uiItemR(layout, ptr, "gain", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- else {
- uiTemplateColorPicker(layout, ptr, "offset", true, true, false, true);
- uiItemR(layout, ptr, "offset", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiTemplateColorPicker(layout, ptr, "power", true, true, false, true);
- uiItemR(layout, ptr, "power", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiTemplateColorPicker(layout, ptr, "slope", true, true, false, true);
- uiItemR(layout, ptr, "slope", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-
static void node_composit_buts_huecorrect(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
bNode *node = (bNode *)ptr->data;
@@ -1873,260 +594,6 @@ static void node_composit_buts_ycc(uiLayout *layout, bContext *UNUSED(C), Pointe
uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE);
}
-static void node_composit_buts_movieclip(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- "CLIP_OT_open",
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-}
-
-static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
- PointerRNA clipptr;
-
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- "CLIP_OT_open",
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (!node->id) {
- return;
- }
-
- clipptr = RNA_pointer_get(ptr, "clip");
-
- uiTemplateColorspaceSettings(layout, &clipptr, "colorspace_settings");
-}
-
-static void node_composit_buts_stabilize2d(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
-
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- "CLIP_OT_open",
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (!node->id) {
- return;
- }
-
- uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_translate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "use_relative", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "wrap_axis", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_transform(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
-
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- "CLIP_OT_open",
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (!node->id) {
- return;
- }
-
- uiItemR(layout, ptr, "distortion_type", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_colorcorrection(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiLayout *row;
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "red", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "green", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "blue", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemL(row, "", ICON_NONE);
- uiItemL(row, IFACE_("Saturation"), ICON_NONE);
- uiItemL(row, IFACE_("Contrast"), ICON_NONE);
- uiItemL(row, IFACE_("Gamma"), ICON_NONE);
- uiItemL(row, IFACE_("Gain"), ICON_NONE);
- uiItemL(row, IFACE_("Lift"), ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemL(row, IFACE_("Master"), ICON_NONE);
- uiItemR(row, ptr, "master_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "master_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "master_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "master_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "master_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemL(row, IFACE_("Highlights"), ICON_NONE);
- uiItemR(row, ptr, "highlights_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "highlights_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "highlights_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "highlights_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "highlights_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemL(row, IFACE_("Midtones"), ICON_NONE);
- uiItemR(row, ptr, "midtones_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "midtones_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "midtones_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "midtones_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "midtones_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemL(row, IFACE_("Shadows"), ICON_NONE);
- uiItemR(row, ptr, "shadows_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "shadows_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "shadows_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "shadows_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "shadows_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "midtones_start", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_end", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_colorcorrection_ex(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiLayout *row;
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "red", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "green", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "blue", DEFAULT_FLAGS, nullptr, ICON_NONE);
- row = layout;
- uiItemL(row, IFACE_("Saturation"), ICON_NONE);
- uiItemR(row, ptr, "master_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "highlights_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "shadows_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- uiItemL(row, IFACE_("Contrast"), ICON_NONE);
- uiItemR(row, ptr, "master_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "highlights_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "shadows_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- uiItemL(row, IFACE_("Gamma"), ICON_NONE);
- uiItemR(row, ptr, "master_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "highlights_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "shadows_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- uiItemL(row, IFACE_("Gain"), ICON_NONE);
- uiItemR(row, ptr, "master_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "highlights_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "shadows_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- uiItemL(row, IFACE_("Lift"), ICON_NONE);
- uiItemR(row, ptr, "master_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "highlights_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "shadows_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "midtones_start", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_end", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_set_alpha(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_switch(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "check", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_switch_view_ex(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *UNUSED(ptr))
-{
- uiItemFullO(layout,
- "NODE_OT_switch_view_update",
- "Update Views",
- ICON_FILE_REFRESH,
- nullptr,
- WM_OP_INVOKE_DEFAULT,
- 0,
- nullptr);
-}
-
-static void node_composit_buts_boxmask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *row;
-
- row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "x", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "y", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "width", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "height", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- uiItemR(layout, ptr, "rotation", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "mask_type", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_bokehimage(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "flaps", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "angle", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "rounding", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "catadioptric", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "shift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_bokehblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "use_variable_size", DEFAULT_FLAGS, nullptr, ICON_NONE);
- // uiItemR(layout, ptr, "f_stop", DEFAULT_FLAGS, nullptr, ICON_NONE); /* UNUSED */
- uiItemR(layout, ptr, "blur_max", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "use_extended_bounds", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
static void node_composit_backdrop_viewer(
SpaceNode *snode, ImBuf *backdrop, bNode *node, int x, int y)
{
@@ -2246,221 +713,6 @@ static void node_composit_backdrop_ellipsemask(
immUnbindProgram();
}
-static void node_composit_buts_ellipsemask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *row;
- row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "x", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "y", DEFAULT_FLAGS, nullptr, ICON_NONE);
- row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "width", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "height", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- uiItemR(layout, ptr, "rotation", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "mask_type", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_composite(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_viewer(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_viewer_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "tile_order", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (RNA_enum_get(ptr, "tile_order") == 0) {
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "center_x", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "center_y", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-
-static void node_composit_buts_mask(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
-
- uiTemplateID(layout,
- C,
- ptr,
- "mask",
- nullptr,
- nullptr,
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
- uiItemR(layout, ptr, "use_feather", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiItemR(layout, ptr, "size_source", DEFAULT_FLAGS, "", ICON_NONE);
-
- if (node->custom1 & (CMP_NODEFLAG_MASK_FIXED | CMP_NODEFLAG_MASK_FIXED_SCENE)) {
- uiItemR(layout, ptr, "size_x", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "size_y", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-
- uiItemR(layout, ptr, "use_motion_blur", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (node->custom1 & CMP_NODEFLAG_MASK_MOTION_BLUR) {
- uiItemR(layout, ptr, "motion_blur_samples", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "motion_blur_shutter", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-
-static void node_composit_buts_keyingscreen(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
-
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- nullptr,
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (node->id) {
- MovieClip *clip = (MovieClip *)node->id;
- uiLayout *col;
- PointerRNA tracking_ptr;
-
- RNA_pointer_create(&clip->id, &RNA_MovieTracking, &clip->tracking, &tracking_ptr);
-
- col = uiLayoutColumn(layout, true);
- uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA);
- }
-}
-
-static void node_composit_buts_keying(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- /* bNode *node = (bNode*)ptr->data; */ /* UNUSED */
-
- uiItemR(layout, ptr, "blur_pre", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "screen_balance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "despill_factor", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "despill_balance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "edge_kernel_radius", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "edge_kernel_tolerance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "clip_black", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "clip_white", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "dilate_distance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "feather_falloff", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "feather_distance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "blur_post", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
-
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- "CLIP_OT_open",
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (node->id) {
- MovieClip *clip = (MovieClip *)node->id;
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *object;
- uiLayout *col;
- PointerRNA tracking_ptr;
- NodeTrackPosData *data = (NodeTrackPosData *)node->storage;
-
- RNA_pointer_create(&clip->id, &RNA_MovieTracking, tracking, &tracking_ptr);
-
- col = uiLayoutColumn(layout, false);
- uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA);
-
- object = BKE_tracking_object_get_named(tracking, data->tracking_object);
- if (object) {
- PointerRNA object_ptr;
-
- RNA_pointer_create(&clip->id, &RNA_MovieTrackingObject, object, &object_ptr);
-
- uiItemPointerR(col, ptr, "track_name", &object_ptr, "tracks", "", ICON_ANIM_DATA);
- }
- else {
- uiItemR(layout, ptr, "track_name", DEFAULT_FLAGS, "", ICON_ANIM_DATA);
- }
-
- uiItemR(layout, ptr, "position", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (ELEM(node->custom1, CMP_TRACKPOS_RELATIVE_FRAME, CMP_TRACKPOS_ABSOLUTE_FRAME)) {
- uiItemR(layout, ptr, "frame_relative", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- }
-}
-
-static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
- NodePlaneTrackDeformData *data = (NodePlaneTrackDeformData *)node->storage;
-
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- "CLIP_OT_open",
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (node->id) {
- MovieClip *clip = (MovieClip *)node->id;
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *object;
- uiLayout *col;
- PointerRNA tracking_ptr;
-
- RNA_pointer_create(&clip->id, &RNA_MovieTracking, tracking, &tracking_ptr);
-
- col = uiLayoutColumn(layout, false);
- uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA);
-
- object = BKE_tracking_object_get_named(tracking, data->tracking_object);
- if (object) {
- PointerRNA object_ptr;
-
- RNA_pointer_create(&clip->id, &RNA_MovieTrackingObject, object, &object_ptr);
-
- uiItemPointerR(
- col, ptr, "plane_track_name", &object_ptr, "plane_tracks", "", ICON_ANIM_DATA);
- }
- else {
- uiItemR(layout, ptr, "plane_track_name", 0, "", ICON_ANIM_DATA);
- }
- }
-
- uiItemR(layout, ptr, "use_motion_blur", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) {
- uiItemR(layout, ptr, "motion_blur_samples", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "motion_blur_shutter", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-
-static void node_composit_buts_sunbeams(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "source", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, "", ICON_NONE);
- uiItemR(layout, ptr, "ray_length", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
static void node_composit_buts_cryptomatte_legacy(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
@@ -2536,31 +788,6 @@ static void node_composit_buts_cryptomatte(uiLayout *layout, bContext *C, Pointe
uiTemplateCryptoPicker(row, ptr, "remove", ICON_REMOVE);
}
-static void node_composit_buts_brightcontrast(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "use_premultiply", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_denoise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
-#ifndef WITH_OPENIMAGEDENOISE
- uiItemL(layout, IFACE_("Disabled, built without OpenImageDenoise"), ICON_ERROR);
-#else
- /* Always supported through Accelerate framework BNNS on macOS. */
-# ifndef __APPLE__
- if (!BLI_cpu_support_sse41()) {
- uiItemL(layout, IFACE_("Disabled, CPU with SSE4.1 is required"), ICON_ERROR);
- }
-# endif
-#endif
-
- uiItemL(layout, IFACE_("Prefilter:"), ICON_NONE);
- uiItemR(layout, ptr, "prefilter", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "use_hdr", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
/* only once called */
static void node_composit_set_butfunc(bNodeType *ntype)
{
@@ -2569,15 +796,6 @@ static void node_composit_set_butfunc(bNodeType *ntype)
ntype->draw_buttons = node_composit_buts_image;
ntype->draw_buttons_ex = node_composit_buts_image_ex;
break;
- case CMP_NODE_R_LAYERS:
- ntype->draw_buttons = node_composit_buts_viewlayers;
- break;
- case CMP_NODE_NORMAL:
- ntype->draw_buttons = node_buts_normal;
- break;
- case CMP_NODE_CURVE_VEC:
- ntype->draw_buttons = node_buts_curvevec;
- break;
case CMP_NODE_CURVE_RGB:
ntype->draw_buttons = node_buts_curvecol;
break;
@@ -2587,210 +805,34 @@ static void node_composit_set_butfunc(bNodeType *ntype)
case CMP_NODE_RGB:
ntype->draw_buttons = node_buts_rgb;
break;
- case CMP_NODE_FLIP:
- ntype->draw_buttons = node_composit_buts_flip;
- break;
- case CMP_NODE_SPLITVIEWER:
- ntype->draw_buttons = node_composit_buts_splitviewer;
- break;
case CMP_NODE_MIX_RGB:
ntype->draw_buttons = node_buts_mix_rgb;
break;
case CMP_NODE_VALTORGB:
ntype->draw_buttons = node_buts_colorramp;
break;
- case CMP_NODE_CROP:
- ntype->draw_buttons = node_composit_buts_crop;
- break;
- case CMP_NODE_BLUR:
- ntype->draw_buttons = node_composit_buts_blur;
- break;
- case CMP_NODE_DBLUR:
- ntype->draw_buttons = node_composit_buts_dblur;
- break;
- case CMP_NODE_BILATERALBLUR:
- ntype->draw_buttons = node_composit_buts_bilateralblur;
- break;
- case CMP_NODE_DEFOCUS:
- ntype->draw_buttons = node_composit_buts_defocus;
- break;
- case CMP_NODE_ANTIALIASING:
- ntype->draw_buttons = node_composit_buts_antialiasing;
- break;
- case CMP_NODE_GLARE:
- ntype->draw_buttons = node_composit_buts_glare;
- break;
- case CMP_NODE_TONEMAP:
- ntype->draw_buttons = node_composit_buts_tonemap;
- break;
- case CMP_NODE_LENSDIST:
- ntype->draw_buttons = node_composit_buts_lensdist;
- break;
- case CMP_NODE_VECBLUR:
- ntype->draw_buttons = node_composit_buts_vecblur;
- break;
- case CMP_NODE_FILTER:
- ntype->draw_buttons = node_composit_buts_filter;
- break;
- case CMP_NODE_MAP_VALUE:
- ntype->draw_buttons = node_composit_buts_map_value;
- break;
- case CMP_NODE_MAP_RANGE:
- ntype->draw_buttons = node_composit_buts_map_range;
- break;
case CMP_NODE_TIME:
ntype->draw_buttons = node_buts_time;
break;
- case CMP_NODE_ALPHAOVER:
- ntype->draw_buttons = node_composit_buts_alphaover;
- break;
case CMP_NODE_TEXTURE:
ntype->draw_buttons = node_buts_texture;
break;
- case CMP_NODE_DILATEERODE:
- ntype->draw_buttons = node_composit_buts_dilateerode;
- break;
- case CMP_NODE_INPAINT:
- ntype->draw_buttons = node_composit_buts_inpaint;
- break;
- case CMP_NODE_DESPECKLE:
- ntype->draw_buttons = node_composit_buts_despeckle;
- break;
- case CMP_NODE_OUTPUT_FILE:
- ntype->draw_buttons = node_composit_buts_file_output;
- ntype->draw_buttons_ex = node_composit_buts_file_output_ex;
- break;
- case CMP_NODE_DIFF_MATTE:
- ntype->draw_buttons = node_composit_buts_diff_matte;
- break;
- case CMP_NODE_DIST_MATTE:
- ntype->draw_buttons = node_composit_buts_distance_matte;
- break;
- case CMP_NODE_COLOR_SPILL:
- ntype->draw_buttons = node_composit_buts_color_spill;
- break;
- case CMP_NODE_CHROMA_MATTE:
- ntype->draw_buttons = node_composit_buts_chroma_matte;
- break;
- case CMP_NODE_COLOR_MATTE:
- ntype->draw_buttons = node_composit_buts_color_matte;
- break;
- case CMP_NODE_SCALE:
- ntype->draw_buttons = node_composit_buts_scale;
- break;
- case CMP_NODE_ROTATE:
- ntype->draw_buttons = node_composit_buts_rotate;
- break;
- case CMP_NODE_CHANNEL_MATTE:
- ntype->draw_buttons = node_composit_buts_channel_matte;
- break;
- case CMP_NODE_LUMA_MATTE:
- ntype->draw_buttons = node_composit_buts_luma_matte;
- break;
- case CMP_NODE_MAP_UV:
- ntype->draw_buttons = node_composit_buts_map_uv;
- break;
- case CMP_NODE_ID_MASK:
- ntype->draw_buttons = node_composit_buts_id_mask;
- break;
- case CMP_NODE_DOUBLEEDGEMASK:
- ntype->draw_buttons = node_composit_buts_double_edge_mask;
- break;
case CMP_NODE_MATH:
ntype->draw_buttons = node_buts_math;
break;
- case CMP_NODE_INVERT:
- ntype->draw_buttons = node_composit_buts_invert;
- break;
- case CMP_NODE_PREMULKEY:
- ntype->draw_buttons = node_composit_buts_premulkey;
- break;
- case CMP_NODE_VIEW_LEVELS:
- ntype->draw_buttons = node_composit_buts_view_levels;
- break;
- case CMP_NODE_COLORBALANCE:
- ntype->draw_buttons = node_composit_buts_colorbalance;
- ntype->draw_buttons_ex = node_composit_buts_colorbalance_ex;
- break;
case CMP_NODE_HUECORRECT:
ntype->draw_buttons = node_composit_buts_huecorrect;
break;
- case CMP_NODE_ZCOMBINE:
- ntype->draw_buttons = node_composit_buts_zcombine;
- break;
case CMP_NODE_COMBYCCA:
case CMP_NODE_SEPYCCA:
ntype->draw_buttons = node_composit_buts_ycc;
break;
- case CMP_NODE_MOVIECLIP:
- ntype->draw_buttons = node_composit_buts_movieclip;
- ntype->draw_buttons_ex = node_composit_buts_movieclip_ex;
- break;
- case CMP_NODE_STABILIZE2D:
- ntype->draw_buttons = node_composit_buts_stabilize2d;
- break;
- case CMP_NODE_TRANSFORM:
- ntype->draw_buttons = node_composit_buts_transform;
- break;
- case CMP_NODE_TRANSLATE:
- ntype->draw_buttons = node_composit_buts_translate;
- break;
- case CMP_NODE_MOVIEDISTORTION:
- ntype->draw_buttons = node_composit_buts_moviedistortion;
- break;
- case CMP_NODE_COLORCORRECTION:
- ntype->draw_buttons = node_composit_buts_colorcorrection;
- ntype->draw_buttons_ex = node_composit_buts_colorcorrection_ex;
- break;
- case CMP_NODE_SETALPHA:
- ntype->draw_buttons = node_composit_buts_set_alpha;
- break;
- case CMP_NODE_SWITCH:
- ntype->draw_buttons = node_composit_buts_switch;
- break;
- case CMP_NODE_SWITCH_VIEW:
- ntype->draw_buttons_ex = node_composit_buts_switch_view_ex;
- break;
case CMP_NODE_MASK_BOX:
- ntype->draw_buttons = node_composit_buts_boxmask;
ntype->draw_backdrop = node_composit_backdrop_boxmask;
break;
case CMP_NODE_MASK_ELLIPSE:
- ntype->draw_buttons = node_composit_buts_ellipsemask;
ntype->draw_backdrop = node_composit_backdrop_ellipsemask;
break;
- case CMP_NODE_BOKEHIMAGE:
- ntype->draw_buttons = node_composit_buts_bokehimage;
- break;
- case CMP_NODE_BOKEHBLUR:
- ntype->draw_buttons = node_composit_buts_bokehblur;
- break;
- case CMP_NODE_VIEWER:
- ntype->draw_buttons = node_composit_buts_viewer;
- ntype->draw_buttons_ex = node_composit_buts_viewer_ex;
- ntype->draw_backdrop = node_composit_backdrop_viewer;
- break;
- case CMP_NODE_COMPOSITE:
- ntype->draw_buttons = node_composit_buts_composite;
- break;
- case CMP_NODE_MASK:
- ntype->draw_buttons = node_composit_buts_mask;
- break;
- case CMP_NODE_KEYINGSCREEN:
- ntype->draw_buttons = node_composit_buts_keyingscreen;
- break;
- case CMP_NODE_KEYING:
- ntype->draw_buttons = node_composit_buts_keying;
- break;
- case CMP_NODE_TRACKPOS:
- ntype->draw_buttons = node_composit_buts_trackpos;
- break;
- case CMP_NODE_PLANETRACKDEFORM:
- ntype->draw_buttons = node_composit_buts_planetrackdeform;
- break;
- case CMP_NODE_SUNBEAMS:
- ntype->draw_buttons = node_composit_buts_sunbeams;
- break;
case CMP_NODE_CRYPTOMATTE:
ntype->draw_buttons = node_composit_buts_cryptomatte;
break;
@@ -2798,11 +840,8 @@ static void node_composit_set_butfunc(bNodeType *ntype)
ntype->draw_buttons = node_composit_buts_cryptomatte_legacy;
ntype->draw_buttons_ex = node_composit_buts_cryptomatte_legacy_ex;
break;
- case CMP_NODE_BRIGHTCONTRAST:
- ntype->draw_buttons = node_composit_buts_brightcontrast;
- break;
- case CMP_NODE_DENOISE:
- ntype->draw_buttons = node_composit_buts_denoise;
+ case CMP_NODE_VIEWER:
+ ntype->draw_backdrop = node_composit_backdrop_viewer;
break;
}
}
@@ -2997,7 +1036,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)
@@ -3065,8 +1105,12 @@ static void node_socket_undefined_interface_draw_color(bContext *UNUSED(C),
/** \} */
+} // namespace blender::ed::space_node
+
void ED_node_init_butfuncs()
{
+ using namespace blender::ed::space_node;
+
/* Fallback types for undefined tree, nodes, sockets
* Defined in blenkernel, but not registered in type hashes.
*/
@@ -3091,12 +1135,6 @@ void ED_node_init_butfuncs()
node_template_properties_update(ntype);
}
NODE_TYPES_END;
-
- /* tree type icons */
- ntreeType_Composite->ui_icon = ICON_NODE_COMPOSITING;
- ntreeType_Shader->ui_icon = ICON_NODE_MATERIAL;
- ntreeType_Texture->ui_icon = ICON_NODE_TEXTURE;
- ntreeType_Geometry->ui_icon = ICON_NODETREE;
}
void ED_init_custom_node_type(bNodeType *UNUSED(ntype))
@@ -3105,9 +1143,11 @@ void ED_init_custom_node_type(bNodeType *UNUSED(ntype))
void ED_init_custom_node_socket_type(bNodeSocketType *stype)
{
- stype->draw = node_socket_button_label;
+ stype->draw = blender::ed::space_node::node_socket_button_label;
}
+namespace blender::ed::space_node {
+
static const float virtual_node_socket_color[4] = {0.2, 0.2, 0.2, 1.0};
/* maps standard socket integer type to a color */
@@ -3390,14 +1430,6 @@ static void std_node_socket_interface_draw(bContext *UNUSED(C), uiLayout *layout
uiItemR(layout, ptr, "hide_value", DEFAULT_FLAGS, nullptr, 0);
}
-void ED_init_standard_node_socket_type(bNodeSocketType *stype)
-{
- stype->draw = std_node_socket_draw;
- stype->draw_color = std_node_socket_draw_color;
- stype->interface_draw = std_node_socket_interface_draw;
- stype->interface_draw_color = std_node_socket_interface_draw_color;
-}
-
static void node_socket_virtual_draw_color(bContext *UNUSED(C),
PointerRNA *UNUSED(ptr),
PointerRNA *UNUSED(node_ptr),
@@ -3406,12 +1438,26 @@ static void node_socket_virtual_draw_color(bContext *UNUSED(C),
copy_v4_v4(r_color, virtual_node_socket_color);
}
+} // namespace blender::ed::space_node
+
+void ED_init_standard_node_socket_type(bNodeSocketType *stype)
+{
+ using namespace blender::ed::space_node;
+ stype->draw = std_node_socket_draw;
+ stype->draw_color = std_node_socket_draw_color;
+ stype->interface_draw = std_node_socket_interface_draw;
+ stype->interface_draw_color = std_node_socket_interface_draw_color;
+}
+
void ED_init_node_socket_type_virtual(bNodeSocketType *stype)
{
+ using namespace blender::ed::space_node;
stype->draw = node_socket_button_label;
stype->draw_color = node_socket_virtual_draw_color;
}
+namespace blender::ed::space_node {
+
/* ************** Generic drawing ************** */
void draw_nodespace_back_pix(const bContext &C,
@@ -3845,23 +1891,29 @@ static void nodelink_batch_draw(const SpaceNode &snode)
}
GPU_blend(GPU_BLEND_ALPHA);
+ NodeLinkInstanceData node_link_data;
+
+ UI_GetThemeColor4fv(TH_WIRE_INNER, node_link_data.colors[nodelink_get_color_id(TH_WIRE_INNER)]);
+ UI_GetThemeColor4fv(TH_WIRE, node_link_data.colors[nodelink_get_color_id(TH_WIRE)]);
+ UI_GetThemeColor4fv(TH_ACTIVE, node_link_data.colors[nodelink_get_color_id(TH_ACTIVE)]);
+ UI_GetThemeColor4fv(TH_EDGE_SELECT,
+ node_link_data.colors[nodelink_get_color_id(TH_EDGE_SELECT)]);
+ UI_GetThemeColor4fv(TH_REDALERT, node_link_data.colors[nodelink_get_color_id(TH_REDALERT)]);
+ node_link_data.expandSize = snode.runtime->aspect * LINK_WIDTH;
+ node_link_data.arrowSize = ARROW_SIZE;
- float colors[6][4] = {{0.0f}};
- UI_GetThemeColor4fv(TH_WIRE_INNER, colors[nodelink_get_color_id(TH_WIRE_INNER)]);
- UI_GetThemeColor4fv(TH_WIRE, colors[nodelink_get_color_id(TH_WIRE)]);
- UI_GetThemeColor4fv(TH_ACTIVE, colors[nodelink_get_color_id(TH_ACTIVE)]);
- UI_GetThemeColor4fv(TH_EDGE_SELECT, colors[nodelink_get_color_id(TH_EDGE_SELECT)]);
- UI_GetThemeColor4fv(TH_REDALERT, colors[nodelink_get_color_id(TH_REDALERT)]);
+ GPUUniformBuf *ubo = GPU_uniformbuf_create_ex(sizeof(node_link_data), &node_link_data, __func__);
GPU_vertbuf_data_len_set(g_batch_link.inst_vbo, g_batch_link.count);
GPU_vertbuf_use(g_batch_link.inst_vbo); /* force update. */
GPU_batch_program_set_builtin(g_batch_link.batch, GPU_SHADER_2D_NODELINK_INST);
- GPU_batch_uniform_4fv_array(g_batch_link.batch, "colors", 6, colors);
- GPU_batch_uniform_1f(g_batch_link.batch, "expandSize", snode.runtime->aspect * LINK_WIDTH);
- GPU_batch_uniform_1f(g_batch_link.batch, "arrowSize", ARROW_SIZE);
+ GPU_batch_uniformbuf_bind(g_batch_link.batch, "node_link_data", ubo);
GPU_batch_draw(g_batch_link.batch);
+ GPU_uniformbuf_unbind(ubo);
+ GPU_uniformbuf_free(ubo);
+
nodelink_batch_reset();
GPU_blend(GPU_BLEND_NONE);
@@ -4032,19 +2084,32 @@ void node_draw_link_bezier(const bContext &C,
copy_v4_v4(colors[2], link_preselection_highlight_color);
}
+ NodeLinkData node_link_data;
+ for (int i = 0; i < 4; i++) {
+ copy_v2_v2(node_link_data.bezierPts[i], vec[i]);
+ }
+ for (int i = 0; i < 3; i++) {
+ copy_v4_v4(node_link_data.colors[i], colors[i]);
+ }
+ node_link_data.doArrow = drawarrow;
+ node_link_data.doMuted = drawmuted;
+ node_link_data.dim_factor = dim_factor;
+ node_link_data.thickness = thickness;
+ node_link_data.dash_factor = dash_factor;
+ node_link_data.dash_alpha = dash_alpha;
+ node_link_data.expandSize = snode.runtime->aspect * LINK_WIDTH;
+ node_link_data.arrowSize = ARROW_SIZE;
+
GPUBatch *batch = g_batch_link.batch_single;
+ GPUUniformBuf *ubo = GPU_uniformbuf_create_ex(
+ sizeof(NodeLinkData), &node_link_data, __func__);
+
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_NODELINK);
- GPU_batch_uniform_2fv_array(batch, "bezierPts", 4, vec);
- GPU_batch_uniform_4fv_array(batch, "colors", 3, colors);
- GPU_batch_uniform_1f(batch, "expandSize", snode.runtime->aspect * LINK_WIDTH);
- GPU_batch_uniform_1f(batch, "arrowSize", ARROW_SIZE);
- GPU_batch_uniform_1i(batch, "doArrow", drawarrow);
- GPU_batch_uniform_1i(batch, "doMuted", drawmuted);
- GPU_batch_uniform_1f(batch, "dim_factor", dim_factor);
- GPU_batch_uniform_1f(batch, "thickness", thickness);
- GPU_batch_uniform_1f(batch, "dash_factor", dash_factor);
- GPU_batch_uniform_1f(batch, "dash_alpha", dash_alpha);
+ GPU_batch_uniformbuf_bind(batch, "node_link_data", ubo);
GPU_batch_draw(batch);
+
+ GPU_uniformbuf_unbind(ubo);
+ GPU_uniformbuf_free(ubo);
}
}
}
@@ -4099,6 +2164,8 @@ void node_draw_link(const bContext &C,
node_draw_link_bezier(C, v2d, snode, link, th_col1, th_col2, th_col3);
}
+} // namespace blender::ed::space_node
+
void ED_node_draw_snap(View2D *v2d, const float cent[2], float size, NodeBorder border, uint pos)
{
immBegin(GPU_PRIM_LINES, 4);
diff --git a/source/blender/editors/space_node/link_drag_search.cc b/source/blender/editors/space_node/link_drag_search.cc
new file mode 100644
index 00000000000..45126e9cee0
--- /dev/null
+++ b/source/blender/editors/space_node/link_drag_search.cc
@@ -0,0 +1,327 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_listbase.h"
+#include "BLI_string_search.h"
+
+#include "DNA_space_types.h"
+
+#include "BKE_context.h"
+
+#include "NOD_socket_search_link.hh"
+
+#include "BLT_translation.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+
+#include "ED_node.h"
+
+#include "node_intern.hh"
+
+using blender::nodes::SocketLinkOperation;
+
+namespace blender::ed::space_node {
+
+struct LinkDragSearchStorage {
+ bNode &from_node;
+ bNodeSocket &from_socket;
+ float2 cursor;
+ Vector<SocketLinkOperation> search_link_ops;
+ char search[256];
+
+ eNodeSocketInOut in_out() const
+ {
+ return static_cast<eNodeSocketInOut>(from_socket.in_out);
+ }
+};
+
+static void add_reroute_node_fn(nodes::LinkSearchOpParams &params)
+{
+ bNode &reroute = params.add_node("NodeReroute");
+ if (params.socket.in_out == SOCK_IN) {
+ nodeAddLink(&params.node_tree,
+ &reroute,
+ static_cast<bNodeSocket *>(reroute.outputs.first),
+ &params.node,
+ &params.socket);
+ }
+ else {
+ nodeAddLink(&params.node_tree,
+ &params.node,
+ &params.socket,
+ &reroute,
+ static_cast<bNodeSocket *>(reroute.inputs.first));
+ }
+}
+
+static void add_group_input_node_fn(nodes::LinkSearchOpParams &params)
+{
+ /* Add a group input based on the connected socket, and add a new group input node. */
+ bNodeSocket *interface_socket = ntreeAddSocketInterfaceFromSocket(
+ &params.node_tree, &params.node, &params.socket);
+ const int group_input_index = BLI_findindex(&params.node_tree.inputs, interface_socket);
+
+ bNode &group_input = params.add_node("NodeGroupInput");
+
+ /* This is necessary to create the new sockets in the other input nodes. */
+ 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) {
+ if (node->type == NODE_GROUP_INPUT) {
+ bNodeSocket *new_group_input_socket = (bNodeSocket *)BLI_findlink(&node->outputs,
+ group_input_index);
+ new_group_input_socket->flag |= SOCK_HIDDEN;
+ }
+ }
+
+ /* Hide all existing inputs in the new group input node, to only display the new one. */
+ LISTBASE_FOREACH (bNodeSocket *, socket, &group_input.outputs) {
+ socket->flag |= SOCK_HIDDEN;
+ }
+
+ bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&group_input.outputs, group_input_index);
+ if (socket == nullptr) {
+ /* Adding sockets can fail in some cases. There's no good reason not to be safe here. */
+ return;
+ }
+ /* Unhide the socket for the new input in the new node and make a connection to it. */
+ socket->flag &= ~SOCK_HIDDEN;
+ nodeAddLink(&params.node_tree, &group_input, socket, &params.node, &params.socket);
+}
+
+static void add_existing_group_input_fn(nodes::LinkSearchOpParams &params,
+ const bNodeSocket &interface_socket)
+{
+ const int group_input_index = BLI_findindex(&params.node_tree.inputs, &interface_socket);
+ bNode &group_input = params.add_node("NodeGroupInput");
+
+ LISTBASE_FOREACH (bNodeSocket *, socket, &group_input.outputs) {
+ socket->flag |= SOCK_HIDDEN;
+ }
+
+ bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&group_input.outputs, group_input_index);
+ if (socket == nullptr) {
+ /* Adding sockets can fail in some cases. There's no good reason not to be safe here. */
+ return;
+ }
+
+ socket->flag &= ~SOCK_HIDDEN;
+ nodeAddLink(&params.node_tree, &group_input, socket, &params.node, &params.socket);
+}
+
+/**
+ * Call the callback to gather compatible socket connections for all node types, and the operations
+ * that will actually make the connections. Also add some custom operations like connecting a group
+ * output node.
+ */
+static void gather_socket_link_operations(bNodeTree &node_tree,
+ const bNodeSocket &socket,
+ Vector<SocketLinkOperation> &search_link_ops)
+{
+ NODE_TYPES_BEGIN (node_type) {
+ if (StringRef(node_type->idname).find("Legacy") != StringRef::not_found) {
+ continue;
+ }
+ const char *disabled_hint;
+ if (!(node_type->poll && node_type->poll(node_type, &node_tree, &disabled_hint))) {
+ continue;
+ }
+
+ if (node_type->gather_link_search_ops) {
+ nodes::GatherLinkSearchOpParams params{*node_type, node_tree, socket, search_link_ops};
+ node_type->gather_link_search_ops(params);
+ }
+ }
+ NODE_TYPES_END;
+
+ search_link_ops.append({IFACE_("Reroute"), add_reroute_node_fn});
+
+ const bool is_node_group = !(node_tree.id.flag & LIB_EMBEDDED_DATA);
+
+ if (is_node_group && socket.in_out == SOCK_IN) {
+ search_link_ops.append({IFACE_("Group Input"), add_group_input_node_fn});
+
+ int weight = -1;
+ LISTBASE_FOREACH (const bNodeSocket *, interface_socket, &node_tree.inputs) {
+ eNodeSocketDatatype from = (eNodeSocketDatatype)interface_socket->type;
+ eNodeSocketDatatype to = (eNodeSocketDatatype)socket.type;
+ if (node_tree.typeinfo->validate_link && !node_tree.typeinfo->validate_link(from, to)) {
+ continue;
+ }
+ search_link_ops.append(
+ {std::string(IFACE_("Group Input ")) + UI_MENU_ARROW_SEP + interface_socket->name,
+ [interface_socket](nodes::LinkSearchOpParams &params) {
+ add_existing_group_input_fn(params, *interface_socket);
+ },
+ weight});
+ weight--;
+ }
+ }
+}
+
+static void link_drag_search_update_fn(const bContext *UNUSED(C),
+ void *arg,
+ const char *str,
+ uiSearchItems *items,
+ const bool is_first)
+{
+ LinkDragSearchStorage &storage = *static_cast<LinkDragSearchStorage *>(arg);
+
+ StringSearch *search = BLI_string_search_new();
+
+ for (SocketLinkOperation &op : storage.search_link_ops) {
+ BLI_string_search_add(search, op.name.c_str(), &op, op.weight);
+ }
+
+ /* Don't filter when the menu is first opened, but still run the search
+ * so the items are in the same order they will appear in while searching. */
+ const char *string = is_first ? "" : str;
+ SocketLinkOperation **filtered_items;
+ const int filtered_amount = BLI_string_search_query(search, string, (void ***)&filtered_items);
+
+ for (const int i : IndexRange(filtered_amount)) {
+ SocketLinkOperation &item = *filtered_items[i];
+ if (!UI_search_item_add(items, item.name.c_str(), &item, ICON_NONE, 0, 0)) {
+ break;
+ }
+ }
+
+ MEM_freeN(filtered_items);
+ BLI_string_search_free(search);
+}
+
+static void link_drag_search_exec_fn(bContext *C, void *arg1, void *arg2)
+{
+ Main &bmain = *CTX_data_main(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ LinkDragSearchStorage &storage = *static_cast<LinkDragSearchStorage *>(arg1);
+ SocketLinkOperation *item = static_cast<SocketLinkOperation *>(arg2);
+ if (item == nullptr) {
+ return;
+ }
+
+ node_deselect_all(snode);
+
+ Vector<bNode *> new_nodes;
+ nodes::LinkSearchOpParams params{
+ *C, *snode.edittree, storage.from_node, storage.from_socket, new_nodes};
+ item->fn(params);
+ if (new_nodes.is_empty()) {
+ return;
+ }
+
+ /* For now, assume that only one node is created by the callback. */
+ BLI_assert(new_nodes.size() == 1);
+ bNode *new_node = new_nodes.first();
+
+ new_node->locx = storage.cursor.x / UI_DPI_FAC;
+ new_node->locy = storage.cursor.y / UI_DPI_FAC + 20 * UI_DPI_FAC;
+ if (storage.in_out() == SOCK_IN) {
+ new_node->locx -= new_node->width;
+ }
+
+ nodeSetSelected(new_node, true);
+ nodeSetActive(snode.edittree, new_node);
+
+ /* 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. */
+ 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);
+ BLI_assert(ot);
+ PointerRNA ptr;
+ WM_operator_properties_create_ptr(&ptr, ot);
+ RNA_boolean_set(&ptr, "view2d_edge_pan", true);
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
+ WM_operator_properties_free(&ptr);
+}
+
+static void link_drag_search_free_fn(void *arg)
+{
+ LinkDragSearchStorage *storage = static_cast<LinkDragSearchStorage *>(arg);
+ delete storage;
+}
+
+static uiBlock *create_search_popup_block(bContext *C, ARegion *region, void *arg_op)
+{
+ LinkDragSearchStorage &storage = *(LinkDragSearchStorage *)arg_op;
+
+ bNodeTree *node_tree = CTX_wm_space_node(C)->nodetree;
+ gather_socket_link_operations(*node_tree, storage.from_socket, storage.search_link_ops);
+
+ uiBlock *block = UI_block_begin(C, region, "_popup", UI_EMBOSS);
+ UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU);
+ UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
+
+ uiBut *but = uiDefSearchBut(block,
+ storage.search,
+ 0,
+ ICON_VIEWZOOM,
+ sizeof(storage.search),
+ storage.in_out() == SOCK_OUT ? 10 : 10 - UI_searchbox_size_x(),
+ 10,
+ UI_searchbox_size_x(),
+ UI_UNIT_Y,
+ 0,
+ 0,
+ "");
+ UI_but_func_search_set_sep_string(but, UI_MENU_ARROW_SEP);
+ UI_but_func_search_set(but,
+ nullptr,
+ link_drag_search_update_fn,
+ &storage,
+ false,
+ link_drag_search_free_fn,
+ link_drag_search_exec_fn,
+ nullptr);
+ UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
+
+ /* Fake button to hold space for the search items. */
+ uiDefBut(block,
+ UI_BTYPE_LABEL,
+ 0,
+ "",
+ storage.in_out() == SOCK_OUT ? 10 : 10 - UI_searchbox_size_x(),
+ 10 - UI_searchbox_size_y(),
+ UI_searchbox_size_x(),
+ UI_searchbox_size_y(),
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+
+ const int offset[2] = {0, -UI_UNIT_Y};
+ UI_block_bounds_set_popup(block, 0.3f * U.widget_unit, offset);
+ return block;
+}
+
+void invoke_node_link_drag_add_menu(bContext &C,
+ bNode &node,
+ bNodeSocket &socket,
+ const float2 &cursor)
+{
+ LinkDragSearchStorage *storage = new LinkDragSearchStorage{node, socket, cursor};
+ /* Use the "_ex" variant with `can_refresh` false to avoid a double free when closing Blender. */
+ UI_popup_block_invoke_ex(&C, create_search_popup_block, storage, nullptr, false);
+}
+
+} // 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..8e88f1fad5a 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"
@@ -61,6 +62,8 @@
/** \name Utilities
* \{ */
+namespace blender::ed::space_node {
+
bNode *node_add_node(const bContext &C, const char *idname, int type, float locx, float locy)
{
SpaceNode &snode = *CTX_wm_space_node(&C);
@@ -83,15 +86,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);
- }
-
+ ED_node_tree_propagate_change(&C, &bmain, snode.edittree);
return node;
}
@@ -136,7 +132,7 @@ static bNodeSocketLink *add_reroute_insert_socket_link(ListBase *lb,
{
bNodeSocketLink *socklink, *prev;
- socklink = (bNodeSocketLink *)MEM_callocN(sizeof(bNodeSocketLink), "socket link");
+ socklink = MEM_cnew<bNodeSocketLink>("socket link");
socklink->sock = sock;
socklink->link = link;
copy_v2_v2(socklink->point, point);
@@ -281,10 +277,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;
}
@@ -383,14 +376,10 @@ static int node_add_group_exec(bContext *C, wmOperator *op)
group_node->id = &node_group->id;
id_us_plus(group_node->id);
+ BKE_ntree_update_tag_node_property(snode->edittree, group_node);
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 +468,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;
@@ -517,6 +501,8 @@ static bool node_add_object_poll(bContext *C)
void NODE_OT_add_object(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Add Node Object";
ot->description = "Add an object info node to the current node editor";
@@ -531,15 +517,16 @@ void NODE_OT_add_object(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
RNA_def_string(ot->srna, "name", "Object", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
- RNA_def_int(ot->srna,
- "session_uuid",
- 0,
- INT32_MIN,
- INT32_MAX,
- "Session UUID",
- "Session UUID of the data-block to assign",
- INT32_MIN,
- INT32_MAX);
+ prop = RNA_def_int(ot->srna,
+ "session_uuid",
+ 0,
+ INT32_MIN,
+ INT32_MAX,
+ "Session UUID",
+ "Session UUID of the data-block to assign",
+ INT32_MIN,
+ INT32_MAX);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
}
/** \} */
@@ -587,14 +574,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;
}
@@ -625,6 +607,8 @@ static bool node_add_texture_poll(bContext *C)
void NODE_OT_add_texture(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Add Node Texture";
ot->description = "Add a texture to the current node editor";
@@ -640,15 +624,16 @@ void NODE_OT_add_texture(wmOperatorType *ot)
RNA_def_string(
ot->srna, "name", "Texture", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
- RNA_def_int(ot->srna,
- "session_uuid",
- 0,
- INT32_MIN,
- INT32_MAX,
- "Session UUID",
- "Session UUID of the data-block to assign",
- INT32_MIN,
- INT32_MAX);
+ prop = RNA_def_int(ot->srna,
+ "session_uuid",
+ 0,
+ INT32_MIN,
+ INT32_MAX,
+ "Session UUID",
+ "Session UUID of the data-block to assign",
+ INT32_MIN,
+ INT32_MAX);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
}
/** \} */
@@ -701,14 +686,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;
}
@@ -739,6 +719,8 @@ static bool node_add_collection_poll(bContext *C)
void NODE_OT_add_collection(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Add Node Collection";
ot->description = "Add an collection info node to the current node editor";
@@ -754,15 +736,16 @@ void NODE_OT_add_collection(wmOperatorType *ot)
RNA_def_string(
ot->srna, "name", "Collection", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
- RNA_def_int(ot->srna,
- "session_uuid",
- 0,
- INT32_MIN,
- INT32_MAX,
- "Session UUID",
- "Session UUID of the data-block to assign",
- INT32_MIN,
- INT32_MAX);
+ prop = RNA_def_int(ot->srna,
+ "session_uuid",
+ 0,
+ INT32_MIN,
+ INT32_MAX,
+ "Session UUID",
+ "Session UUID of the data-block to assign",
+ INT32_MIN,
+ INT32_MAX);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
}
/** \} */
@@ -834,8 +817,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 +919,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;
@@ -946,6 +927,8 @@ static int node_add_mask_exec(bContext *C, wmOperator *op)
void NODE_OT_add_mask(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Add Mask Node";
ot->description = "Add a mask node to the current node editor";
@@ -959,15 +942,16 @@ void NODE_OT_add_mask(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
RNA_def_string(ot->srna, "name", "Mask", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
- RNA_def_int(ot->srna,
- "session_uuid",
- 0,
- INT32_MIN,
- INT32_MAX,
- "Session UUID",
- "Session UUID of the data-block to assign",
- INT32_MIN,
- INT32_MAX);
+ prop = RNA_def_int(ot->srna,
+ "session_uuid",
+ 0,
+ INT32_MIN,
+ INT32_MAX,
+ "Session UUID",
+ "Session UUID of the data-block to assign",
+ INT32_MIN,
+ INT32_MAX);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
}
/** \} */
@@ -1064,3 +1048,5 @@ void NODE_OT_new_node_tree(wmOperatorType *ot)
}
/** \} */
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_context_path.cc b/source/blender/editors/space_node/node_context_path.cc
index 2f3855fd654..cab7cbf10be 100644
--- a/source/blender/editors/space_node/node_context_path.cc
+++ b/source/blender/editors/space_node/node_context_path.cc
@@ -45,11 +45,11 @@
#include "node_intern.hh"
-struct Mesh;
struct Curve;
struct Light;
-struct World;
struct Material;
+struct Mesh;
+struct World;
namespace blender::ed::space_node {
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index d68f16f6197..82da890fa9b 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -88,13 +88,6 @@
#include "node_intern.hh" /* own include */
-using blender::Array;
-using blender::float2;
-using blender::Map;
-using blender::Set;
-using blender::Span;
-using blender::Vector;
-using blender::VectorSet;
using blender::fn::CPPType;
using blender::fn::FieldCPPType;
using blender::fn::FieldInput;
@@ -115,6 +108,8 @@ float ED_node_grid_size()
void ED_node_tree_update(const bContext *C)
{
+ using namespace blender::ed::space_node;
+
SpaceNode *snode = CTX_wm_space_node(C);
if (snode) {
snode_set_context(*C);
@@ -176,34 +171,7 @@ 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);
- }
-}
+namespace blender::ed::space_node {
static bool compare_nodes(const bNode *a, const bNode *b)
{
@@ -261,14 +229,14 @@ static bool compare_nodes(const bNode *a, const bNode *b)
return false;
}
-void ED_node_sort(bNodeTree *ntree)
+void node_sort(bNodeTree &ntree)
{
/* Merge sort is the algorithm of choice here. */
- int totnodes = BLI_listbase_count(&ntree->nodes);
+ int totnodes = BLI_listbase_count(&ntree.nodes);
int k = 1;
while (k < totnodes) {
- bNode *first_a = (bNode *)ntree->nodes.first;
+ bNode *first_a = (bNode *)ntree.nodes.first;
bNode *first_b = first_a;
do {
@@ -295,8 +263,8 @@ void ED_node_sort(bNodeTree *ntree)
bNode *tmp = node_b;
node_b = node_b->next;
b++;
- BLI_remlink(&ntree->nodes, tmp);
- BLI_insertlinkbefore(&ntree->nodes, node_a, tmp);
+ BLI_remlink(&ntree.nodes, tmp);
+ BLI_insertlinkbefore(&ntree.nodes, node_a, tmp);
}
}
@@ -365,6 +333,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 +349,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 +450,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,
@@ -1096,8 +1068,12 @@ static void node_socket_draw_nested(const bContext &C,
UI_block_emboss_set(&block, old_emboss);
}
+} // namespace blender::ed::space_node
+
void ED_node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[4], float scale)
{
+ using namespace blender::ed::space_node;
+
const float size = 2.25f * NODE_SOCKSIZE * scale;
rcti draw_rect = *rect;
float outline_color[4] = {0};
@@ -1144,6 +1120,8 @@ void ED_node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[
GPU_blend(state);
}
+namespace blender::ed::space_node {
+
/* ************** Socket callbacks *********** */
static void node_draw_preview_background(rctf *rect)
@@ -1194,17 +1172,17 @@ static void node_draw_preview(bNodePreview *preview, rctf *prv)
GPU_blend(GPU_BLEND_ALPHA);
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- immDrawPixelsTex(&state,
- draw_rect.xmin,
- draw_rect.ymin,
- preview->xsize,
- preview->ysize,
- GPU_RGBA8,
- true,
- preview->rect,
- scale,
- scale,
- nullptr);
+ immDrawPixelsTexTiled(&state,
+ draw_rect.xmin,
+ draw_rect.ymin,
+ preview->xsize,
+ preview->ysize,
+ GPU_RGBA8,
+ true,
+ preview->rect,
+ scale,
+ scale,
+ nullptr);
GPU_blend(GPU_BLEND_NONE);
@@ -2405,7 +2383,6 @@ static void node_update_nodetree(const bContext &C,
{
/* Make sure socket "used" tags are correct, for displaying value buttons. */
SpaceNode *snode = CTX_wm_space_node(&C);
- ntreeTagUsedSockets(&ntree);
count_multi_input_socket_links(ntree, *snode);
@@ -2414,9 +2391,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 +2407,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,
@@ -2469,7 +2455,7 @@ static void frame_node_draw_label(const bNodeTree &ntree,
const bool has_label = node.label[0] != '\0';
if (has_label) {
BLF_position(fontid, x, y, 0);
- BLF_draw(fontid, label, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw(fontid, label, sizeof(label));
}
/* draw text body */
@@ -2896,3 +2882,5 @@ void node_draw_space(const bContext &C, ARegion &region)
/* Scrollers. */
UI_view2d_scrollers_draw(&v2d, nullptr);
}
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc
index fb90e2bfe50..6275e7e4656 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"
@@ -75,9 +76,9 @@
#include "NOD_texture.h"
#include "node_intern.hh" /* own include */
-#define USE_ESC_COMPO
+namespace blender::ed::space_node {
-using blender::float2;
+#define USE_ESC_COMPO
/* ***************** composite job manager ********************** */
@@ -318,8 +319,12 @@ static void compo_startjob(void *cjv,
ntree->progress = nullptr;
}
+} // namespace blender::ed::space_node
+
void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene *scene_owner)
{
+ using namespace blender::ed::space_node;
+
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -342,7 +347,7 @@ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene
"Compositing",
WM_JOB_EXCL_RENDER | WM_JOB_PROGRESS,
WM_JOB_TYPE_COMPOSITE);
- CompoJob *cj = (CompoJob *)MEM_callocN(sizeof(CompoJob), "compo job");
+ CompoJob *cj = MEM_cnew<CompoJob>("compo job");
/* customdata for preview thread */
cj->bmain = bmain;
@@ -359,6 +364,8 @@ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
+namespace blender::ed::space_node {
+
/* ***************************************** */
bool composite_node_active(bContext *C)
@@ -383,31 +390,11 @@ bool composite_node_editable(bContext *C)
return false;
}
-void snode_dag_update(bContext &C, SpaceNode &snode)
-{
- Main *bmain = CTX_data_main(&C);
-
- /* 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)
+static void send_notifiers_after_tree_change(ID *id, bNodeTree *ntree)
{
- ID *id = snode.id;
+ WM_main_add_notifier(NC_NODE | NA_EDITED, nullptr);
- 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 +405,40 @@ 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);
}
}
+} // namespace blender::ed::space_node
+
+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) {
+ blender::ed::space_node::send_notifiers_after_tree_change(snode->id, root_ntree);
+ }
+ }
+
+ NodeTreeUpdateExtraParams params = {nullptr};
+ params.tree_changed_fn = [](ID *id, bNodeTree *ntree, void *UNUSED(user_data)) {
+ blender::ed::space_node::send_notifiers_after_tree_change(id, ntree);
+ DEG_id_tag_update(&ntree->id, ID_RECALC_COPY_ON_WRITE);
+ };
+ 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 +487,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 +527,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 +565,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,9 +593,11 @@ 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);
}
+namespace blender::ed::space_node {
+
/**
* Here we set the active tree(s), even called for each redraw now, so keep it fast :)
*/
@@ -628,27 +640,7 @@ 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);
- }
-}
+} // namespace blender::ed::space_node
void ED_node_set_active(
Main *bmain, SpaceNode *snode, bNodeTree *ntree, bNode *node, bool *r_active_texture_changed)
@@ -680,11 +672,6 @@ void ED_node_set_active(
/* tree specific activate calls */
if (ntree->type == NTREE_SHADER) {
- /* when we select a material, active texture is cleared, for buttons */
- if (node->id && ELEM(GS(node->id->name), ID_MA, ID_LA, ID_WO)) {
- nodeClearActiveID(ntree, ID_TE);
- }
-
if (ELEM(node->type,
SH_NODE_OUTPUT_MATERIAL,
SH_NODE_OUTPUT_WORLD,
@@ -697,14 +684,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 +733,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 +750,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 +765,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) {
@@ -824,6 +807,8 @@ void ED_node_post_apply_transform(bContext *UNUSED(C), bNodeTree *UNUSED(ntree))
// node_update_nodetree(C, ntree, 0.0f, 0.0f);
}
+namespace blender::ed::space_node {
+
/* ***************** generic operator functions for nodes ***************** */
#if 0 /* UNUSED */
@@ -931,7 +916,7 @@ static void node_resize_init(bContext *C,
{
SpaceNode *snode = CTX_wm_space_node(C);
- NodeSizeWidget *nsw = (NodeSizeWidget *)MEM_callocN(sizeof(NodeSizeWidget), __func__);
+ NodeSizeWidget *nsw = MEM_cnew<NodeSizeWidget>(__func__);
op->customdata = nsw;
nsw->mxstart = snode->runtime->cursor[0] * UI_DPI_FAC;
@@ -1274,7 +1259,8 @@ bool node_link_is_hidden_or_dimmed(const View2D &v2d, const bNodeLink &link)
/* ****************** Duplicate *********************** */
-static void node_duplicate_reparent_recursive(bNode *node)
+static void node_duplicate_reparent_recursive(const Map<const bNode *, bNode *> &node_map,
+ bNode *node)
{
bNode *parent;
@@ -1284,15 +1270,15 @@ static void node_duplicate_reparent_recursive(bNode *node)
for (parent = node->parent; parent; parent = parent->parent) {
if (parent->flag & SELECT) {
if (!(parent->flag & NODE_TEST)) {
- node_duplicate_reparent_recursive(parent);
+ node_duplicate_reparent_recursive(node_map, parent);
}
break;
}
}
/* reparent node copy to parent copy */
if (parent) {
- nodeDetachNode(node->new_node);
- nodeAttachNode(node->new_node, parent->new_node);
+ nodeDetachNode(node_map.lookup(node));
+ nodeAttachNode(node_map.lookup(node), node_map.lookup(parent));
}
}
@@ -1302,17 +1288,18 @@ 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);
+ Map<const bNode *, bNode *> node_map;
+ Map<const bNodeSocket *, bNodeSocket *> socket_map;
+
bNode *lastnode = (bNode *)ntree->nodes.last;
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);
+ bNode *new_node = blender::bke::node_copy_with_mapping(
+ ntree, *node, LIB_ID_COPY_DEFAULT, true, socket_map);
+ node_map.add_new(node, new_node);
}
/* make sure we don't copy new nodes again! */
@@ -1321,8 +1308,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
}
}
- /* Copy links between selected nodes.
- * NOTE: this depends on correct node->new_node and sock->new_sock pointers from above copy! */
+ /* Copy links between selected nodes. */
bNodeLink *lastlink = (bNodeLink *)ntree->links.last;
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
/* This creates new links between copied nodes.
@@ -1330,13 +1316,13 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
*/
if (link->tonode && (link->tonode->flag & NODE_SELECT) &&
(keep_inputs || (link->fromnode && (link->fromnode->flag & NODE_SELECT)))) {
- bNodeLink *newlink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "bNodeLink");
+ bNodeLink *newlink = MEM_cnew<bNodeLink>("bNodeLink");
newlink->flag = link->flag;
- newlink->tonode = link->tonode->new_node;
- newlink->tosock = link->tosock->new_sock;
+ newlink->tonode = node_map.lookup(link->tonode);
+ newlink->tosock = socket_map.lookup(link->tosock);
if (link->fromnode && (link->fromnode->flag & NODE_SELECT)) {
- newlink->fromnode = link->fromnode->new_node;
- newlink->fromsock = link->fromsock->new_sock;
+ newlink->fromnode = node_map.lookup(link->fromnode);
+ newlink->fromsock = socket_map.lookup(link->fromsock);
}
else {
/* input node not copied, this keeps the original input linked */
@@ -1360,7 +1346,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
/* reparent copied nodes */
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if ((node->flag & SELECT) && !(node->flag & NODE_TEST)) {
- node_duplicate_reparent_recursive(node);
+ node_duplicate_reparent_recursive(node_map, node);
}
/* only has to check old nodes */
@@ -1373,13 +1359,11 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->flag & SELECT) {
/* has been set during copy above */
- bNode *newnode = node->new_node;
+ bNode *newnode = node_map.lookup(node);
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 +1372,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;
}
@@ -1416,7 +1394,7 @@ void NODE_OT_duplicate(wmOperatorType *ot)
ot->srna, "keep_inputs", false, "Keep Inputs", "Keep the input links to duplicated nodes");
}
-bool ED_node_select_check(const ListBase *lb)
+static bool node_select_check(const ListBase *lb)
{
LISTBASE_FOREACH (const bNode *, node, lb) {
if (node->flag & NODE_SELECT) {
@@ -1427,10 +1405,10 @@ bool ED_node_select_check(const ListBase *lb)
return false;
}
-void ED_node_select_all(ListBase *lb, int action)
+void node_select_all(ListBase *lb, int action)
{
if (action == SEL_TOGGLE) {
- if (ED_node_select_check(lb)) {
+ if (node_select_check(lb)) {
action = SEL_DESELECT;
}
else {
@@ -1485,8 +1463,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 +1630,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 +1709,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 +1737,17 @@ 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));
+ BKE_ntree_update_tag_node_mute(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 +1773,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 +1826,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 +1861,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 +1908,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 +1957,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 +2024,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;
}
@@ -2096,18 +2053,15 @@ void NODE_OT_output_file_move_active_socket(wmOperatorType *ot)
static int node_copy_color_exec(bContext *C, wmOperator *UNUSED(op))
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &ntree = *snode.edittree;
- if (!ntree) {
- return OPERATOR_CANCELLED;
- }
- bNode *node = nodeGetActive(ntree);
+ bNode *node = nodeGetActive(&ntree);
if (!node) {
return OPERATOR_CANCELLED;
}
- LISTBASE_FOREACH (bNode *, node_iter, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node_iter, &ntree.nodes) {
if (node_iter->flag & NODE_SELECT && node_iter != node) {
if (node->flag & NODE_CUSTOM_COLOR) {
node_iter->flag |= NODE_CUSTOM_COLOR;
@@ -2119,7 +2073,7 @@ static int node_copy_color_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- ED_node_sort(ntree);
+ node_sort(ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
return OPERATOR_FINISHED;
@@ -2153,47 +2107,48 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op))
BKE_node_clipboard_clear();
BKE_node_clipboard_init(ntree);
+ Map<const bNode *, bNode *> node_map;
+ Map<const bNodeSocket *, bNodeSocket *> socket_map;
+
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->flag & SELECT) {
/* No ID refcounting, this node is virtual,
* detached from any actual Blender data currently. */
- bNode *new_node = BKE_node_copy_store_new_pointers(
- nullptr, node, LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN);
- BKE_node_clipboard_add_node(new_node);
+ bNode *new_node = blender::bke::node_copy_with_mapping(nullptr,
+ *node,
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_MAIN,
+ false,
+ socket_map);
+ node_map.add_new(node, new_node);
}
}
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->flag & SELECT) {
- bNode *new_node = node->new_node;
-
- /* ensure valid pointers */
- if (new_node->parent) {
- /* parent pointer must be redirected to new node or detached if parent is
- * not copied */
- if (new_node->parent->flag & NODE_SELECT) {
- new_node->parent = new_node->parent->new_node;
- }
- else {
- nodeDetachNode(new_node);
- }
+ for (bNode *new_node : node_map.values()) {
+ BKE_node_clipboard_add_node(new_node);
+
+ /* Parent pointer must be redirected to new node or detached if parent is not copied. */
+ if (new_node->parent) {
+ if (node_map.contains(new_node->parent)) {
+ new_node->parent = node_map.lookup(new_node->parent);
+ }
+ else {
+ nodeDetachNode(new_node);
}
}
}
- /* Copy links between selected nodes.
- * NOTE: this depends on correct node->new_node and sock->new_sock pointers from above copy! */
-
+ /* Copy links between selected nodes. */
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- /* This creates new links between copied nodes. */
- if (link->tonode && (link->tonode->flag & NODE_SELECT) && link->fromnode &&
- (link->fromnode->flag & NODE_SELECT)) {
- bNodeLink *newlink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "bNodeLink");
+ BLI_assert(link->tonode);
+ BLI_assert(link->fromnode);
+ if (link->tonode->flag & NODE_SELECT && link->fromnode->flag & NODE_SELECT) {
+ bNodeLink *newlink = MEM_cnew<bNodeLink>(__func__);
newlink->flag = link->flag;
- newlink->tonode = link->tonode->new_node;
- newlink->tosock = link->tosock->new_sock;
- newlink->fromnode = link->fromnode->new_node;
- newlink->fromsock = link->fromsock->new_sock;
+ newlink->tonode = node_map.lookup(link->tonode);
+ newlink->tosock = socket_map.lookup(link->tosock);
+ newlink->fromnode = node_map.lookup(link->fromnode);
+ newlink->fromsock = socket_map.lookup(link->fromsock);
BKE_node_clipboard_add_link(newlink);
}
@@ -2288,35 +2243,38 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
}
mul_v2_fl(center, 1.0 / num_nodes);
+ Map<const bNode *, bNode *> node_map;
+ Map<const bNodeSocket *, bNodeSocket *> socket_map;
+
/* copy nodes from clipboard */
LISTBASE_FOREACH (bNode *, node, clipboard_nodes_lb) {
- bNode *new_node = BKE_node_copy_store_new_pointers(ntree, node, LIB_ID_COPY_DEFAULT);
+ bNode *new_node = blender::bke::node_copy_with_mapping(
+ ntree, *node, LIB_ID_COPY_DEFAULT, true, socket_map);
+ node_map.add_new(node, new_node);
+ }
+ for (bNode *new_node : node_map.values()) {
/* pasted nodes are selected */
nodeSetSelected(new_node, true);
- }
- /* reparent copied nodes */
- LISTBASE_FOREACH (bNode *, node, clipboard_nodes_lb) {
- bNode *new_node = node->new_node;
+ /* The parent pointer must be redirected to new node. */
if (new_node->parent) {
- new_node->parent = new_node->parent->new_node;
+ if (node_map.contains(new_node->parent)) {
+ new_node->parent = node_map.lookup(new_node->parent);
+ }
}
}
LISTBASE_FOREACH (bNodeLink *, link, clipboard_links_lb) {
nodeAddLink(ntree,
- link->fromnode->new_node,
- link->fromsock->new_sock,
- link->tonode->new_node,
- link->tosock->new_sock);
+ node_map.lookup(link->fromnode),
+ socket_map.lookup(link->fromsock),
+ node_map.lookup(link->tonode),
+ socket_map.lookup(link->tosock));
}
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 +2342,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 +2389,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 +2440,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 +2449,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 +2560,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 +2792,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 +2832,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 +2877,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 +2923,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;
}
@@ -2996,3 +2942,4 @@ void NODE_OT_cryptomatte_layer_remove(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+} // namespace blender::ed::space_node
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..542e6fd748f 100644
--- a/source/blender/editors/space_node/node_geometry_attribute_search.cc
+++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc
@@ -46,13 +46,11 @@
#include "node_intern.hh"
-using blender::IndexRange;
-using blender::Map;
-using blender::Set;
-using blender::StringRef;
namespace geo_log = blender::nodes::geometry_nodes_eval_log;
using geo_log::GeometryAttributeInfo;
+namespace blender::ed::space_node {
+
struct AttributeSearchData {
const bNodeTree *tree;
const bNode *node;
@@ -125,8 +123,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);
@@ -139,3 +137,5 @@ void node_geometry_add_attribute_search_button(const bContext &UNUSED(C),
attribute_search_exec_fn,
nullptr);
}
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_gizmo.cc b/source/blender/editors/space_node/node_gizmo.cc
index 717f4d2f4f9..8c60d100b26 100644
--- a/source/blender/editors/space_node/node_gizmo.cc
+++ b/source/blender/editors/space_node/node_gizmo.cc
@@ -43,6 +43,8 @@
#include "node_intern.hh"
+namespace blender::ed::space_node {
+
/* -------------------------------------------------------------------- */
/** \name Local Utilities
* \{ */
@@ -292,7 +294,11 @@ static void gizmo_node_crop_prop_matrix_set(const wmGizmo *gz,
const bool ny = rct.ymin > rct.ymax;
BLI_rctf_resize(&rct, fabsf(matrix[0][0]), fabsf(matrix[1][1]));
BLI_rctf_recenter(&rct, (matrix[3][0] / dims[0]) + 0.5f, (matrix[3][1] / dims[1]) + 0.5f);
- const rctf rct_isect{0, 0, 1, 1};
+ rctf rct_isect{};
+ rct_isect.xmin = 0;
+ rct_isect.xmax = 1;
+ rct_isect.ymin = 0;
+ rct_isect.ymax = 1;
BLI_rctf_isect(&rct_isect, &rct, &rct);
if (nx) {
SWAP(float, rct.xmin, rct.xmax);
@@ -380,7 +386,7 @@ static void WIDGETGROUP_node_crop_refresh(const bContext *C, wmGizmoGroup *gzgro
params.value_get_fn = gizmo_node_crop_prop_matrix_get;
params.value_set_fn = gizmo_node_crop_prop_matrix_set;
params.range_get_fn = nullptr;
- params.user_data = snode;
+ params.user_data = node;
WM_gizmo_target_property_def_func(gz, "matrix", &params);
}
else {
@@ -632,3 +638,5 @@ void NODE_GGT_backdrop_corner_pin(wmGizmoGroupType *gzgt)
}
/** \} */
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_group.cc b/source/blender/editors/space_node/node_group.cc
index 704ffe1e478..73e419d667a 100644
--- a/source/blender/editors/space_node/node_group.cc
+++ b/source/blender/editors/space_node/node_group.cc
@@ -28,10 +28,11 @@
#include "DNA_anim_types.h"
#include "DNA_node_types.h"
-#include "BLI_float2.hh"
#include "BLI_linklist.h"
#include "BLI_listbase.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_string.h"
+#include "BLI_vector.hh"
#include "BLT_translation.h"
@@ -40,6 +41,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"
@@ -60,7 +62,7 @@
#include "NOD_socket.h"
#include "node_intern.hh" /* own include */
-using blender::float2;
+namespace blender::ed::space_node {
/* -------------------------------------------------------------------- */
/** \name Local Utilities
@@ -216,38 +218,34 @@ static void animation_basepath_change_free(AnimationBasePathChange *basepath_cha
MEM_freeN(basepath_change);
}
-/* returns 1 if its OK */
-static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
+/**
+ * \return True if successful.
+ */
+static bool node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
{
- /* Clear new pointers, set in #ntreeCopyTree_ex_new_pointers. */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- node->new_node = nullptr;
- }
-
ListBase anim_basepaths = {nullptr, nullptr};
- LinkNode *nodes_delayed_free = nullptr;
- bNodeTree *ngroup = (bNodeTree *)gnode->id;
+ Vector<bNode *> nodes_delayed_free;
+ const bNodeTree *ngroup = reinterpret_cast<const bNodeTree *>(gnode->id);
- /* wgroup is a temporary copy of the NodeTree we're merging in
- * - all of wgroup's nodes are copied across to their new home
- * - ngroup (i.e. the source NodeTree) is left unscathed
- * - temp copy. do change ID usercount for the copies
+ /* `wgroup` is a temporary copy of the #NodeTree we're merging in
+ * - All of wgroup's nodes are copied across to their new home.
+ * - `ngroup` (i.e. the source NodeTree) is left unscathed.
+ * - Temp copy. do change ID user-count for the copies.
*/
- bNodeTree *wgroup = ntreeCopyTree_ex_new_pointers(ngroup, bmain, true);
+ bNodeTree *wgroup = ntreeCopyTree(bmain, ngroup);
- /* Add the nodes into the ntree */
+ /* Add the nodes into the `ntree`. */
LISTBASE_FOREACH_MUTABLE (bNode *, node, &wgroup->nodes) {
/* Remove interface nodes.
* This also removes remaining links to and from interface nodes.
*/
if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
/* We must delay removal since sockets will reference this node. see: T52092 */
- BLI_linklist_prepend(&nodes_delayed_free, node);
+ nodes_delayed_free.append(node);
}
- /* keep track of this node's RNA "base" path (the part of the path identifying the node)
- * if the old nodetree has animation data which potentially covers this node
- */
+ /* Keep track of this node's RNA "base" path (the part of the path identifying the node)
+ * if the old node-tree has animation data which potentially covers this node. */
const char *old_animation_basepath = nullptr;
if (wgroup->adt) {
PointerRNA ptr;
@@ -258,6 +256,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 +283,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;
@@ -385,17 +385,14 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
}
}
- while (nodes_delayed_free) {
- bNode *node = (bNode *)BLI_linklist_pop(&nodes_delayed_free);
+ for (bNode *node : nodes_delayed_free) {
nodeRemoveNode(bmain, ntree, node, false);
}
/* delete the group instance and dereference group tree */
nodeRemoveNode(bmain, ntree, gnode, true);
- ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
-
- return 1;
+ return true;
}
static int node_group_ungroup_exec(bContext *C, wmOperator *op)
@@ -412,16 +409,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;
}
@@ -457,13 +451,11 @@ static bool node_group_separate_selected(
nodeSetSelected(node, false);
}
- /* clear new pointers, set in BKE_node_copy_ex(). */
- LISTBASE_FOREACH (bNode *, node, &ngroup.nodes) {
- node->new_node = nullptr;
- }
-
ListBase anim_basepaths = {nullptr, nullptr};
+ Map<const bNode *, bNode *> node_map;
+ Map<const bNodeSocket *, bNodeSocket *> socket_map;
+
/* add selected nodes into the ntree */
LISTBASE_FOREACH_MUTABLE (bNode *, node, &ngroup.nodes) {
if (!(node->flag & NODE_SELECT)) {
@@ -479,16 +471,17 @@ static bool node_group_separate_selected(
bNode *newnode;
if (make_copy) {
/* make a copy */
- newnode = BKE_node_copy_store_new_pointers(&ngroup, node, LIB_ID_COPY_DEFAULT);
+ newnode = blender::bke::node_copy_with_mapping(
+ &ngroup, *node, LIB_ID_COPY_DEFAULT, true, socket_map);
+ node_map.add_new(node, newnode);
}
else {
/* use the existing node */
newnode = node;
}
- /* keep track of this node's RNA "base" path (the part of the path identifying the node)
- * if the old nodetree has animation data which potentially covers this node
- */
+ /* Keep track of this node's RNA "base" path (the part of the path identifying the node)
+ * if the old node-tree has animation data which potentially covers this node. */
if (ngroup.adt) {
PointerRNA ptr;
char *path;
@@ -528,10 +521,10 @@ static bool node_group_separate_selected(
/* make a copy of internal links */
if (fromselect && toselect) {
nodeAddLink(&ntree,
- link->fromnode->new_node,
- link->fromsock->new_sock,
- link->tonode->new_node,
- link->tosock->new_sock);
+ node_map.lookup(link->fromnode),
+ socket_map.lookup(link->fromsock),
+ node_map.lookup(link->tonode),
+ socket_map.lookup(link->tosock));
}
}
else {
@@ -558,9 +551,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 +607,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;
}
@@ -789,9 +779,8 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree,
/* move nodes over */
LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree.nodes) {
if (node_group_make_use_node(*node, gnode)) {
- /* keep track of this node's RNA "base" path (the part of the pat identifying the node)
- * if the old nodetree has animation data which potentially covers this node
- */
+ /* Keep track of this node's RNA "base" path (the part of the pat identifying the node)
+ * if the old node-tree has animation data which potentially covers this node. */
if (ntree.adt) {
PointerRNA ptr;
char *path;
@@ -812,6 +801,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 +974,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,
@@ -1004,7 +990,7 @@ static bNode *node_group_make_from_selected(const bContext &C,
return nullptr;
}
- /* new nodetree */
+ /* New node-tree. */
bNodeTree *ngroup = ntreeAddTree(bmain, "NodeGroup", ntreetype);
/* make group node */
@@ -1016,9 +1002,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 +1030,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 +1086,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;
}
@@ -1133,3 +1107,5 @@ void NODE_OT_group_insert(wmOperatorType *ot)
}
/** \} */
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh
index f3ba405c6d0..c161fc70402 100644
--- a/source/blender/editors/space_node/node_intern.hh
+++ b/source/blender/editors/space_node/node_intern.hh
@@ -23,7 +23,7 @@
#pragma once
-#include "BLI_float2.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_vector.hh"
#include "BKE_node.h"
@@ -45,19 +45,39 @@ struct wmGizmoGroupType;
struct wmKeyConfig;
struct wmWindow;
+/* Outside of blender namespace to avoid Python documentation build error with `ctypes`. */
+extern const char *node_context_dir[];
+
+namespace blender::ed::space_node {
+
/** Temporary data used in node link drag modal operator. */
struct bNodeLinkDrag {
/** Links dragged by the operator. */
- blender::Vector<bNodeLink *> links;
+ Vector<bNodeLink *> links;
bool from_multi_input_socket;
- int in_out;
+ eNodeSocketInOut in_out;
+
+ /** Draw handler for the "+" icon when dragging a link in empty space. */
+ void *draw_handle;
/** Temporarily stores the last picked link from multi-input socket operator. */
- struct bNodeLink *last_picked_multi_input_socket_link;
+ bNodeLink *last_picked_multi_input_socket_link;
- /** Temporarily stores the last hovered socket for multi-input socket operator.
- * Store it to recalculate sorting after it is no longer hovered. */
- struct bNode *last_node_hovered_while_dragging_a_link;
+ /**
+ * Temporarily stores the last hovered socket for multi-input socket operator.
+ * Store it to recalculate sorting after it is no longer hovered.
+ */
+ bNode *last_node_hovered_while_dragging_a_link;
+
+ /* The cursor position, used for drawing a + icon when dragging a node link. */
+ std::array<int, 2> cursor;
+
+ /** The node the drag started at. */
+ bNode *start_node;
+ /** The socket the drag started at. */
+ bNodeSocket *start_socket;
+ /** The number of links connected to the #start_socket when the drag started. */
+ int start_link_count;
/* Data for edge panning */
View2DEdgePanData pan_data;
@@ -67,7 +87,7 @@ struct SpaceNode_Runtime {
float aspect;
/** Mouse position for drawing socket-less links and adding nodes. */
- blender::float2 cursor;
+ float2 cursor;
/** For auto compositing. */
bool recalc;
@@ -92,15 +112,15 @@ ENUM_OPERATORS(NodeResizeDirection, NODE_RESIZE_LEFT);
/**
* Transform between View2Ds in the tree path.
*/
-blender::float2 space_node_group_offset(const SpaceNode &snode);
+float2 space_node_group_offset(const SpaceNode &snode);
float node_socket_calculate_height(const bNodeSocket &socket);
-blender::float2 node_link_calculate_multi_input_position(const blender::float2 &socket_position,
- int index,
- int total_inputs);
+float2 node_link_calculate_multi_input_position(const float2 &socket_position,
+ int index,
+ int total_inputs);
int node_get_resize_cursor(NodeResizeDirection directions);
-NodeResizeDirection node_get_resize_direction(const bNode *node, const int x, const int y);
+NodeResizeDirection node_get_resize_direction(const bNode *node, int x, int y);
/**
* Usual convention here would be #node_socket_get_color(),
* but that's already used (for setting a color property socket).
@@ -112,22 +132,26 @@ void node_socket_color_get(const bContext &C,
float r_color[4]);
void node_draw_space(const bContext &C, ARegion &region);
-void node_set_cursor(wmWindow &win, SpaceNode &snode, const blender::float2 &cursor);
+/**
+ * Sort nodes by selection: unselected nodes first, then selected,
+ * then the active node at the very end. Relative order is kept intact.
+ */
+void node_sort(bNodeTree &ntree);
+
+void node_set_cursor(wmWindow &win, SpaceNode &snode, const float2 &cursor);
/* DPI scaled coords */
-blender::float2 node_to_view(const bNode &node, const blender::float2 &co);
+float2 node_to_view(const bNode &node, const float2 &co);
void node_to_updated_rect(const bNode &node, rctf &r_rect);
-blender::float2 node_from_view(const bNode &node, const blender::float2 &co);
-
-void node_toolbar_register(ARegionType *art);
+float2 node_from_view(const bNode &node, const float2 &co);
-void node_operatortypes(void);
+void node_operatortypes();
void node_keymap(wmKeyConfig *keyconf);
void node_deselect_all(SpaceNode &snode);
void node_socket_select(bNode *node, bNodeSocket &sock);
-void node_socket_deselect(bNode *node, bNodeSocket &sock, const bool deselect_node);
-void node_deselect_all_input_sockets(SpaceNode &snode, const bool deselect_nodes);
-void node_deselect_all_output_sockets(SpaceNode &snode, const bool deselect_nodes);
+void node_socket_deselect(bNode *node, bNodeSocket &sock, bool deselect_node);
+void node_deselect_all_input_sockets(SpaceNode &snode, bool deselect_nodes);
+void node_deselect_all_output_sockets(SpaceNode &snode, bool deselect_nodes);
void node_select_single(bContext &C, bNode &node);
void NODE_OT_select(wmOperatorType *ot);
@@ -178,7 +202,7 @@ bool node_link_bezier_points(const View2D *v2d,
const SpaceNode *snode,
const bNodeLink &link,
float coord_array[][2],
- const int resol);
+ int resol);
/**
* Return quadratic beziers points for a given nodelink and clip if v2d is not nullptr.
*/
@@ -191,6 +215,8 @@ void draw_nodespace_back_pix(const bContext &C,
SpaceNode &snode,
bNodeInstanceKey parent_key);
+void node_select_all(ListBase *lb, int action);
+
/**
* XXX Does some additional initialization on top of #nodeAddNode
* Can be used with both custom and static nodes,
@@ -216,8 +242,7 @@ void NODE_OT_group_edit(wmOperatorType *ot);
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);
+ const float2 *cursor);
void NODE_OT_link(wmOperatorType *ot);
void NODE_OT_link_make(wmOperatorType *ot);
@@ -234,12 +259,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);
@@ -251,7 +272,7 @@ int node_render_changed_exec(bContext *, wmOperator *);
bool node_find_indicated_socket(SpaceNode &snode,
bNode **nodep,
bNodeSocket **sockp,
- const blender::float2 &cursor,
+ const float2 &cursor,
eNodeSocketInOut in_out);
float node_link_dim_factor(const View2D &v2d, const bNodeLink &link);
bool node_link_is_hidden_or_dimmed(const View2D &v2d, const bNodeLink &link);
@@ -307,8 +328,6 @@ void node_geometry_add_attribute_search_button(const bContext &C,
PointerRNA &socket_ptr,
uiLayout &layout);
-extern const char *node_context_dir[];
-
/* Nodes draw without dpi - the view zoom is flexible. */
#define HIDDEN_RAD (0.75f * U.widget_unit)
#define BASIS_RAD (0.2f * U.widget_unit)
@@ -323,8 +342,11 @@ extern const char *node_context_dir[];
#define NODE_RESIZE_MARGIN (0.20f * U.widget_unit)
#define NODE_LINK_RESOL 12
-namespace blender::ed::space_node {
-
Vector<ui::ContextPathItem> context_path_for_space_node(const bContext &C);
-}
+void invoke_node_link_drag_add_menu(bContext &C,
+ bNode &node,
+ bNodeSocket &socket,
+ const float2 &cursor);
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_ops.cc b/source/blender/editors/space_node/node_ops.cc
index a6264f151e4..2ca475f6948 100644
--- a/source/blender/editors/space_node/node_ops.cc
+++ b/source/blender/editors/space_node/node_ops.cc
@@ -35,6 +35,8 @@
#include "node_intern.hh" /* own include */
+namespace blender::ed::space_node {
+
void node_operatortypes()
{
WM_operatortype_append(NODE_OT_select);
@@ -127,6 +129,17 @@ void node_operatortypes()
WM_operatortype_append(NODE_OT_cryptomatte_layer_remove);
}
+void node_keymap(struct wmKeyConfig *keyconf)
+{
+ /* Entire Editor only ----------------- */
+ WM_keymap_ensure(keyconf, "Node Generic", SPACE_NODE, 0);
+
+ /* Main Region only ----------------- */
+ WM_keymap_ensure(keyconf, "Node Editor", SPACE_NODE, 0);
+}
+
+} // namespace blender::ed::space_node
+
void ED_operatormacros_node()
{
wmOperatorType *ot;
@@ -203,12 +216,3 @@ void ED_operatormacros_node()
WM_operatortype_macro_define(ot, "NODE_OT_links_detach");
WM_operatortype_macro_define(ot, "NODE_OT_translate_attach");
}
-
-void node_keymap(struct wmKeyConfig *keyconf)
-{
- /* Entire Editor only ----------------- */
- WM_keymap_ensure(keyconf, "Node Generic", SPACE_NODE, 0);
-
- /* Main Region only ----------------- */
- WM_keymap_ensure(keyconf, "Node Editor", SPACE_NODE, 0);
-}
diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc
index ce07496068d..fd9420b173d 100644
--- a/source/blender/editors/space_node/node_relationships.cc
+++ b/source/blender/editors/space_node/node_relationships.cc
@@ -34,11 +34,13 @@
#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 */
#include "ED_render.h"
#include "ED_screen.h"
+#include "ED_space_api.h"
#include "ED_spreadsheet.h"
#include "ED_util.h"
@@ -50,6 +52,9 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "GPU_state.h"
+
+#include "UI_interface_icons.h"
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -57,127 +62,12 @@
#include "NOD_node_declaration.hh"
#include "NOD_node_tree_ref.hh"
+#include "NOD_socket_declarations.hh"
+#include "NOD_socket_declarations_geometry.hh"
#include "node_intern.hh" /* own include */
using namespace blender::nodes::node_tree_ref_types;
-using blender::float2;
-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
@@ -206,9 +96,11 @@ static void clear_picking_highlight(ListBase *links)
}
}
-static bNodeLink *create_drag_link(Main &bmain, SpaceNode &snode, bNode &node, bNodeSocket &sock)
+namespace blender::ed::space_node {
+
+static bNodeLink *create_drag_link(bNode &node, bNodeSocket &sock)
{
- bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), __func__);
+ bNodeLink *oplink = MEM_cnew<bNodeLink>(__func__);
if (sock.in_out == SOCK_OUT) {
oplink->fromnode = &node;
oplink->fromsock = &sock;
@@ -218,27 +110,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);
@@ -250,7 +132,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);
}
}
@@ -316,7 +198,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);
}
}
}
@@ -328,7 +210,10 @@ static bool socket_is_available(bNodeTree *UNUSED(ntree), bNodeSocket *sock, con
}
if (!allow_used && (sock->flag & SOCK_IN_USE)) {
- return false;
+ /* Multi input sockets are available (even if used). */
+ if (!(sock->flag & SOCK_MULTI_INPUT)) {
+ return false;
+ }
}
return true;
@@ -558,7 +443,7 @@ static void snode_autoconnect(Main &bmain,
}
if (numlinks > 0) {
- ntreeUpdateTree(&bmain, ntree);
+ BKE_ntree_update_main_tree(&bmain, ntree, nullptr);
}
}
@@ -568,7 +453,7 @@ static void snode_autoconnect(Main &bmain,
/** \name Link Viewer Operator
* \{ */
-namespace blender::ed::nodes::viewer_linking {
+namespace viewer_linking {
/* Depending on the node tree type, different socket types are supported by viewer nodes. */
static bool socket_can_be_viewed(const OutputSocketRef &socket)
@@ -632,7 +517,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;
}
}
@@ -802,7 +687,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);
@@ -811,10 +696,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);
-
+ ED_node_tree_propagate_change(&C, CTX_data_main(&C), &btree);
return OPERATOR_FINISHED;
}
@@ -838,7 +720,7 @@ static int node_link_viewer(const bContext &C, bNode &bnode_to_view)
return link_socket_to_viewer(C, viewer_bnode, bnode_to_view, bsocket_to_view);
}
-} // namespace blender::ed::nodes::viewer_linking
+} // namespace viewer_linking
static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -851,11 +733,11 @@ static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op))
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- if (blender::ed::nodes::viewer_linking::node_link_viewer(*C, *node) == OPERATOR_CANCELLED) {
+ if (viewer_linking::node_link_viewer(*C, *node) == OPERATOR_CANCELLED) {
return OPERATOR_CANCELLED;
}
- snode_notify(*C, snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree);
return OPERATOR_FINISHED;
}
@@ -890,6 +772,83 @@ void NODE_OT_link_viewer(wmOperatorType *ot)
/** \name Add Link Operator
* \{ */
+/**
+ * Check if any of the dragged links are connected to a socket on the side that they are dragged
+ * from.
+ */
+static bool dragged_links_are_detached(const bNodeLinkDrag &nldrag)
+{
+ if (nldrag.in_out == SOCK_OUT) {
+ for (const bNodeLink *link : nldrag.links) {
+ if (link->tonode && link->tosock) {
+ return false;
+ }
+ }
+ }
+ else {
+ for (const bNodeLink *link : nldrag.links) {
+ if (link->fromnode && link->fromsock) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static bool should_create_drag_link_search_menu(const bNodeTree &node_tree,
+ const bNodeLinkDrag &nldrag)
+{
+ /* Custom node trees aren't supported yet. */
+ if (node_tree.type == NTREE_CUSTOM) {
+ return false;
+ }
+ /* Only create the search menu when the drag has not already connected the links to a socket. */
+ if (!dragged_links_are_detached(nldrag)) {
+ return false;
+ }
+ /* Don't create the search menu if the drag is disconnecting a link from an input node. */
+ if (nldrag.start_socket->in_out == SOCK_IN && nldrag.start_link_count > 0) {
+ return false;
+ }
+ /* Don't allow a drag from the "new socket" of a group input node. Handling these
+ * properly in node callbacks increases the complexity too much for now. */
+ if (ELEM(nldrag.start_node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
+ if (nldrag.start_socket->type == SOCK_CUSTOM) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static void draw_draglink_tooltip(const bContext *UNUSED(C), ARegion *UNUSED(region), void *arg)
+{
+ bNodeLinkDrag *nldrag = static_cast<bNodeLinkDrag *>(arg);
+
+ const uchar text_col[4] = {255, 255, 255, 255};
+ const int padding = 4 * UI_DPI_FAC;
+ const float x = nldrag->in_out == SOCK_IN ? nldrag->cursor[0] - 3.3f * padding :
+ nldrag->cursor[0];
+ const float y = nldrag->cursor[1] - 2.0f * UI_DPI_FAC;
+
+ UI_icon_draw_ex(x, y, ICON_ADD, U.inv_dpi_fac, 1.0f, 0.0f, text_col, false);
+}
+
+static void draw_draglink_tooltip_activate(const ARegion &region, bNodeLinkDrag &nldrag)
+{
+ if (nldrag.draw_handle == nullptr) {
+ nldrag.draw_handle = ED_region_draw_cb_activate(
+ region.type, draw_draglink_tooltip, &nldrag, REGION_DRAW_POST_PIXEL);
+ }
+}
+
+static void draw_draglink_tooltip_deactivate(const ARegion &region, bNodeLinkDrag &nldrag)
+{
+ if (nldrag.draw_handle) {
+ ED_region_draw_cb_exit(region.type, nldrag.draw_handle);
+ nldrag.draw_handle = nullptr;
+ }
+}
+
static void node_link_update_header(bContext *C, bNodeLinkDrag *UNUSED(nldrag))
{
char header[UI_MAX_DRAW_STR];
@@ -952,22 +911,14 @@ static void node_remove_extra_links(SpaceNode &snode, bNodeLink &link)
static void node_link_exit(bContext &C, wmOperator &op, const bool apply_links)
{
Main *bmain = CTX_data_main(&C);
+ ARegion &region = *CTX_wm_region(&C);
SpaceNode &snode = *CTX_wm_space_node(&C);
bNodeTree &ntree = *snode.edittree;
bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op.customdata;
- bool do_tag_update = false;
- /* View will be reset if no links connect. */
- bool reset_view = true;
/* 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) {
@@ -983,20 +934,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));
- }
-
- reset_view = false;
}
else {
nodeRemLink(&ntree, link);
@@ -1004,15 +945,14 @@ 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);
- if (reset_view) {
- UI_view2d_edge_pan_cancel(&C, &nldrag->pan_data);
- }
+ /* Ensure draglink tooltip is disabled. */
+ draw_draglink_tooltip_deactivate(*CTX_wm_region(&C), *nldrag);
+
+ ED_workspace_status_text(&C, nullptr);
+ ED_region_tag_redraw(&region);
+ clear_picking_highlight(&snode.edittree->links);
snode.runtime->linkdrag.reset();
}
@@ -1099,12 +1039,15 @@ static void node_link_find_socket(bContext &C, wmOperator &op, const float2 &cur
static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op->customdata;
+ SpaceNode &snode = *CTX_wm_space_node(C);
ARegion *region = CTX_wm_region(C);
UI_view2d_edge_pan_apply_event(C, &nldrag->pan_data, event);
float2 cursor;
UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &cursor.x, &cursor.y);
+ nldrag->cursor[0] = event->mval[0];
+ nldrag->cursor[1] = event->mval[1];
switch (event->type) {
case MOUSEMOVE:
@@ -1117,29 +1060,50 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event)
node_link_update_header(C, nldrag);
ED_region_tag_redraw(region);
}
- break;
+ if (should_create_drag_link_search_menu(*snode.edittree, *nldrag)) {
+ draw_draglink_tooltip_activate(*region, *nldrag);
+ }
+ else {
+ draw_draglink_tooltip_deactivate(*region, *nldrag);
+ }
+ break;
case LEFTMOUSE:
+ if (event->val == KM_RELEASE) {
+ /* Add a search menu for compatible sockets if the drag released on empty space. */
+ if (should_create_drag_link_search_menu(*snode.edittree, *nldrag)) {
+ bNodeLink &link = *nldrag->links.first();
+ if (nldrag->in_out == SOCK_OUT) {
+ invoke_node_link_drag_add_menu(*C, *link.fromnode, *link.fromsock, cursor);
+ }
+ else {
+ invoke_node_link_drag_add_menu(*C, *link.tonode, *link.tosock, cursor);
+ }
+ }
+
+ /* Finish link. */
+ node_link_exit(*C, *op, true);
+ return OPERATOR_FINISHED;
+ }
+ break;
case RIGHTMOUSE:
case MIDDLEMOUSE: {
if (event->val == KM_RELEASE) {
node_link_exit(*C, *op, true);
-
- ED_workspace_status_text(C, nullptr);
- ED_region_tag_redraw(region);
- SpaceNode &snode = *CTX_wm_space_node(C);
- clear_picking_highlight(&snode.edittree->links);
return OPERATOR_FINISHED;
}
break;
}
+ case EVT_ESCKEY: {
+ node_link_exit(*C, *op, true);
+ return OPERATOR_FINISHED;
+ }
}
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)
{
@@ -1148,32 +1112,22 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain,
bNodeSocket *sock;
if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) {
std::unique_ptr<bNodeLinkDrag> nldrag = std::make_unique<bNodeLinkDrag>();
-
- const int num_links = nodeCountSocketLinks(snode.edittree, sock);
+ nldrag->start_node = node;
+ nldrag->start_socket = sock;
+ nldrag->start_link_count = nodeCountSocketLinks(snode.edittree, sock);
int link_limit = nodeSocketLinkLimit(sock);
- if (num_links > 0 && (num_links >= link_limit || detach)) {
+ if (nldrag->start_link_count > 0 && (nldrag->start_link_count >= link_limit || detach)) {
/* dragged links are fixed on input side */
nldrag->in_out = SOCK_IN;
/* detach current links and store them in the operator data */
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode.edittree->links) {
if (link->fromsock == sock) {
- bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link");
+ bNodeLink *oplink = MEM_cnew<bNodeLink>("drag link op link");
*oplink = *link;
oplink->next = oplink->prev = nullptr;
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);
}
@@ -1183,7 +1137,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;
}
@@ -1192,9 +1146,11 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain,
if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) {
std::unique_ptr<bNodeLinkDrag> nldrag = std::make_unique<bNodeLinkDrag>();
nldrag->last_node_hovered_while_dragging_a_link = node;
+ nldrag->start_node = node;
+ nldrag->start_socket = sock;
- const int num_links = nodeCountSocketLinks(snode.edittree, sock);
- if (num_links > 0) {
+ nldrag->start_link_count = nodeCountSocketLinks(snode.edittree, sock);
+ if (nldrag->start_link_count > 0) {
/* dragged links are fixed on output side */
nldrag->in_out = SOCK_OUT;
/* detach current links and store them in the operator data */
@@ -1209,22 +1165,18 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain,
}
if (link_to_pick != nullptr && !nldrag->from_multi_input_socket) {
- bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link");
+ bNodeLink *oplink = MEM_cnew<bNodeLink>("drag link op link");
*oplink = *link_to_pick;
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);
}
}
}
@@ -1232,7 +1184,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;
}
@@ -1255,11 +1207,15 @@ 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);
+ /* Add "+" icon when the link is dragged in empty space. */
+ if (should_create_drag_link_search_menu(*snode.edittree, *nldrag)) {
+ draw_draglink_tooltip_activate(*CTX_wm_region(C), *nldrag);
+ }
snode.runtime->linkdrag = std::move(nldrag);
op->customdata = snode.runtime->linkdrag.get();
@@ -1354,9 +1310,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;
}
@@ -1413,7 +1367,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];
@@ -1448,23 +1401,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;
}
@@ -1510,7 +1454,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];
@@ -1552,10 +1495,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);
}
}
@@ -1568,12 +1507,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;
}
@@ -1624,11 +1558,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;
}
@@ -1654,14 +1584,14 @@ void NODE_OT_links_detach(wmOperatorType *ot)
static int node_parent_set_exec(bContext *C, wmOperator *UNUSED(op))
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
- bNode *frame = nodeGetActive(ntree);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &ntree = *snode.edittree;
+ bNode *frame = nodeGetActive(&ntree);
if (!frame || frame->type != NODE_FRAME) {
return OPERATOR_CANCELLED;
}
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
if (node == frame) {
continue;
}
@@ -1671,7 +1601,7 @@ static int node_parent_set_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- ED_node_sort(ntree);
+ node_sort(ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
return OPERATOR_FINISHED;
@@ -1768,7 +1698,7 @@ static int node_join_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- ED_node_sort(&ntree);
+ node_sort(ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
return OPERATOR_FINISHED;
@@ -1795,15 +1725,15 @@ void NODE_OT_join(wmOperatorType *ot)
/** \name Attach Operator
* \{ */
-static bNode *node_find_frame_to_attach(ARegion *region,
- const bNodeTree *ntree,
+static bNode *node_find_frame_to_attach(ARegion &region,
+ const bNodeTree &ntree,
const int mouse_xy[2])
{
/* convert mouse coordinates to v2d space */
float cursor[2];
- UI_view2d_region_to_view(&region->v2d, UNPACK2(mouse_xy), &cursor[0], &cursor[1]);
+ UI_view2d_region_to_view(&region.v2d, UNPACK2(mouse_xy), &cursor[0], &cursor[1]);
- LISTBASE_FOREACH_BACKWARD (bNode *, frame, &ntree->nodes) {
+ LISTBASE_FOREACH_BACKWARD (bNode *, frame, &ntree.nodes) {
/* skip selected, those are the nodes we want to attach */
if ((frame->type != NODE_FRAME) || (frame->flag & NODE_SELECT)) {
continue;
@@ -1818,13 +1748,13 @@ static bNode *node_find_frame_to_attach(ARegion *region,
static int node_attach_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
- ARegion *region = CTX_wm_region(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
+ ARegion &region = *CTX_wm_region(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &ntree = *snode.edittree;
bNode *frame = node_find_frame_to_attach(region, ntree, event->mval);
if (frame) {
- LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree.nodes) {
if (node->flag & NODE_SELECT) {
if (node->parent == nullptr) {
/* disallow moving a parent into its child */
@@ -1854,7 +1784,7 @@ static int node_attach_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent
}
}
- ED_node_sort(ntree);
+ node_sort(ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
return OPERATOR_FINISHED;
@@ -1914,23 +1844,23 @@ static void node_detach_recursive(bNode *node)
/* detach the root nodes in the current selection */
static int node_detach_exec(bContext *C, wmOperator *UNUSED(op))
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &ntree = *snode.edittree;
/* reset tags */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
node->done = 0;
}
/* detach nodes recursively
* relative order is preserved here!
*/
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
if (!(node->done & NODE_DETACH_DONE)) {
node_detach_recursive(node);
}
}
- ED_node_sort(ntree);
+ node_sort(ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
return OPERATOR_FINISHED;
@@ -2015,8 +1945,12 @@ static bool ed_node_link_conditions(ScrArea *area,
return true;
}
+} // namespace blender::ed::space_node
+
void ED_node_link_intersect_test(ScrArea *area, int test)
{
+ using namespace blender::ed::space_node;
+
bNode *select;
SpaceNode *snode;
if (!ed_node_link_conditions(area, test, &snode, &select)) {
@@ -2076,6 +2010,8 @@ void ED_node_link_intersect_test(ScrArea *area, int test)
}
}
+namespace blender::ed::space_node {
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -2115,20 +2051,17 @@ static int get_main_socket_priority(const bNodeSocket *socket)
/** Get the "main" socket based on the node declaration or an heuristic. */
static bNodeSocket *get_main_socket(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out)
{
- using namespace blender;
- using namespace blender::nodes;
-
ListBase *sockets = (in_out == SOCK_IN) ? &node.inputs : &node.outputs;
/* Try to get the main socket based on the socket declaration. */
nodeDeclarationEnsure(&ntree, &node);
- const NodeDeclaration *node_decl = node.declaration;
+ const nodes::NodeDeclaration *node_decl = node.declaration;
if (node_decl != nullptr) {
- Span<SocketDeclarationPtr> socket_decls = (in_out == SOCK_IN) ? node_decl->inputs() :
- node_decl->outputs();
+ Span<nodes::SocketDeclarationPtr> socket_decls = (in_out == SOCK_IN) ? node_decl->inputs() :
+ node_decl->outputs();
int index;
LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, sockets, index) {
- const SocketDeclaration &socket_decl = *socket_decls[index];
+ const nodes::SocketDeclaration &socket_decl = *socket_decls[index];
if (nodeSocketIsHidden(socket)) {
continue;
}
@@ -2305,7 +2238,7 @@ static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd,
/* frame attachment wasn't handled yet
* so we search the frame that the node will be attached to later */
- insert.parent = node_find_frame_to_attach(region, ntree, mouse_xy);
+ insert.parent = node_find_frame_to_attach(*region, *ntree, mouse_xy);
/* this makes sure nodes are also correctly offset when inserting a node on top of a frame
* without actually making it a part of the frame (because mouse isn't intersecting it)
@@ -2492,12 +2425,16 @@ void NODE_OT_insert_offset(wmOperatorType *ot)
/** \} */
+} // namespace blender::ed::space_node
+
/* -------------------------------------------------------------------- */
/** \name Note Link Insert
* \{ */
void ED_node_link_insert(Main *bmain, ScrArea *area)
{
+ using namespace blender::ed::space_node;
+
bNode *select;
SpaceNode *snode;
if (!ed_node_link_conditions(area, true, &snode, &select)) {
@@ -2534,8 +2471,7 @@ void ED_node_link_insert(Main *bmain, ScrArea *area)
/* set up insert offset data, it needs stuff from here */
if ((snode->flag & SNODE_SKIP_INSOFFSET) == 0) {
- NodeInsertOfsData *iofsd = (NodeInsertOfsData *)MEM_callocN(sizeof(NodeInsertOfsData),
- __func__);
+ NodeInsertOfsData *iofsd = MEM_cnew<NodeInsertOfsData>(__func__);
iofsd->insert = select;
iofsd->prev = link->fromnode;
@@ -2544,10 +2480,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_select.cc b/source/blender/editors/space_node/node_select.cc
index 334ca1f76ee..2751a53e8af 100644
--- a/source/blender/editors/space_node/node_select.cc
+++ b/source/blender/editors/space_node/node_select.cc
@@ -62,7 +62,7 @@
#include "node_intern.hh" /* own include */
-using blender::float2;
+namespace blender::ed::space_node {
/**
* Function to detect if there is a visible view3d that uses workbench in texture mode.
@@ -111,11 +111,13 @@ static bNode *node_under_mouse_select(bNodeTree &ntree, int mx, int my)
static bNode *node_under_mouse_tweak(bNodeTree &ntree, const float2 &mouse)
{
+ using namespace blender::math;
+
LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree.nodes) {
if (node->type == NODE_REROUTE) {
bNodeSocket *socket = (bNodeSocket *)node->inputs.first;
const float2 location{socket->locx, socket->locy};
- if (float2::distance(mouse, location) < 24.0f) {
+ if (distance(mouse, location) < 24.0f) {
return node;
}
}
@@ -278,57 +280,51 @@ void node_deselect_all_output_sockets(SpaceNode &snode, const bool deselect_node
/* Return true if we need redraw, otherwise false. */
-static bool node_select_grouped_type(SpaceNode *snode, bNode *node_act)
+static bool node_select_grouped_type(bNodeTree &node_tree, bNode &node_act)
{
- bNode *node;
bool changed = false;
-
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
if ((node->flag & SELECT) == 0) {
- if (node->type == node_act->type) {
+ if (node->type == node_act.type) {
nodeSetSelected(node, true);
changed = true;
}
}
}
-
return changed;
}
-static bool node_select_grouped_color(SpaceNode *snode, bNode *node_act)
+static bool node_select_grouped_color(bNodeTree &node_tree, bNode &node_act)
{
bool changed = false;
-
- LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
if ((node->flag & SELECT) == 0) {
- if (compare_v3v3(node->color, node_act->color, 0.005f)) {
+ if (compare_v3v3(node->color, node_act.color, 0.005f)) {
nodeSetSelected(node, true);
changed = true;
}
}
}
-
return changed;
}
-static bool node_select_grouped_name(SpaceNode *snode, bNode *node_act, const bool from_right)
+static bool node_select_grouped_name(bNodeTree &node_tree, bNode &node_act, const bool from_right)
{
- bNode *node;
bool changed = false;
const uint delims[] = {'.', '-', '_', '\0'};
size_t pref_len_act, pref_len_curr;
const char *sep, *suf_act, *suf_curr;
pref_len_act = BLI_str_partition_ex_utf8(
- node_act->name, nullptr, delims, &sep, &suf_act, from_right);
+ node_act.name, nullptr, delims, &sep, &suf_act, from_right);
/* NOTE: in case we are searching for suffix, and found none, use whole name as suffix. */
if (from_right && !(sep && suf_act)) {
pref_len_act = 0;
- suf_act = node_act->name;
+ suf_act = node_act.name;
}
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
if (node->flag & SELECT) {
continue;
}
@@ -343,7 +339,7 @@ static bool node_select_grouped_name(SpaceNode *snode, bNode *node_act, const bo
if ((from_right && STREQ(suf_act, suf_curr)) ||
(!from_right && (pref_len_act == pref_len_curr) &&
- STREQLEN(node_act->name, node->name, pref_len_act))) {
+ STREQLEN(node_act.name, node->name, pref_len_act))) {
nodeSetSelected(node, true);
changed = true;
}
@@ -361,20 +357,20 @@ enum {
static int node_select_grouped_exec(bContext *C, wmOperator *op)
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNode *node_act = nodeGetActive(snode->edittree);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &node_tree = *snode.edittree;
+ bNode *node_act = nodeGetActive(snode.edittree);
if (node_act == nullptr) {
return OPERATOR_CANCELLED;
}
- bNode *node;
bool changed = false;
const bool extend = RNA_boolean_get(op->ptr, "extend");
const int type = RNA_enum_get(op->ptr, "type");
if (!extend) {
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
nodeSetSelected(node, false);
}
}
@@ -382,23 +378,23 @@ static int node_select_grouped_exec(bContext *C, wmOperator *op)
switch (type) {
case NODE_SELECT_GROUPED_TYPE:
- changed = node_select_grouped_type(snode, node_act);
+ changed = node_select_grouped_type(node_tree, *node_act);
break;
case NODE_SELECT_GROUPED_COLOR:
- changed = node_select_grouped_color(snode, node_act);
+ changed = node_select_grouped_color(node_tree, *node_act);
break;
case NODE_SELECT_GROUPED_PREFIX:
- changed = node_select_grouped_name(snode, node_act, false);
+ changed = node_select_grouped_name(node_tree, *node_act, false);
break;
case NODE_SELECT_GROUPED_SUFIX:
- changed = node_select_grouped_name(snode, node_act, true);
+ changed = node_select_grouped_name(node_tree, *node_act, true);
break;
default:
break;
}
if (changed) {
- ED_node_sort(snode->edittree);
+ node_sort(node_tree);
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
return OPERATOR_FINISHED;
}
@@ -449,26 +445,26 @@ void NODE_OT_select_grouped(wmOperatorType *ot)
void node_select_single(bContext &C, bNode &node)
{
Main *bmain = CTX_data_main(&C);
- SpaceNode *snode = CTX_wm_space_node(&C);
+ SpaceNode &snode = *CTX_wm_space_node(&C);
+ bNodeTree &node_tree = *snode.edittree;
const Object *ob = CTX_data_active_object(&C);
const Scene *scene = CTX_data_scene(&C);
const wmWindowManager *wm = CTX_wm_manager(&C);
bool active_texture_changed = false;
- bNode *tnode;
- for (tnode = (bNode *)snode->edittree->nodes.first; tnode; tnode = tnode->next) {
- if (tnode != &node) {
- nodeSetSelected(tnode, false);
+ LISTBASE_FOREACH (bNode *, node_iter, &node_tree.nodes) {
+ if (node_iter != &node) {
+ nodeSetSelected(node_iter, false);
}
}
nodeSetSelected(&node, true);
- ED_node_set_active(bmain, snode, snode->edittree, &node, &active_texture_changed);
- ED_node_set_active_viewer_key(snode);
+ ED_node_set_active(bmain, &snode, &node_tree, &node, &active_texture_changed);
+ ED_node_set_active_viewer_key(&snode);
- ED_node_sort(snode->edittree);
+ node_sort(node_tree);
if (active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) {
- DEG_id_tag_update(&snode->edittree->id, ID_RECALC_COPY_ON_WRITE);
+ DEG_id_tag_update(&node_tree.id, ID_RECALC_COPY_ON_WRITE);
}
WM_event_add_notifier(&C, NC_NODE | NA_SELECTED, nullptr);
@@ -609,7 +605,7 @@ static int node_mouse_select(bContext *C,
ED_spreadsheet_context_paths_set_geometry_node(&bmain, &snode, node);
}
ED_node_set_active_viewer_key(&snode);
- ED_node_sort(snode.edittree);
+ node_sort(*snode.edittree);
if ((active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) ||
viewer_node_changed) {
DEG_id_tag_update(&snode.edittree->id, ID_RECALC_COPY_ON_WRITE);
@@ -676,20 +672,21 @@ void NODE_OT_select(wmOperatorType *ot)
static int node_box_select_exec(bContext *C, wmOperator *op)
{
- SpaceNode *snode = CTX_wm_space_node(C);
- ARegion *region = CTX_wm_region(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &node_tree = *snode.edittree;
+ const ARegion &region = *CTX_wm_region(C);
rctf rectf;
WM_operator_properties_border_to_rctf(op, &rectf);
- UI_view2d_region_to_view_rctf(&region->v2d, &rectf, &rectf);
+ UI_view2d_region_to_view_rctf(&region.v2d, &rectf, &rectf);
const eSelectOp sel_op = (eSelectOp)RNA_enum_get(op->ptr, "mode");
const bool select = (sel_op != SEL_OP_SUB);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- ED_node_select_all(&snode->edittree->nodes, SEL_DESELECT);
+ node_select_all(&node_tree.nodes, SEL_DESELECT);
}
- LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
bool is_inside;
if (node->type == NODE_FRAME) {
is_inside = BLI_rctf_inside_rctf(&rectf, &node->totr);
@@ -703,7 +700,7 @@ static int node_box_select_exec(bContext *C, wmOperator *op)
}
}
- ED_node_sort(snode->edittree);
+ node_sort(node_tree);
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
@@ -773,7 +770,7 @@ static int node_circleselect_exec(bContext *C, wmOperator *op)
WM_gesture_is_modal_first((const wmGesture *)op->customdata));
const bool select = (sel_op != SEL_OP_SUB);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- ED_node_select_all(&snode->edittree->nodes, SEL_DESELECT);
+ node_select_all(&snode->edittree->nodes, SEL_DESELECT);
}
/* get operator properties */
@@ -848,7 +845,7 @@ static bool do_lasso_select_node(bContext *C,
const bool select = (sel_op != SEL_OP_SUB);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- ED_node_select_all(&snode->edittree->nodes, SEL_DESELECT);
+ node_select_all(&snode->edittree->nodes, SEL_DESELECT);
changed = true;
}
@@ -935,13 +932,13 @@ void NODE_OT_select_lasso(wmOperatorType *ot)
static int node_select_all_exec(bContext *C, wmOperator *op)
{
- SpaceNode *snode = CTX_wm_space_node(C);
- ListBase *node_lb = &snode->edittree->nodes;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ ListBase *node_lb = &snode.edittree->nodes;
int action = RNA_enum_get(op->ptr, "action");
- ED_node_select_all(node_lb, action);
+ node_select_all(node_lb, action);
- ED_node_sort(snode->edittree);
+ node_sort(*snode.edittree);
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
return OPERATOR_FINISHED;
@@ -972,15 +969,14 @@ void NODE_OT_select_all(wmOperatorType *ot)
static int node_select_linked_to_exec(bContext *C, wmOperator *UNUSED(op))
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeLink *link;
- bNode *node;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &node_tree = *snode.edittree;
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
node->flag &= ~NODE_TEST;
}
- for (link = (bNodeLink *)snode->edittree->links.first; link; link = link->next) {
+ LISTBASE_FOREACH (bNodeLink *, link, &node_tree.links) {
if (nodeLinkIsHidden(link)) {
continue;
}
@@ -989,13 +985,13 @@ static int node_select_linked_to_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
if (node->flag & NODE_TEST) {
nodeSetSelected(node, true);
}
}
- ED_node_sort(snode->edittree);
+ node_sort(node_tree);
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
return OPERATOR_FINISHED;
@@ -1024,15 +1020,14 @@ void NODE_OT_select_linked_to(wmOperatorType *ot)
static int node_select_linked_from_exec(bContext *C, wmOperator *UNUSED(op))
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeLink *link;
- bNode *node;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &node_tree = *snode.edittree;
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
node->flag &= ~NODE_TEST;
}
- for (link = (bNodeLink *)snode->edittree->links.first; link; link = link->next) {
+ LISTBASE_FOREACH (bNodeLink *, link, &node_tree.links) {
if (nodeLinkIsHidden(link)) {
continue;
}
@@ -1041,13 +1036,13 @@ static int node_select_linked_from_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
if (node->flag & NODE_TEST) {
nodeSetSelected(node, true);
}
}
- ED_node_sort(snode->edittree);
+ node_sort(node_tree);
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
return OPERATOR_FINISHED;
@@ -1314,3 +1309,5 @@ void NODE_OT_find_node(wmOperatorType *ot)
}
/** \} */
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_templates.cc b/source/blender/editors/space_node/node_templates.cc
index 386178596af..113e2bd3bb3 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"
@@ -52,9 +53,10 @@
#include "ED_undo.h"
-using blender::Vector;
using blender::nodes::NodeDeclaration;
+namespace blender::ed::space_node {
+
/************************* Node Socket Manipulation **************************/
/* describes an instance of a node type and a specific socket to link */
@@ -84,7 +86,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 +181,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 +195,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 +297,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 *******************************/
@@ -386,17 +382,42 @@ static Vector<NodeLinkItem> ui_node_link_items(NodeLinkArg *arg,
const SocketDeclaration &socket_decl = *socket_decl_ptr;
NodeLinkItem item;
item.socket_index = index++;
- /* A socket declaration does not necessarily map to exactly one built-in socket type. So only
- * check for the types that matter here. */
- if (dynamic_cast<const decl::Color *>(&socket_decl)) {
- item.socket_type = SOCK_RGBA;
- }
- else if (dynamic_cast<const decl::Float *>(&socket_decl)) {
+ if (dynamic_cast<const decl::Float *>(&socket_decl)) {
item.socket_type = SOCK_FLOAT;
}
+ else if (dynamic_cast<const decl::Int *>(&socket_decl)) {
+ item.socket_type = SOCK_INT;
+ }
+ else if (dynamic_cast<const decl::Bool *>(&socket_decl)) {
+ item.socket_type = SOCK_BOOLEAN;
+ }
else if (dynamic_cast<const decl::Vector *>(&socket_decl)) {
item.socket_type = SOCK_VECTOR;
}
+ else if (dynamic_cast<const decl::Color *>(&socket_decl)) {
+ item.socket_type = SOCK_RGBA;
+ }
+ else if (dynamic_cast<const decl::String *>(&socket_decl)) {
+ item.socket_type = SOCK_STRING;
+ }
+ else if (dynamic_cast<const decl::Image *>(&socket_decl)) {
+ item.socket_type = SOCK_IMAGE;
+ }
+ else if (dynamic_cast<const decl::Texture *>(&socket_decl)) {
+ item.socket_type = SOCK_TEXTURE;
+ }
+ else if (dynamic_cast<const decl::Material *>(&socket_decl)) {
+ item.socket_type = SOCK_MATERIAL;
+ }
+ else if (dynamic_cast<const decl::Shader *>(&socket_decl)) {
+ item.socket_type = SOCK_SHADER;
+ }
+ else if (dynamic_cast<const decl::Collection *>(&socket_decl)) {
+ item.socket_type = SOCK_COLLECTION;
+ }
+ else if (dynamic_cast<const decl::Object *>(&socket_decl)) {
+ item.socket_type = SOCK_OBJECT;
+ }
else {
item.socket_type = SOCK_CUSTOM;
}
@@ -696,15 +717,19 @@ static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_
ui_node_menu_column(arg, NODE_CLASS_GROUP, N_("Group"));
}
+} // namespace blender::ed::space_node
+
void uiTemplateNodeLink(
uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input)
{
+ using namespace blender::ed::space_node;
+
uiBlock *block = uiLayoutGetBlock(layout);
NodeLinkArg *arg;
uiBut *but;
float socket_col[4];
- arg = (NodeLinkArg *)MEM_callocN(sizeof(NodeLinkArg), "NodeLinkArg");
+ arg = MEM_new<NodeLinkArg>("NodeLinkArg");
arg->ntree = ntree;
arg->node = node;
arg->sock = input;
@@ -740,6 +765,8 @@ void uiTemplateNodeLink(
}
}
+namespace blender::ed::space_node {
+
/**************************** Node Tree Layout *******************************/
static void ui_node_draw_input(
@@ -892,9 +919,13 @@ static void ui_node_draw_input(
node->flag &= ~NODE_TEST;
}
+} // namespace blender::ed::space_node
+
void uiTemplateNodeView(
uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input)
{
+ using namespace blender::ed::space_node;
+
bNode *tnode;
if (!ntree) {
diff --git a/source/blender/editors/space_node/node_view.cc b/source/blender/editors/space_node/node_view.cc
index df629a983e3..9d99709a780 100644
--- a/source/blender/editors/space_node/node_view.cc
+++ b/source/blender/editors/space_node/node_view.cc
@@ -55,7 +55,7 @@
#include "node_intern.hh" /* own include */
-using blender::StringRef;
+namespace blender::ed::space_node {
/* -------------------------------------------------------------------- */
/** \name View All Operator
@@ -255,7 +255,7 @@ static int snode_bg_viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *
return OPERATOR_CANCELLED;
}
- nvm = (NodeViewMove *)MEM_callocN(sizeof(NodeViewMove), "NodeViewMove struct");
+ nvm = MEM_cnew<NodeViewMove>("NodeViewMove struct");
op->customdata = nvm;
nvm->mvalo[0] = event->mval[0];
nvm->mvalo[1] = event->mval[1];
@@ -444,6 +444,8 @@ static void sample_draw(const bContext *C, ARegion *region, void *arg_info)
}
}
+} // namespace blender::ed::space_node
+
bool ED_space_node_get_position(
Main *bmain, SpaceNode *snode, struct ARegion *region, const int mval[2], float fpos[2])
{
@@ -526,6 +528,8 @@ bool ED_space_node_color_sample(
return ret;
}
+namespace blender::ed::space_node {
+
static void sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
{
Main *bmain = CTX_data_main(C);
@@ -643,7 +647,7 @@ static int sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
}
- info = (ImageSampleInfo *)MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");
+ info = MEM_cnew<ImageSampleInfo>("ImageSampleInfo");
info->art = region->type;
info->draw_handle = ED_region_draw_cb_activate(
region->type, sample_draw, info, REGION_DRAW_POST_PIXEL);
@@ -783,3 +787,5 @@ void NODE_OT_geometry_node_view_legacy(wmOperatorType *ot)
}
/** \} */
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc
index f3b95ca2024..00fd328b2ed 100644
--- a/source/blender/editors/space_node/space_node.cc
+++ b/source/blender/editors/space_node/space_node.cc
@@ -31,6 +31,7 @@
#include "BKE_context.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_remap.h"
#include "BKE_node.h"
#include "BKE_screen.h"
@@ -63,7 +64,7 @@ void ED_node_tree_start(SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from)
BLI_listbase_clear(&snode->treepath);
if (ntree) {
- bNodeTreePath *path = (bNodeTreePath *)MEM_callocN(sizeof(bNodeTreePath), "node tree path");
+ bNodeTreePath *path = MEM_cnew<bNodeTreePath>("node tree path");
path->nodetree = ntree;
path->parent_key = NODE_INSTANCE_KEY_BASE;
@@ -96,7 +97,7 @@ void ED_node_tree_start(SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from)
void ED_node_tree_push(SpaceNode *snode, bNodeTree *ntree, bNode *gnode)
{
- bNodeTreePath *path = (bNodeTreePath *)MEM_callocN(sizeof(bNodeTreePath), "node tree path");
+ bNodeTreePath *path = MEM_cnew<bNodeTreePath>("node tree path");
bNodeTreePath *prev_path = (bNodeTreePath *)snode->treepath.last;
path->nodetree = ntree;
if (gnode) {
@@ -206,6 +207,18 @@ void ED_node_set_active_viewer_key(SpaceNode *snode)
}
}
+void ED_node_cursor_location_get(const SpaceNode *snode, float value[2])
+{
+ copy_v2_v2(value, snode->runtime->cursor);
+}
+
+void ED_node_cursor_location_set(SpaceNode *snode, const float value[2])
+{
+ copy_v2_v2(snode->runtime->cursor, value);
+}
+
+namespace blender::ed::space_node {
+
float2 space_node_group_offset(const SpaceNode &snode)
{
const bNodeTreePath *path = (bNodeTreePath *)snode.treepath.last;
@@ -220,7 +233,7 @@ float2 space_node_group_offset(const SpaceNode &snode)
static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
{
- SpaceNode *snode = (SpaceNode *)MEM_callocN(sizeof(SpaceNode), "initnode");
+ SpaceNode *snode = MEM_cnew<SpaceNode>("initnode");
snode->spacetype = SPACE_NODE;
snode->flag = SNODE_SHOW_GPENCIL | SNODE_USE_ALPHA;
@@ -238,21 +251,21 @@ static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(s
NODE_TREE_TYPES_END;
/* header */
- ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "header for node");
+ ARegion *region = MEM_cnew<ARegion>("header for node");
BLI_addtail(&snode->regionbase, region);
region->regiontype = RGN_TYPE_HEADER;
region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
/* buttons/list view */
- region = (ARegion *)MEM_callocN(sizeof(ARegion), "buttons for node");
+ region = MEM_cnew<ARegion>("buttons for node");
BLI_addtail(&snode->regionbase, region);
region->regiontype = RGN_TYPE_UI;
region->alignment = RGN_ALIGN_RIGHT;
/* toolbar */
- region = (ARegion *)MEM_callocN(sizeof(ARegion), "node tools");
+ region = MEM_cnew<ARegion>("node tools");
BLI_addtail(&snode->regionbase, region);
region->regiontype = RGN_TYPE_TOOLS;
@@ -261,7 +274,7 @@ static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(s
region->flag = RGN_FLAG_HIDDEN;
/* main region */
- region = (ARegion *)MEM_callocN(sizeof(ARegion), "main region for node");
+ region = MEM_cnew<ARegion>("main region for node");
BLI_addtail(&snode->regionbase, region);
region->regiontype = RGN_TYPE_WINDOW;
@@ -309,8 +322,21 @@ static void node_init(struct wmWindowManager *UNUSED(wm), ScrArea *area)
SpaceNode *snode = (SpaceNode *)area->spacedata.first;
if (snode->runtime == nullptr) {
- snode->runtime = (SpaceNode_Runtime *)MEM_callocN(sizeof(SpaceNode_Runtime), __func__);
+ snode->runtime = MEM_new<SpaceNode_Runtime>(__func__);
+ }
+}
+
+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)
@@ -370,9 +396,6 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params)
else if (wmn->data == ND_SHADING_LINKS) {
ED_area_tag_refresh(area);
}
- else if (wmn->action == NA_ADDED && snode->edittree) {
- nodeSetActiveID(snode->edittree, ID_MA, (ID *)wmn->reference);
- }
}
break;
case NC_TEXTURE:
@@ -436,10 +459,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 +471,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);
}
}
@@ -482,27 +504,7 @@ static void node_area_refresh(const struct bContext *C, ScrArea *area)
snode_set_context(*C);
if (snode->nodetree) {
- if (snode->nodetree->type == NTREE_SHADER) {
- if (GS(snode->id->name) == ID_MA) {
- Material *ma = (Material *)snode->id;
- if (ma->use_nodes) {
- ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER);
- }
- }
- else if (GS(snode->id->name) == ID_LA) {
- Light *la = (Light *)snode->id;
- if (la->use_nodes) {
- ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER);
- }
- }
- else if (GS(snode->id->name) == ID_WO) {
- World *wo = (World *)snode->id;
- if (wo->use_nodes) {
- ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER);
- }
- }
- }
- else if (snode->nodetree->type == NTREE_COMPOSIT) {
+ if (snode->nodetree->type == NTREE_COMPOSIT) {
Scene *scene = (Scene *)snode->id;
if (scene->use_nodes) {
/* recalc is set on 3d view changes for auto compo */
@@ -515,12 +517,6 @@ static void node_area_refresh(const struct bContext *C, ScrArea *area)
}
}
}
- else if (snode->nodetree->type == NTREE_TEXTURE) {
- Tex *tex = (Tex *)snode->id;
- if (tex->use_nodes) {
- ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER);
- }
- }
}
}
@@ -573,16 +569,6 @@ static void node_toolbar_region_draw(const bContext *C, ARegion *region)
ED_region_panels(C, region);
}
-void ED_node_cursor_location_get(const SpaceNode *snode, float value[2])
-{
- copy_v2_v2(value, snode->runtime->cursor);
-}
-
-void ED_node_cursor_location_set(SpaceNode *snode, const float value[2])
-{
- copy_v2_v2(snode->runtime->cursor, value);
-}
-
static void node_cursor(wmWindow *win, ScrArea *area, ARegion *region)
{
SpaceNode *snode = (SpaceNode *)area->spacedata.first;
@@ -831,8 +817,14 @@ static void node_region_listener(const wmRegionListenerParams *params)
}
}
+} // namespace blender::ed::space_node
+
+/* Outside of blender namespace to avoid Python documentation build error with `ctypes`. */
const char *node_context_dir[] = {
"selected_nodes", "active_node", "light", "material", "world", nullptr};
+
+namespace blender::ed::space_node {
+
static int /*eContextResult*/ node_context(const bContext *C,
const char *member,
bContextDataResult *result)
@@ -905,9 +897,9 @@ static void node_widgets()
WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_corner_pin);
}
-static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void node_id_remap_cb(ID *old_id, ID *new_id, void *user_data)
{
- SpaceNode *snode = (SpaceNode *)slink;
+ SpaceNode *snode = static_cast<SpaceNode *>(user_data);
if (snode->id == old_id) {
/* nasty DNA logic for SpaceNode:
@@ -973,6 +965,24 @@ static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, I
}
}
+static void node_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
+{
+ /* Although we should be able to perform all the mappings in a single go this lead to issues when
+ * running the python test cases. Somehow the nodetree/edittree weren't updated to the new
+ * pointers that generated a SEGFAULT.
+ *
+ * To move forward we should perhaps remove snode->edittree and snode->nodetree as they are just
+ * copies of pointers. All usages should be calling a function that will receive the appropriate
+ * instance.
+ *
+ * We could also move a remap address at a time to ise the IDRemapper as that should get closer
+ * to cleaner code. See {D13615} for more information about this topic.
+ */
+ BKE_id_remapper_iter(mappings, node_id_remap_cb, slink);
+}
+
static int node_space_subtype_get(ScrArea *area)
{
SpaceNode *snode = (SpaceNode *)area->spacedata.first;
@@ -995,9 +1005,13 @@ static void node_space_subtype_item_extend(bContext *C, EnumPropertyItem **item,
}
}
+} // namespace blender::ed::space_node
+
void ED_spacetype_node()
{
- SpaceType *st = (SpaceType *)MEM_callocN(sizeof(SpaceType), "spacetype node");
+ using namespace blender::ed::space_node;
+
+ SpaceType *st = MEM_cnew<SpaceType>("spacetype node");
ARegionType *art;
st->spaceid = SPACE_NODE;
@@ -1020,7 +1034,7 @@ void ED_spacetype_node()
st->space_subtype_set = node_space_subtype_set;
/* regions: main window */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype node region");
+ art = MEM_cnew<ARegionType>("spacetype node region");
art->regionid = RGN_TYPE_WINDOW;
art->init = node_main_region_init;
art->draw = node_main_region_draw;
@@ -1034,7 +1048,7 @@ void ED_spacetype_node()
BLI_addhead(&st->regiontypes, art);
/* regions: header */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype node region");
+ art = MEM_cnew<ARegionType>("spacetype node region");
art->regionid = RGN_TYPE_HEADER;
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
@@ -1045,7 +1059,7 @@ void ED_spacetype_node()
BLI_addhead(&st->regiontypes, art);
/* regions: listview/buttons */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype node region");
+ art = MEM_cnew<ARegionType>("spacetype node region");
art->regionid = RGN_TYPE_UI;
art->prefsizex = UI_SIDEBAR_PANEL_WIDTH;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
@@ -1056,7 +1070,7 @@ void ED_spacetype_node()
BLI_addhead(&st->regiontypes, art);
/* regions: toolbar */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype view3d tools region");
+ art = MEM_cnew<ARegionType>("spacetype view3d tools region");
art->regionid = RGN_TYPE_TOOLS;
art->prefsizex = 58; /* XXX */
art->prefsizey = 50; /* XXX */
@@ -1068,7 +1082,5 @@ void ED_spacetype_node()
art->draw = node_toolbar_region_draw;
BLI_addhead(&st->regiontypes, art);
- node_toolbar_register(art);
-
BKE_spacetype_register(st);
}
diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt
index c31239f0e9c..bc6db978a4f 100644
--- a/source/blender/editors/space_outliner/CMakeLists.txt
+++ b/source/blender/editors/space_outliner/CMakeLists.txt
@@ -34,18 +34,18 @@ set(INC
set(SRC
- outliner_collections.c
- outliner_context.c
- outliner_dragdrop.c
- outliner_draw.c
- outliner_edit.c
- outliner_ops.c
- outliner_select.c
- outliner_sync.c
- outliner_tools.c
- outliner_tree.c
- outliner_utils.c
- space_outliner.c
+ outliner_collections.cc
+ outliner_context.cc
+ outliner_dragdrop.cc
+ outliner_draw.cc
+ outliner_edit.cc
+ outliner_ops.cc
+ outliner_select.cc
+ outliner_sync.cc
+ outliner_tools.cc
+ outliner_tree.cc
+ outliner_utils.cc
+ space_outliner.cc
tree/common.cc
tree/tree_display.cc
tree/tree_display_data.cc
@@ -65,13 +65,14 @@ set(SRC
tree/tree_element_id_scene.cc
tree/tree_element_nla.cc
tree/tree_element_overrides.cc
+ tree/tree_element_rna.cc
tree/tree_element_scene_objects.cc
+ tree/tree_element_seq.cc
tree/tree_element_view_layer.cc
- outliner_intern.h
- tree/tree_display.h
+ outliner_intern.hh
+ tree/common.hh
tree/tree_display.hh
- tree/tree_element.h
tree/tree_element.hh
tree/tree_element_anim_data.hh
tree/tree_element_collection.hh
@@ -82,7 +83,9 @@ set(SRC
tree/tree_element_id_scene.hh
tree/tree_element_nla.hh
tree/tree_element_overrides.hh
+ tree/tree_element_rna.hh
tree/tree_element_scene_objects.hh
+ tree/tree_element_seq.hh
tree/tree_element_view_layer.hh
)
diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.cc
index 946d7a0538d..8d60a6088d3 100644
--- a/source/blender/editors/space_outliner/outliner_collections.c
+++ b/source/blender/editors/space_outliner/outliner_collections.cc
@@ -18,7 +18,7 @@
* \ingroup spoutliner
*/
-#include <string.h>
+#include <cstring>
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
@@ -49,7 +49,7 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
-#include "outliner_intern.h" /* own include */
+#include "outliner_intern.hh" /* own include */
/* -------------------------------------------------------------------- */
/** \name Utility API
@@ -81,11 +81,11 @@ Collection *outliner_collection_from_tree_element(const TreeElement *te)
TreeStoreElem *tselem = TREESTORE(te);
if (!tselem) {
- return NULL;
+ return nullptr;
}
if (tselem->type == TSE_LAYER_COLLECTION) {
- LayerCollection *lc = te->directdata;
+ LayerCollection *lc = reinterpret_cast<LayerCollection *>(te->directdata);
return lc->collection;
}
if (ELEM(tselem->type, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) {
@@ -96,12 +96,12 @@ Collection *outliner_collection_from_tree_element(const TreeElement *te)
return (Collection *)tselem->id;
}
- return NULL;
+ return nullptr;
}
TreeTraversalAction outliner_find_selected_collections(TreeElement *te, void *customdata)
{
- struct IDsSelectedData *data = customdata;
+ struct IDsSelectedData *data = reinterpret_cast<IDsSelectedData *>(customdata);
TreeStoreElem *tselem = TREESTORE(te);
if (outliner_is_collection_tree_element(te)) {
@@ -118,14 +118,15 @@ TreeTraversalAction outliner_find_selected_collections(TreeElement *te, void *cu
TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata)
{
- struct IDsSelectedData *data = customdata;
+ struct IDsSelectedData *data = reinterpret_cast<IDsSelectedData *>(customdata);
TreeStoreElem *tselem = TREESTORE(te);
if (outliner_is_collection_tree_element(te)) {
return TRAVERSE_CONTINUE;
}
- if ((tselem->type != TSE_SOME_ID) || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) {
+ if ((tselem->type != TSE_SOME_ID) || (tselem->id == nullptr) ||
+ (GS(tselem->id->name) != ID_OB)) {
return TRAVERSE_SKIP_CHILDS;
}
@@ -137,7 +138,7 @@ TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *custom
void ED_outliner_selected_objects_get(const bContext *C, ListBase *objects)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- struct IDsSelectedData data = {{NULL}};
+ struct IDsSelectedData data = {{nullptr}};
outliner_tree_traverse(space_outliner,
&space_outliner->tree,
0,
@@ -161,14 +162,14 @@ void ED_outliner_selected_objects_get(const bContext *C, ListBase *objects)
bool ED_outliner_collections_editor_poll(bContext *C)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- return (space_outliner != NULL) &&
+ return (space_outliner != nullptr) &&
ELEM(space_outliner->outlinevis, SO_VIEW_LAYER, SO_SCENES, SO_LIBRARIES);
}
static bool outliner_view_layer_collections_editor_poll(bContext *C)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- return (space_outliner != NULL) && (space_outliner->outlinevis == SO_VIEW_LAYER);
+ return (space_outliner != nullptr) && (space_outliner->outlinevis == SO_VIEW_LAYER);
}
static bool collection_edit_in_active_scene_poll(bContext *C)
@@ -196,14 +197,14 @@ struct CollectionNewData {
static TreeTraversalAction collection_find_selected_to_add(TreeElement *te, void *customdata)
{
- struct CollectionNewData *data = customdata;
+ struct CollectionNewData *data = reinterpret_cast<CollectionNewData *>(customdata);
Collection *collection = outliner_collection_from_tree_element(te);
if (!collection) {
return TRAVERSE_SKIP_CHILDS;
}
- if (data->collection != NULL) {
+ if (data->collection != nullptr) {
data->error = true;
return TRAVERSE_BREAK;
}
@@ -220,10 +221,7 @@ static int collection_new_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- struct CollectionNewData data = {
- .error = false,
- .collection = NULL,
- };
+ CollectionNewData data{};
if (RNA_boolean_get(op->ptr, "nested")) {
outliner_build_tree(bmain, scene, view_layer, space_outliner, region);
@@ -241,7 +239,7 @@ static int collection_new_exec(bContext *C, wmOperator *op)
}
}
- if (data.collection == NULL || ID_IS_LINKED(data.collection) ||
+ if (data.collection == nullptr || ID_IS_LINKED(data.collection) ||
ID_IS_OVERRIDE_LIBRARY(data.collection)) {
data.collection = scene->master_collection;
}
@@ -251,13 +249,13 @@ static int collection_new_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- BKE_collection_add(bmain, data.collection, NULL);
+ BKE_collection_add(bmain, data.collection, nullptr);
DEG_id_tag_update(&data.collection->id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(bmain);
outliner_cleanup_tree(space_outliner);
- WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, nullptr);
return OPERATOR_FINISHED;
}
@@ -295,7 +293,7 @@ struct CollectionEditData {
static TreeTraversalAction collection_find_data_to_edit(TreeElement *te, void *customdata)
{
- struct CollectionEditData *data = customdata;
+ CollectionEditData *data = reinterpret_cast<CollectionEditData *>(customdata);
Collection *collection = outliner_collection_from_tree_element(te);
if (!collection) {
@@ -321,10 +319,9 @@ void outliner_collection_delete(
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- struct CollectionEditData data = {
- .scene = scene,
- .space_outliner = space_outliner,
- };
+ CollectionEditData data{};
+ data.scene = scene;
+ data.space_outliner = space_outliner;
data.collections_to_edit = BLI_gset_ptr_new(__func__);
@@ -336,7 +333,8 @@ void outliner_collection_delete(
/* Effectively delete the collections. */
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ Collection *collection = reinterpret_cast<Collection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
/* Test in case collection got deleted as part of another one. */
if (BLI_findindex(&bmain->collections, collection) != -1) {
@@ -358,7 +356,7 @@ void outliner_collection_delete(
BLI_assert(parent->id.flag & LIB_EMBEDDED_DATA);
const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(&parent->id);
- BLI_assert(id_type->owner_get != NULL);
+ BLI_assert(id_type->owner_get != nullptr);
ID *scene_owner = id_type->owner_get(bmain, &parent->id);
BLI_assert(GS(scene_owner->name) == ID_SCE);
@@ -384,9 +382,11 @@ void outliner_collection_delete(
}
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
}
+/* FIXME: See comment above #WM_msg_publish_rna_prop(). */
+extern "C" {
static int collection_hierarchy_delete_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -400,7 +400,7 @@ static int collection_hierarchy_delete_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(bmain);
- WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, nullptr);
if (basact_prev != BASACT(view_layer)) {
WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active);
@@ -410,6 +410,7 @@ static int collection_hierarchy_delete_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+}
void OUTLINER_OT_collection_hierarchy_delete(wmOperatorType *ot)
{
@@ -440,12 +441,12 @@ struct CollectionObjectsSelectData {
static TreeTraversalAction outliner_find_first_selected_layer_collection(TreeElement *te,
void *customdata)
{
- struct CollectionObjectsSelectData *data = customdata;
+ CollectionObjectsSelectData *data = reinterpret_cast<CollectionObjectsSelectData *>(customdata);
TreeStoreElem *tselem = TREESTORE(te);
switch (tselem->type) {
case TSE_LAYER_COLLECTION:
- data->layer_collection = te->directdata;
+ data->layer_collection = reinterpret_cast<LayerCollection *>(te->directdata);
return TRAVERSE_BREAK;
case TSE_R_LAYER:
case TSE_SCENE_COLLECTION_BASE:
@@ -460,9 +461,7 @@ static LayerCollection *outliner_active_layer_collection(bContext *C)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- struct CollectionObjectsSelectData data = {
- .layer_collection = NULL,
- };
+ CollectionObjectsSelectData data{};
outliner_tree_traverse(space_outliner,
&space_outliner->tree,
@@ -479,7 +478,7 @@ static int collection_objects_select_exec(bContext *C, wmOperator *op)
LayerCollection *layer_collection = outliner_active_layer_collection(C);
bool deselect = STREQ(op->idname, "OUTLINER_OT_collection_objects_deselect");
- if (layer_collection == NULL) {
+ if (layer_collection == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -536,7 +535,7 @@ struct CollectionDuplicateData {
static TreeTraversalAction outliner_find_first_selected_collection(TreeElement *te,
void *customdata)
{
- struct CollectionDuplicateData *data = customdata;
+ CollectionDuplicateData *data = reinterpret_cast<CollectionDuplicateData *>(customdata);
TreeStoreElem *tselem = TREESTORE(te);
switch (tselem->type) {
@@ -555,9 +554,7 @@ static TreeElement *outliner_active_collection(bContext *C)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- struct CollectionDuplicateData data = {
- .te = NULL,
- };
+ CollectionDuplicateData data = {};
outliner_tree_traverse(space_outliner,
&space_outliner->tree,
@@ -572,38 +569,38 @@ static int collection_duplicate_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
TreeElement *te = outliner_active_collection(C);
- const bool linked = strstr(op->idname, "linked") != NULL;
+ const bool linked = strstr(op->idname, "linked") != nullptr;
/* Can happen when calling from a key binding. */
- if (te == NULL) {
+ if (te == nullptr) {
BKE_report(op->reports, RPT_ERROR, "No active collection");
return OPERATOR_CANCELLED;
}
Collection *collection = outliner_collection_from_tree_element(te);
- Collection *parent = (te->parent) ? outliner_collection_from_tree_element(te->parent) : NULL;
+ Collection *parent = (te->parent) ? outliner_collection_from_tree_element(te->parent) : nullptr;
/* We are allowed to duplicated linked collections (they will become local IDs then),
* but we should not allow its parent to be a linked ID, ever.
* This can happen when a whole scene is linked e.g. */
- if (parent != NULL && (ID_IS_LINKED(parent) || ID_IS_OVERRIDE_LIBRARY(parent))) {
+ if (parent != nullptr && (ID_IS_LINKED(parent) || ID_IS_OVERRIDE_LIBRARY(parent))) {
Scene *scene = CTX_data_scene(C);
- parent = (ID_IS_LINKED(scene) || ID_IS_OVERRIDE_LIBRARY(scene)) ? NULL :
+ parent = (ID_IS_LINKED(scene) || ID_IS_OVERRIDE_LIBRARY(scene)) ? nullptr :
scene->master_collection;
}
- else if (parent != NULL && (parent->flag & COLLECTION_IS_MASTER) != 0) {
+ else if (parent != nullptr && (parent->flag & COLLECTION_IS_MASTER) != 0) {
BLI_assert(parent->id.flag & LIB_EMBEDDED_DATA);
const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(&parent->id);
- BLI_assert(id_type->owner_get != NULL);
+ BLI_assert(id_type->owner_get != nullptr);
Scene *scene_owner = (Scene *)id_type->owner_get(bmain, &parent->id);
- BLI_assert(scene_owner != NULL);
+ BLI_assert(scene_owner != nullptr);
BLI_assert(GS(scene_owner->id.name) == ID_SCE);
if (ID_IS_LINKED(scene_owner) || ID_IS_OVERRIDE_LIBRARY(scene_owner)) {
scene_owner = CTX_data_scene(C);
- parent = ID_IS_LINKED(scene_owner) ? NULL : scene_owner->master_collection;
+ parent = ID_IS_LINKED(scene_owner) ? nullptr : scene_owner->master_collection;
}
}
@@ -612,14 +609,15 @@ static int collection_duplicate_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (parent == NULL) {
+ if (parent == nullptr) {
BKE_report(op->reports,
RPT_WARNING,
"Could not find a valid parent collection for the new duplicate, "
"it won't be linked to any view layer");
}
- const eDupli_ID_Flags dupli_flags = USER_DUP_OBJECT | (linked ? 0 : U.dupflag);
+ const eDupli_ID_Flags dupli_flags = (eDupli_ID_Flags)(USER_DUP_OBJECT |
+ (linked ? 0 : U.dupflag));
BKE_collection_duplicate(bmain, parent, collection, dupli_flags, LIB_ID_DUPLICATE_IS_ROOT_ID);
DEG_relations_tag_update(bmain);
@@ -674,10 +672,10 @@ static int collection_link_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Collection *active_collection = CTX_data_layer_collection(C)->collection;
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- struct CollectionEditData data = {
- .scene = scene,
- .space_outliner = space_outliner,
- };
+
+ CollectionEditData data{};
+ data.scene = scene;
+ data.space_outliner = space_outliner;
if ((ID_IS_LINKED(active_collection) || ID_IS_OVERRIDE_LIBRARY(active_collection)) ||
((active_collection->flag & COLLECTION_IS_MASTER) &&
@@ -696,17 +694,18 @@ static int collection_link_exec(bContext *C, wmOperator *op)
/* Effectively link the collections. */
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ Collection *collection = reinterpret_cast<Collection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
BKE_collection_child_add(bmain, active_collection, collection);
id_fake_user_clear(&collection->id);
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
DEG_id_tag_update(&active_collection->id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(bmain);
- WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, nullptr);
return OPERATOR_FINISHED;
}
@@ -738,10 +737,9 @@ static int collection_instance_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- struct CollectionEditData data = {
- .scene = scene,
- .space_outliner = space_outliner,
- };
+ CollectionEditData data{};
+ data.scene = scene;
+ data.space_outliner = space_outliner;
data.collections_to_edit = BLI_gset_ptr_new(__func__);
@@ -755,7 +753,8 @@ static int collection_instance_exec(bContext *C, wmOperator *UNUSED(op))
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ Collection *collection = reinterpret_cast<Collection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
while (BKE_collection_cycle_find(active_lc->collection, collection)) {
active_lc = BKE_layer_collection_activate_parent(view_layer, active_lc);
@@ -764,20 +763,21 @@ static int collection_instance_exec(bContext *C, wmOperator *UNUSED(op))
/* Effectively instance the collections. */
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ Collection *collection = reinterpret_cast<Collection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
Object *ob = ED_object_add_type(
- C, OB_EMPTY, collection->id.name + 2, scene->cursor.location, NULL, false, 0);
+ C, OB_EMPTY, collection->id.name + 2, scene->cursor.location, nullptr, false, 0);
ob->instance_collection = collection;
ob->transflag |= OB_DUPLICOLLECTION;
id_lib_extern(&collection->id);
id_us_plus(&collection->id);
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
DEG_relations_tag_update(bmain);
- WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, nullptr);
return OPERATOR_FINISHED;
}
@@ -805,14 +805,14 @@ void OUTLINER_OT_collection_instance(wmOperatorType *ot)
static TreeTraversalAction layer_collection_find_data_to_edit(TreeElement *te, void *customdata)
{
- struct CollectionEditData *data = customdata;
+ CollectionEditData *data = reinterpret_cast<CollectionEditData *>(customdata);
TreeStoreElem *tselem = TREESTORE(te);
if (!(tselem && tselem->type == TSE_LAYER_COLLECTION)) {
return TRAVERSE_CONTINUE;
}
- LayerCollection *lc = te->directdata;
+ LayerCollection *lc = reinterpret_cast<LayerCollection *>(te->directdata);
if (lc->collection->flag & COLLECTION_IS_MASTER) {
/* skip - showing warning/error message might be misleading
@@ -836,10 +836,9 @@ static bool collections_view_layer_poll(bContext *C, bool clear, int flag)
}
Scene *scene = CTX_data_scene(C);
- struct CollectionEditData data = {
- .scene = scene,
- .space_outliner = space_outliner,
- };
+ CollectionEditData data{};
+ data.scene = scene;
+ data.space_outliner = space_outliner;
data.collections_to_edit = BLI_gset_ptr_new(__func__);
bool result = false;
@@ -852,7 +851,8 @@ static bool collections_view_layer_poll(bContext *C, bool clear, int flag)
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ LayerCollection *lc = reinterpret_cast<LayerCollection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
if (clear && (lc->flag & flag)) {
result = true;
@@ -862,7 +862,7 @@ static bool collections_view_layer_poll(bContext *C, bool clear, int flag)
}
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
return result;
}
@@ -902,11 +902,10 @@ static int collection_view_layer_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- struct CollectionEditData data = {
- .scene = scene,
- .space_outliner = space_outliner,
- };
- bool clear = strstr(op->idname, "clear") != NULL;
+ CollectionEditData data{};
+ data.scene = scene;
+ data.space_outliner = space_outliner;
+ bool clear = strstr(op->idname, "clear") != nullptr;
int flag = strstr(op->idname, "holdout") ? LAYER_COLLECTION_HOLDOUT :
strstr(op->idname, "indirect_only") ? LAYER_COLLECTION_INDIRECT_ONLY :
LAYER_COLLECTION_EXCLUDE;
@@ -922,16 +921,17 @@ static int collection_view_layer_exec(bContext *C, wmOperator *op)
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ LayerCollection *lc = reinterpret_cast<LayerCollection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
BKE_layer_collection_set_flag(lc, flag, !clear);
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
BKE_layer_collection_sync(scene, view_layer);
DEG_relations_tag_update(bmain);
- WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, nullptr);
return OPERATOR_FINISHED;
}
@@ -1040,10 +1040,9 @@ static int collection_isolate_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
const bool extend = RNA_boolean_get(op->ptr, "extend");
- struct CollectionEditData data = {
- .scene = scene,
- .space_outliner = space_outliner,
- };
+ CollectionEditData data{};
+ data.scene = scene;
+ data.space_outliner = space_outliner;
data.collections_to_edit = BLI_gset_ptr_new(__func__);
outliner_tree_traverse(space_outliner,
&space_outliner->tree,
@@ -1054,7 +1053,8 @@ static int collection_isolate_exec(bContext *C, wmOperator *op)
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
if (extend) {
BKE_layer_collection_isolate_global(scene, view_layer, layer_collection, true);
@@ -1069,16 +1069,16 @@ static int collection_isolate_exec(bContext *C, wmOperator *op)
* was called. */
const bool value = !RNA_property_boolean_get(&ptr, prop);
outliner_collection_isolate_flag(
- scene, view_layer, layer_collection, NULL, prop, "hide_viewport", value);
+ scene, view_layer, layer_collection, nullptr, prop, "hide_viewport", value);
break;
}
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
BKE_layer_collection_sync(scene, view_layer);
DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
- WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, nullptr);
return OPERATOR_FINISHED;
}
@@ -1127,7 +1127,7 @@ static bool collection_inside_poll(bContext *C)
if (!ED_outliner_collections_editor_poll(C)) {
return false;
}
- return outliner_active_layer_collection(C) != NULL;
+ return outliner_active_layer_collection(C) != nullptr;
}
static int collection_visibility_exec(bContext *C, wmOperator *op)
@@ -1135,12 +1135,11 @@ static int collection_visibility_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- const bool is_inside = strstr(op->idname, "inside") != NULL;
- const bool show = strstr(op->idname, "show") != NULL;
- struct CollectionEditData data = {
- .scene = scene,
- .space_outliner = space_outliner,
- };
+ const bool is_inside = strstr(op->idname, "inside") != nullptr;
+ const bool show = strstr(op->idname, "show") != nullptr;
+ CollectionEditData data{};
+ data.scene = scene;
+ data.space_outliner = space_outliner;
data.collections_to_edit = BLI_gset_ptr_new(__func__);
outliner_tree_traverse(space_outliner,
@@ -1152,15 +1151,16 @@ static int collection_visibility_exec(bContext *C, wmOperator *op)
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
BKE_layer_collection_set_visible(view_layer, layer_collection, show, is_inside);
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
BKE_layer_collection_sync(scene, view_layer);
DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
- WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, nullptr);
return OPERATOR_FINISHED;
}
@@ -1237,12 +1237,12 @@ static bool collection_flag_poll(bContext *C, bool clear, int flag)
}
TreeElement *te = outliner_active_collection(C);
- if (te == NULL) {
+ if (te == nullptr) {
return false;
}
Collection *collection = outliner_collection_from_tree_element(te);
- if (collection == NULL) {
+ if (collection == nullptr) {
return false;
}
@@ -1284,10 +1284,9 @@ static int collection_flag_exec(bContext *C, wmOperator *op)
const bool is_render = strstr(op->idname, "render");
const bool clear = strstr(op->idname, "show") || strstr(op->idname, "enable");
int flag = is_render ? COLLECTION_HIDE_RENDER : COLLECTION_HIDE_VIEWPORT;
- struct CollectionEditData data = {
- .scene = scene,
- .space_outliner = space_outliner,
- };
+ CollectionEditData data{};
+ data.scene = scene;
+ data.space_outliner = space_outliner;
data.collections_to_edit = BLI_gset_ptr_new(__func__);
const bool has_layer_collection = space_outliner->outlinevis == SO_VIEW_LAYER;
@@ -1300,7 +1299,8 @@ static int collection_flag_exec(bContext *C, wmOperator *op)
&data);
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
Collection *collection = layer_collection->collection;
if (ID_IS_LINKED(collection)) {
continue;
@@ -1317,7 +1317,7 @@ static int collection_flag_exec(bContext *C, wmOperator *op)
layer_collection->flag &= ~LAYER_COLLECTION_HIDE;
}
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
}
else {
outliner_tree_traverse(space_outliner,
@@ -1328,7 +1328,8 @@ static int collection_flag_exec(bContext *C, wmOperator *op)
&data);
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ Collection *collection = reinterpret_cast<Collection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
if (ID_IS_LINKED(collection)) {
continue;
}
@@ -1340,7 +1341,7 @@ static int collection_flag_exec(bContext *C, wmOperator *op)
collection->flag |= flag;
}
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
}
BKE_layer_collection_sync(scene, view_layer);
@@ -1350,7 +1351,7 @@ static int collection_flag_exec(bContext *C, wmOperator *op)
DEG_relations_tag_update(CTX_data_main(C));
}
- WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, nullptr);
return OPERATOR_FINISHED;
}
@@ -1430,15 +1431,15 @@ struct OutlinerHideEditData {
static TreeTraversalAction outliner_hide_find_data_to_edit(TreeElement *te, void *customdata)
{
- struct OutlinerHideEditData *data = customdata;
+ OutlinerHideEditData *data = reinterpret_cast<OutlinerHideEditData *>(customdata);
TreeStoreElem *tselem = TREESTORE(te);
- if (tselem == NULL) {
+ if (tselem == nullptr) {
return TRAVERSE_CONTINUE;
}
if (tselem->type == TSE_LAYER_COLLECTION) {
- LayerCollection *lc = te->directdata;
+ LayerCollection *lc = reinterpret_cast<LayerCollection *>(te->directdata);
if (lc->collection->flag & COLLECTION_IS_MASTER) {
/* Skip - showing warning/error message might be misleading
@@ -1464,11 +1465,10 @@ static int outliner_hide_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- struct OutlinerHideEditData data = {
- .scene = scene,
- .view_layer = view_layer,
- .space_outliner = space_outliner,
- };
+ OutlinerHideEditData data{};
+ data.scene = scene;
+ data.view_layer = view_layer;
+ data.space_outliner = space_outliner;
data.collections_to_edit = BLI_gset_ptr_new("outliner_hide_exec__collections_to_edit");
data.bases_to_edit = BLI_gset_ptr_new("outliner_hide_exec__bases_to_edit");
@@ -1481,22 +1481,23 @@ static int outliner_hide_exec(bContext *C, wmOperator *UNUSED(op))
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
BKE_layer_collection_set_visible(view_layer, layer_collection, false, false);
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
GSetIterator bases_to_edit_iter;
GSET_ITER (bases_to_edit_iter, data.bases_to_edit) {
- Base *base = BLI_gsetIterator_getKey(&bases_to_edit_iter);
+ Base *base = reinterpret_cast<Base *>(BLI_gsetIterator_getKey(&bases_to_edit_iter));
base->flag |= BASE_HIDDEN;
}
- BLI_gset_free(data.bases_to_edit, NULL);
+ BLI_gset_free(data.bases_to_edit, nullptr);
BKE_layer_collection_sync(scene, view_layer);
DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
- WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, nullptr);
return OPERATOR_FINISHED;
}
@@ -1521,7 +1522,8 @@ static int outliner_unhide_all_exec(bContext *C, wmOperator *UNUSED(op))
ViewLayer *view_layer = CTX_data_view_layer(C);
/* Unhide all the collections. */
- LayerCollection *lc_master = view_layer->layer_collections.first;
+ LayerCollection *lc_master = reinterpret_cast<LayerCollection *>(
+ view_layer->layer_collections.first);
LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_master->layer_collections) {
BKE_layer_collection_set_flag(lc_iter, LAYER_COLLECTION_HIDE, false);
}
@@ -1534,7 +1536,7 @@ static int outliner_unhide_all_exec(bContext *C, wmOperator *UNUSED(op))
BKE_layer_collection_sync(scene, view_layer);
DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
- WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, nullptr);
return OPERATOR_FINISHED;
}
@@ -1565,9 +1567,7 @@ static int outliner_color_tag_set_exec(bContext *C, wmOperator *op)
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
const short color_tag = RNA_enum_get(op->ptr, "color");
- struct IDsSelectedData selected = {
- .selected_array = {NULL, NULL},
- };
+ IDsSelectedData selected{};
outliner_tree_traverse(space_outliner,
&space_outliner->tree,
@@ -1593,7 +1593,7 @@ static int outliner_color_tag_set_exec(bContext *C, wmOperator *op)
BLI_freelistN(&selected.selected_array);
- WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, nullptr);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_outliner/outliner_context.c b/source/blender/editors/space_outliner/outliner_context.cc
index d61bb17f661..d3b99928ec1 100644
--- a/source/blender/editors/space_outliner/outliner_context.c
+++ b/source/blender/editors/space_outliner/outliner_context.cc
@@ -27,7 +27,7 @@
#include "DNA_space_types.h"
-#include "outliner_intern.h"
+#include "outliner_intern.hh"
static void outliner_context_selected_ids_recursive(const ListBase *subtree,
bContextDataResult *result)
@@ -48,7 +48,7 @@ static void outliner_context_selected_ids(const SpaceOutliner *space_outliner,
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
}
-static const char *outliner_context_dir[] = {"selected_ids", NULL};
+static const char *outliner_context_dir[] = {"selected_ids", nullptr};
int /*eContextResult*/ outliner_context(const bContext *C,
const char *member,
diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.cc
index a4d5f2635d4..3745894d630 100644
--- a/source/blender/editors/space_outliner/outliner_dragdrop.c
+++ b/source/blender/editors/space_outliner/outliner_dragdrop.cc
@@ -21,7 +21,7 @@
* \ingroup spoutliner
*/
-#include <string.h>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -58,7 +58,7 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "outliner_intern.h"
+#include "outliner_intern.hh"
static Collection *collection_parent_from_ID(ID *id);
@@ -83,7 +83,7 @@ static TreeElement *outliner_dropzone_element(TreeElement *te,
}
}
}
- return NULL;
+ return nullptr;
}
/* Find tree element to drop into. */
@@ -97,7 +97,7 @@ static TreeElement *outliner_dropzone_find(const SpaceOutliner *space_outliner,
return te_valid;
}
}
- return NULL;
+ return nullptr;
}
static TreeElement *outliner_drop_find(bContext *C, const wmEvent *event)
@@ -113,17 +113,17 @@ static TreeElement *outliner_drop_find(bContext *C, const wmEvent *event)
static ID *outliner_ID_drop_find(bContext *C, const wmEvent *event, short idcode)
{
TreeElement *te = outliner_drop_find(C, event);
- TreeStoreElem *tselem = (te) ? TREESTORE(te) : NULL;
+ TreeStoreElem *tselem = (te) ? TREESTORE(te) : nullptr;
if (te && (te->idcode == idcode) && (tselem->type == TSE_SOME_ID)) {
return tselem->id;
}
- return NULL;
+ return nullptr;
}
/* 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);
@@ -133,11 +133,14 @@ static TreeElement *outliner_drop_insert_find(bContext *C,
/* Empty tree, e.g. while filtered. */
if (BLI_listbase_is_empty(&space_outliner->tree)) {
- return NULL;
+ return nullptr;
}
- 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) {
@@ -154,7 +157,7 @@ static TreeElement *outliner_drop_insert_find(bContext *C,
return te_hovered;
}
*r_insert_type = TE_INSERT_BEFORE;
- return te_hovered->subtree.first;
+ return reinterpret_cast<TreeElement *>(te_hovered->subtree.first);
}
*r_insert_type = TE_INSERT_AFTER;
return te_hovered;
@@ -169,8 +172,8 @@ static TreeElement *outliner_drop_insert_find(bContext *C,
/* Mouse doesn't hover any item (ignoring x-axis),
* so it's either above list bounds or below. */
- TreeElement *first = space_outliner->tree.first;
- TreeElement *last = space_outliner->tree.last;
+ TreeElement *first = reinterpret_cast<TreeElement *>(space_outliner->tree.first);
+ TreeElement *last = reinterpret_cast<TreeElement *>(space_outliner->tree.last);
if (view_mval[1] < last->ys) {
*r_insert_type = TE_INSERT_AFTER;
@@ -181,21 +184,21 @@ static TreeElement *outliner_drop_insert_find(bContext *C,
return first;
}
BLI_assert(0);
- return NULL;
+ return nullptr;
}
-typedef bool (*CheckTypeFn)(TreeElement *te);
+using CheckTypeFn = bool (*)(TreeElement *te);
static TreeElement *outliner_data_from_tree_element_and_parents(CheckTypeFn check_type,
TreeElement *te)
{
- while (te != NULL) {
+ while (te != nullptr) {
if (check_type(te)) {
return te;
}
te = te->parent;
}
- return NULL;
+ return nullptr;
}
static bool is_collection_element(TreeElement *te)
@@ -216,18 +219,18 @@ 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;
+ return nullptr;
}
TreeElement *collection_te = outliner_data_from_tree_element_and_parents(is_collection_element,
te);
if (!collection_te) {
- return NULL;
+ return nullptr;
}
Collection *collection = outliner_collection_from_tree_element(collection_te);
@@ -260,7 +263,7 @@ static int outliner_get_insert_index(TreeElement *drag_te,
}
}
- if (drop_te == NULL) {
+ if (drop_te == nullptr) {
return 0;
}
@@ -364,7 +367,7 @@ static void parent_drop_set_parents(bContext *C,
TreeElement *te = outliner_find_id(space_outliner, &space_outliner->tree, &parent->id);
Scene *scene = (Scene *)outliner_search_back(te, ID_SCE);
- if (scene == NULL) {
+ if (scene == nullptr) {
/* currently outliner organized in a way, that if there's no parent scene
* element for object it means that all displayed objects belong to
* active scene and parenting them is allowed (sergey)
@@ -387,7 +390,7 @@ static void parent_drop_set_parents(bContext *C,
}
if (ED_object_parent_set(
- reports, C, scene, object, parent, parent_type, false, keep_transform, NULL)) {
+ reports, C, scene, object, parent, parent_type, false, keep_transform, nullptr)) {
parent_set = true;
}
}
@@ -399,15 +402,15 @@ static void parent_drop_set_parents(bContext *C,
if (parent_set) {
DEG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, nullptr);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, nullptr);
}
}
static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
TreeElement *te = outliner_drop_find(C, event);
- TreeStoreElem *tselem = te ? TREESTORE(te) : NULL;
+ TreeStoreElem *tselem = te ? TREESTORE(te) : nullptr;
if (!(te && (te->idcode == ID_OB) && (tselem->type == TSE_SOME_ID))) {
return OPERATOR_CANCELLED;
@@ -416,7 +419,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Object *par = (Object *)tselem->id;
Object *ob = (Object *)WM_drag_get_local_ID_from_event(event, ID_OB);
- if (ELEM(NULL, ob, par)) {
+ if (ELEM(nullptr, ob, par)) {
return OPERATOR_CANCELLED;
}
if (ob == par) {
@@ -427,10 +430,11 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
}
- ListBase *lb = event->customdata;
- wmDrag *drag = lb->first;
+ ListBase *lb = reinterpret_cast<ListBase *>(event->customdata);
+ wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first);
- parent_drop_set_parents(C, op->reports, drag->ids.first, par, PAR_OBJECT, event->alt);
+ parent_drop_set_parents(
+ C, op->reports, reinterpret_cast<wmDragID *>(drag->ids.first), par, PAR_OBJECT, event->alt);
return OPERATOR_FINISHED;
}
@@ -501,8 +505,8 @@ static int parent_clear_invoke(bContext *C, wmOperator *UNUSED(op), const wmEven
return OPERATOR_CANCELLED;
}
- ListBase *lb = event->customdata;
- wmDrag *drag = lb->first;
+ ListBase *lb = reinterpret_cast<ListBase *>(event->customdata);
+ wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first);
LISTBASE_FOREACH (wmDragID *, drag_id, &drag->ids) {
if (GS(drag_id->id->name) == ID_OB) {
@@ -513,8 +517,8 @@ static int parent_clear_invoke(bContext *C, wmOperator *UNUSED(op), const wmEven
}
DEG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, nullptr);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, nullptr);
return OPERATOR_FINISHED;
}
@@ -540,7 +544,7 @@ static bool scene_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
/* Ensure item under cursor is valid drop target */
Object *ob = (Object *)WM_drag_get_local_ID(drag, ID_OB);
- return (ob && (outliner_ID_drop_find(C, event, ID_SCE) != NULL));
+ return (ob && (outliner_ID_drop_find(C, event, ID_SCE) != nullptr));
}
static int scene_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
@@ -549,7 +553,7 @@ static int scene_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent
Scene *scene = (Scene *)outliner_ID_drop_find(C, event, ID_SCE);
Object *ob = (Object *)WM_drag_get_local_ID_from_event(event, ID_OB);
- if (ELEM(NULL, ob, scene) || ID_IS_LINKED(scene)) {
+ if (ELEM(nullptr, ob, scene) || ID_IS_LINKED(scene)) {
return OPERATOR_CANCELLED;
}
@@ -605,7 +609,7 @@ static bool material_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
/* Ensure item under cursor is valid drop target */
Material *ma = (Material *)WM_drag_get_local_ID(drag, ID_MA);
- return (ma && (outliner_ID_drop_find(C, event, ID_OB) != NULL));
+ return (ma && (outliner_ID_drop_find(C, event, ID_OB) != nullptr));
}
static int material_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
@@ -614,19 +618,19 @@ static int material_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEve
Object *ob = (Object *)outliner_ID_drop_find(C, event, ID_OB);
Material *ma = (Material *)WM_drag_get_local_ID_from_event(event, ID_MA);
- if (ELEM(NULL, ob, ma)) {
+ if (ELEM(nullptr, ob, ma)) {
return OPERATOR_CANCELLED;
}
/* only drop grease pencil material on grease pencil objects */
- if ((ma->gp_style != NULL) && (ob->type != OB_GPENCIL)) {
+ if ((ma->gp_style != nullptr) && (ob->type != OB_GPENCIL)) {
return OPERATOR_CANCELLED;
}
BKE_object_material_assign(bmain, ob, ma, ob->totcol + 1, BKE_MAT_ASSIGN_USERPREF);
WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, ob);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, nullptr);
WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, ma);
return OPERATOR_FINISHED;
@@ -658,13 +662,13 @@ void OUTLINER_OT_material_drop(wmOperatorType *ot)
* - Copying a single modifier/constraint/effect to another object.
* - Copying (linking) an object's modifiers/constraints/effects to another. */
-typedef enum eDataStackDropAction {
+enum eDataStackDropAction {
DATA_STACK_DROP_REORDER,
DATA_STACK_DROP_COPY,
DATA_STACK_DROP_LINK,
-} eDataStackDropAction;
+};
-typedef struct StackDropData {
+struct StackDropData {
Object *ob_parent;
bPoseChannel *pchan_parent;
TreeStoreElem *drag_tselem;
@@ -674,7 +678,7 @@ typedef struct StackDropData {
eDataStackDropAction drop_action;
TreeElement *drop_te;
TreeElementInsertType insert_type;
-} StackDropData;
+};
static void datastack_drop_data_init(wmDrag *drag,
Object *ob,
@@ -683,7 +687,7 @@ static void datastack_drop_data_init(wmDrag *drag,
TreeStoreElem *tselem,
void *directdata)
{
- StackDropData *drop_data = MEM_callocN(sizeof(*drop_data), "datastack drop data");
+ StackDropData *drop_data = MEM_cnew<StackDropData>("datastack drop data");
drop_data->ob_parent = ob;
drop_data->pchan_parent = pchan;
@@ -707,7 +711,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;
}
@@ -717,20 +721,20 @@ static bool datastack_drop_init(bContext *C, const wmEvent *event, StackDropData
return false;
}
- Object *ob = NULL;
+ Object *ob = nullptr;
TreeElement *object_te = outliner_data_from_tree_element_and_parents(is_object_element,
te_target);
if (object_te) {
ob = (Object *)TREESTORE(object_te)->id;
}
- bPoseChannel *pchan = NULL;
+ bPoseChannel *pchan = nullptr;
TreeElement *pchan_te = outliner_data_from_tree_element_and_parents(is_pchan_element, te_target);
if (pchan_te) {
pchan = (bPoseChannel *)pchan_te->directdata;
}
if (pchan) {
- ob = NULL;
+ ob = nullptr;
}
if (ob && ID_IS_LINKED(&ob->id)) {
@@ -833,7 +837,7 @@ static bool datastack_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
bool changed = outliner_flag_set(
&space_outliner->tree, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false);
- StackDropData *drop_data = drag->poin;
+ StackDropData *drop_data = reinterpret_cast<StackDropData *>(drag->poin);
if (!drop_data) {
return false;
}
@@ -871,7 +875,7 @@ static char *datastack_drop_tooltip(bContext *UNUSED(C),
const int UNUSED(xy[2]),
struct wmDropBox *UNUSED(drop))
{
- StackDropData *drop_data = drag->poin;
+ StackDropData *drop_data = reinterpret_cast<StackDropData *>(drag->poin);
switch (drop_data->drop_action) {
case DATA_STACK_DROP_REORDER:
return BLI_strdup(TIP_("Reorder"));
@@ -893,7 +897,7 @@ static char *datastack_drop_tooltip(bContext *UNUSED(C),
}
break;
}
- return NULL;
+ return nullptr;
}
static void datastack_drop_link(bContext *C, StackDropData *drop_data)
@@ -948,20 +952,28 @@ static void datastack_drop_copy(bContext *C, StackDropData *drop_data)
switch (drop_data->drag_tselem->type) {
case TSE_MODIFIER:
if (drop_data->ob_parent->type == OB_GPENCIL && ob_dst->type == OB_GPENCIL) {
- ED_object_gpencil_modifier_copy_to_object(ob_dst, drop_data->drag_directdata);
+ ED_object_gpencil_modifier_copy_to_object(
+ ob_dst, reinterpret_cast<GpencilModifierData *>(drop_data->drag_directdata));
}
else if (drop_data->ob_parent->type != OB_GPENCIL && ob_dst->type != OB_GPENCIL) {
ED_object_modifier_copy_to_object(
- C, ob_dst, drop_data->ob_parent, drop_data->drag_directdata);
+ C,
+ ob_dst,
+ drop_data->ob_parent,
+ reinterpret_cast<ModifierData *>(drop_data->drag_directdata));
}
break;
case TSE_CONSTRAINT:
if (tselem->type == TSE_POSE_CHANNEL) {
ED_object_constraint_copy_for_pose(
- bmain, ob_dst, drop_data->drop_te->directdata, drop_data->drag_directdata);
+ bmain,
+ ob_dst,
+ reinterpret_cast<bPoseChannel *>(drop_data->drop_te->directdata),
+ reinterpret_cast<bConstraint *>(drop_data->drag_directdata));
}
else {
- ED_object_constraint_copy_for_object(bmain, ob_dst, drop_data->drag_directdata);
+ ED_object_constraint_copy_for_object(
+ bmain, ob_dst, reinterpret_cast<bConstraint *>(drop_data->drag_directdata));
}
break;
case TSE_GPENCIL_EFFECT: {
@@ -969,7 +981,8 @@ static void datastack_drop_copy(bContext *C, StackDropData *drop_data)
return;
}
- ED_object_shaderfx_copy(ob_dst, drop_data->drag_directdata);
+ ED_object_shaderfx_copy(ob_dst,
+ reinterpret_cast<ShaderFxData *>(drop_data->drag_directdata));
break;
}
}
@@ -995,11 +1008,16 @@ static void datastack_drop_reorder(bContext *C, ReportList *reports, StackDropDa
if (ob->type == OB_GPENCIL) {
index = outliner_get_insert_index(
drag_te, drop_te, insert_type, &ob->greasepencil_modifiers);
- ED_object_gpencil_modifier_move_to_index(reports, ob, drop_data->drag_directdata, index);
+ ED_object_gpencil_modifier_move_to_index(
+ reports,
+ ob,
+ reinterpret_cast<GpencilModifierData *>(drop_data->drag_directdata),
+ index);
}
else {
index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->modifiers);
- ED_object_modifier_move_to_index(reports, ob, drop_data->drag_directdata, index);
+ ED_object_modifier_move_to_index(
+ reports, ob, reinterpret_cast<ModifierData *>(drop_data->drag_directdata), index);
}
break;
case TSE_CONSTRAINT:
@@ -1010,12 +1028,14 @@ static void datastack_drop_reorder(bContext *C, ReportList *reports, StackDropDa
else {
index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->constraints);
}
- ED_object_constraint_move_to_index(ob, drop_data->drag_directdata, index);
+ ED_object_constraint_move_to_index(
+ ob, reinterpret_cast<bConstraint *>(drop_data->drag_directdata), index);
break;
case TSE_GPENCIL_EFFECT:
index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->shader_fx);
- ED_object_shaderfx_move_to_index(reports, ob, drop_data->drag_directdata, index);
+ ED_object_shaderfx_move_to_index(
+ reports, ob, reinterpret_cast<ShaderFxData *>(drop_data->drag_directdata), index);
}
}
@@ -1025,9 +1045,9 @@ static int datastack_drop_invoke(bContext *C, wmOperator *op, const wmEvent *eve
return OPERATOR_CANCELLED;
}
- ListBase *lb = event->customdata;
- wmDrag *drag = lb->first;
- StackDropData *drop_data = drag->poin;
+ ListBase *lb = reinterpret_cast<ListBase *>(event->customdata);
+ wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first);
+ StackDropData *drop_data = reinterpret_cast<StackDropData *>(drag->poin);
switch (drop_data->drop_action) {
case DATA_STACK_DROP_LINK:
@@ -1062,19 +1082,19 @@ void OUTLINER_OT_datastack_drop(wmOperatorType *ot)
/* ******************** Collection Drop Operator *********************** */
-typedef struct CollectionDrop {
+struct CollectionDrop {
Collection *from;
Collection *to;
TreeElement *te;
TreeElementInsertType insert_type;
-} CollectionDrop;
+};
static Collection *collection_parent_from_ID(ID *id)
{
/* Can't change linked parent collections. */
if (!id || ID_IS_LINKED(id)) {
- return NULL;
+ return nullptr;
}
/* Also support dropping into/from scene collection. */
@@ -1085,17 +1105,15 @@ static Collection *collection_parent_from_ID(ID *id)
return (Collection *)id;
}
- return NULL;
+ return nullptr;
}
-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;
}
@@ -1110,8 +1128,8 @@ static bool collection_drop_init(bContext *C,
return false;
}
- wmDragID *drag_id = drag->ids.first;
- if (drag_id == NULL) {
+ wmDragID *drag_id = reinterpret_cast<wmDragID *>(drag->ids.first);
+ if (drag_id == nullptr) {
return false;
}
@@ -1123,12 +1141,12 @@ 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) {
- from_collection = NULL;
+ if (is_link) {
+ from_collection = nullptr;
}
/* Currently this should not be allowed, cannot edit items in an override of a Collection. */
- if (from_collection != NULL && ID_IS_OVERRIDE_LIBRARY(from_collection)) {
+ if (from_collection != nullptr && ID_IS_OVERRIDE_LIBRARY(from_collection)) {
return false;
}
@@ -1164,7 +1182,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 +1219,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 : nullptr;
+
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"));
@@ -1244,7 +1263,7 @@ static char *collection_drop_tooltip(bContext *C,
}
}
}
- return NULL;
+ return nullptr;
}
static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
@@ -1256,16 +1275,16 @@ static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmE
return OPERATOR_CANCELLED;
}
- ListBase *lb = event->customdata;
- wmDrag *drag = lb->first;
+ ListBase *lb = reinterpret_cast<ListBase *>(event->customdata);
+ wmDrag *drag = reinterpret_cast<wmDrag *>(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;
}
/* Before/after insert handling. */
- Collection *relative = NULL;
+ Collection *relative = nullptr;
bool relative_after = false;
if (ELEM(data.insert_type, TE_INSERT_BEFORE, TE_INSERT_AFTER)) {
@@ -1274,8 +1293,8 @@ static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmE
relative = data.to;
relative_after = (data.insert_type == TE_INSERT_AFTER);
- TreeElement *parent_te = outliner_find_parent_element(&space_outliner->tree, NULL, data.te);
- data.to = (parent_te) ? outliner_collection_from_tree_element(parent_te) : NULL;
+ TreeElement *parent_te = outliner_find_parent_element(&space_outliner->tree, nullptr, data.te);
+ data.to = (parent_te) ? outliner_collection_from_tree_element(parent_te) : nullptr;
}
if (!data.to) {
@@ -1288,7 +1307,7 @@ static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmE
LISTBASE_FOREACH (wmDragID *, drag_id, &drag->ids) {
/* Ctrl enables linking, so we don't need a from collection then. */
- Collection *from = (event->ctrl) ? NULL : collection_parent_from_ID(drag_id->from_parent);
+ Collection *from = (event->ctrl) ? nullptr : collection_parent_from_ID(drag_id->from_parent);
if (GS(drag_id->id->name) == ID_OB) {
/* Move/link object into collection. */
@@ -1400,10 +1419,10 @@ static int outliner_item_drag_drop_invoke(bContext *C,
TSE_GPENCIL_EFFECT_BASE);
const int wm_drag_type = use_datastack_drag ? WM_DRAG_DATASTACK : WM_DRAG_ID;
- wmDrag *drag = WM_event_start_drag(C, data.icon, wm_drag_type, NULL, 0.0, WM_DRAG_NOP);
+ wmDrag *drag = WM_event_start_drag(C, data.icon, wm_drag_type, nullptr, 0.0, WM_DRAG_NOP);
if (use_datastack_drag) {
- TreeElement *te_bone = NULL;
+ TreeElement *te_bone = nullptr;
bPoseChannel *pchan = outliner_find_parent_bone(te, &te_bone);
datastack_drop_data_init(drag, (Object *)tselem->id, pchan, te, tselem, te->directdata);
}
@@ -1417,9 +1436,7 @@ static int outliner_item_drag_drop_invoke(bContext *C,
}
/* Gather all selected elements. */
- struct IDsSelectedData selected = {
- .selected_array = {NULL, NULL},
- };
+ IDsSelectedData selected{};
if (GS(data.drag_id->name) == ID_OB) {
outliner_tree_traverse(space_outliner,
@@ -1466,7 +1483,7 @@ static int outliner_item_drag_drop_invoke(bContext *C,
}
/* Find parent collection. */
- Collection *parent = NULL;
+ Collection *parent = nullptr;
if (te_selected->parent) {
for (TreeElement *te_parent = te_selected->parent; te_parent;
@@ -1519,16 +1536,20 @@ void outliner_dropboxes(void)
{
ListBase *lb = WM_dropboxmap_find("Outliner", SPACE_OUTLINER, RGN_TYPE_WINDOW);
- WM_dropbox_add(lb, "OUTLINER_OT_parent_drop", parent_drop_poll, NULL, NULL, NULL);
- WM_dropbox_add(lb, "OUTLINER_OT_parent_clear", parent_clear_poll, NULL, NULL, NULL);
- WM_dropbox_add(lb, "OUTLINER_OT_scene_drop", scene_drop_poll, NULL, NULL, NULL);
- WM_dropbox_add(lb, "OUTLINER_OT_material_drop", material_drop_poll, NULL, NULL, NULL);
- WM_dropbox_add(
- lb, "OUTLINER_OT_datastack_drop", datastack_drop_poll, NULL, NULL, datastack_drop_tooltip);
+ WM_dropbox_add(lb, "OUTLINER_OT_parent_drop", parent_drop_poll, nullptr, nullptr, nullptr);
+ WM_dropbox_add(lb, "OUTLINER_OT_parent_clear", parent_clear_poll, nullptr, nullptr, nullptr);
+ WM_dropbox_add(lb, "OUTLINER_OT_scene_drop", scene_drop_poll, nullptr, nullptr, nullptr);
+ WM_dropbox_add(lb, "OUTLINER_OT_material_drop", material_drop_poll, nullptr, nullptr, nullptr);
+ WM_dropbox_add(lb,
+ "OUTLINER_OT_datastack_drop",
+ datastack_drop_poll,
+ nullptr,
+ nullptr,
+ datastack_drop_tooltip);
WM_dropbox_add(lb,
"OUTLINER_OT_collection_drop",
collection_drop_poll,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
collection_drop_tooltip);
}
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.cc
index a586f268128..5fd7559370f 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.cc
@@ -78,7 +78,12 @@
#include "RNA_access.h"
-#include "outliner_intern.h"
+#include "outliner_intern.hh"
+#include "tree/tree_display.hh"
+#include "tree/tree_element.hh"
+#include "tree/tree_element_rna.hh"
+
+using namespace blender::ed::outliner;
/* Disable - this is far too slow - campbell. */
/* #define USE_GROUP_SELECT */
@@ -93,7 +98,7 @@ static void outliner_tree_dimensions_impl(SpaceOutliner *space_outliner,
{
LISTBASE_FOREACH (TreeElement *, te, lb) {
*width = MAX2(*width, te->xend);
- if (height != NULL) {
+ if (height != nullptr) {
*height += UI_UNIT_Y;
}
@@ -102,7 +107,7 @@ static void outliner_tree_dimensions_impl(SpaceOutliner *space_outliner,
outliner_tree_dimensions_impl(space_outliner, &te->subtree, width, height);
}
else {
- outliner_tree_dimensions_impl(space_outliner, &te->subtree, width, NULL);
+ outliner_tree_dimensions_impl(space_outliner, &te->subtree, width, nullptr);
}
}
}
@@ -119,7 +124,7 @@ void outliner_tree_dimensions(SpaceOutliner *space_outliner, int *r_width, int *
*/
static bool is_object_data_in_editmode(const ID *id, const Object *obact)
{
- if (id == NULL) {
+ if (id == nullptr) {
return false;
}
@@ -141,9 +146,7 @@ static void restrictbutton_recursive_ebone(bArmature *arm,
int flag,
bool set_flag)
{
- EditBone *ebone;
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (ED_armature_ebone_is_child_recursive(ebone_parent, ebone)) {
if (set_flag) {
ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
@@ -158,8 +161,7 @@ static void restrictbutton_recursive_ebone(bArmature *arm,
static void restrictbutton_recursive_bone(Bone *bone_parent, int flag, bool set_flag)
{
- Bone *bone;
- for (bone = bone_parent->childbase.first; bone; bone = bone->next) {
+ LISTBASE_FOREACH (Bone *, bone, &bone_parent->childbase) {
if (set_flag) {
bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
bone->flag |= flag;
@@ -196,7 +198,7 @@ static void restrictbutton_bone_select_fn(bContext *C, void *UNUSED(poin), void
restrictbutton_recursive_bone(bone, BONE_UNSELECTABLE, (bone->flag & BONE_UNSELECTABLE) != 0);
}
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
}
static void restrictbutton_ebone_select_fn(bContext *C, void *poin, void *poin2)
@@ -213,7 +215,7 @@ static void restrictbutton_ebone_select_fn(bContext *C, void *poin, void *poin2)
arm, ebone, BONE_UNSELECTABLE, (ebone->flag & BONE_UNSELECTABLE) != 0);
}
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
}
static void restrictbutton_ebone_visibility_fn(bContext *C, void *poin, void *poin2)
@@ -228,7 +230,7 @@ static void restrictbutton_ebone_visibility_fn(bContext *C, void *poin, void *po
restrictbutton_recursive_ebone(arm, ebone, BONE_HIDDEN_A, (ebone->flag & BONE_HIDDEN_A) != 0);
}
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
}
static void restrictbutton_gp_layer_flag_fn(bContext *C, void *poin, void *UNUSED(poin2))
@@ -236,14 +238,14 @@ static void restrictbutton_gp_layer_flag_fn(bContext *C, void *poin, void *UNUSE
ID *id = (ID *)poin;
DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, nullptr);
}
static void restrictbutton_id_user_toggle(bContext *UNUSED(C), void *poin, void *UNUSED(poin2))
{
ID *id = (ID *)poin;
- BLI_assert(id != NULL);
+ BLI_assert(id != nullptr);
if (id->flag & LIB_FAKEUSER) {
id_us_plus(id);
@@ -281,7 +283,8 @@ static void outliner_object_set_flag_recursive_fn(bContext *C,
Object *ob_parent = ob ? ob : base->object;
- for (Object *ob_iter = bmain->objects.first; ob_iter; ob_iter = ob_iter->id.next) {
+ for (Object *ob_iter = reinterpret_cast<Object *>(bmain->objects.first); ob_iter;
+ ob_iter = reinterpret_cast<Object *>(ob_iter->id.next)) {
if (BKE_object_is_child_recursive(ob_parent, ob_iter)) {
if (ob) {
RNA_id_pointer_create(&ob_iter->id, &ptr);
@@ -290,7 +293,7 @@ static void outliner_object_set_flag_recursive_fn(bContext *C,
else {
Base *base_iter = BKE_view_layer_base_find(view_layer, ob_iter);
/* Child can be in a collection excluded from viewlayer. */
- if (base_iter == NULL) {
+ if (base_iter == nullptr) {
continue;
}
RNA_pointer_create(&scene->id, &RNA_ObjectBase, base_iter, &ptr);
@@ -315,9 +318,9 @@ static void outliner_object_set_flag_recursive_fn(bContext *C,
*/
static void outliner__object_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
{
- Object *ob = poin;
- char *propname = poin2;
- outliner_object_set_flag_recursive_fn(C, NULL, ob, propname);
+ Object *ob = reinterpret_cast<Object *>(poin);
+ char *propname = reinterpret_cast<char *>(poin2);
+ outliner_object_set_flag_recursive_fn(C, nullptr, ob, propname);
}
/**
@@ -325,9 +328,9 @@ static void outliner__object_set_flag_recursive_fn(bContext *C, void *poin, void
*/
static void outliner__base_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
{
- Base *base = poin;
- char *propname = poin2;
- outliner_object_set_flag_recursive_fn(C, base, NULL, propname);
+ Base *base = reinterpret_cast<Base *>(poin);
+ char *propname = reinterpret_cast<char *>(poin2);
+ outliner_object_set_flag_recursive_fn(C, base, nullptr, propname);
}
/** Create either a RNA_LayerCollection or a RNA_Collection pointer. */
@@ -392,9 +395,9 @@ static void outliner_collection_set_flag_recursive(Scene *scene,
/* Keep going recursively. */
ListBase *lb = (layer_collection ? &layer_collection->layer_collections : &collection->children);
LISTBASE_FOREACH (Link *, link, lb) {
- LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : NULL;
+ LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : nullptr;
Collection *collection_iter = layer_collection ?
- (collection ? layer_collection_iter->collection : NULL) :
+ (collection ? layer_collection_iter->collection : nullptr) :
((CollectionChild *)link)->collection;
outliner_collection_set_flag_recursive(scene,
view_layer,
@@ -458,9 +461,9 @@ static bool outliner_collection_is_isolated(Scene *scene,
/* Keep going recursively. */
ListBase *lb = (layer_collection ? &layer_collection->layer_collections : &collection->children);
LISTBASE_FOREACH (Link *, link, lb) {
- LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : NULL;
+ LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : nullptr;
Collection *collection_iter = layer_collection ?
- (collection ? layer_collection_iter->collection : NULL) :
+ (collection ? layer_collection_iter->collection : nullptr) :
((CollectionChild *)link)->collection;
if (layer_collection_iter && layer_collection_iter->flag & LAYER_COLLECTION_EXCLUDE) {
continue;
@@ -488,11 +491,13 @@ void outliner_collection_isolate_flag(Scene *scene,
const bool value)
{
PointerRNA ptr;
- const bool is_hide = strstr(propname, "hide_") != NULL;
+ const bool is_hide = strstr(propname, "hide_") != nullptr;
- LayerCollection *top_layer_collection = layer_collection ? view_layer->layer_collections.first :
- NULL;
- Collection *top_collection = collection ? scene->master_collection : NULL;
+ LayerCollection *top_layer_collection = layer_collection ?
+ reinterpret_cast<LayerCollection *>(
+ view_layer->layer_collections.first) :
+ nullptr;
+ Collection *top_collection = collection ? scene->master_collection : nullptr;
bool was_isolated = (value == is_hide);
was_isolated &= outliner_collection_is_isolated(scene,
@@ -504,14 +509,14 @@ void outliner_collection_isolate_flag(Scene *scene,
top_collection);
if (was_isolated) {
- const bool default_value = RNA_property_boolean_get_default(NULL, layer_or_collection_prop);
+ const bool default_value = RNA_property_boolean_get_default(nullptr, layer_or_collection_prop);
/* Make every collection go back to its default "visibility" state. */
outliner_collection_set_flag_recursive(scene,
view_layer,
top_layer_collection,
top_collection,
layer_or_collection_prop,
- NULL,
+ nullptr,
default_value);
return;
}
@@ -522,12 +527,17 @@ void outliner_collection_isolate_flag(Scene *scene,
top_layer_collection,
top_collection,
layer_or_collection_prop,
- NULL,
+ nullptr,
is_hide);
/* Make this collection and its children collections the only "visible". */
- outliner_collection_set_flag_recursive(
- scene, view_layer, layer_collection, collection, layer_or_collection_prop, NULL, !is_hide);
+ outliner_collection_set_flag_recursive(scene,
+ view_layer,
+ layer_collection,
+ collection,
+ layer_or_collection_prop,
+ nullptr,
+ !is_hide);
/* Make this collection direct parents also "visible". */
if (layer_collection) {
@@ -541,7 +551,7 @@ void outliner_collection_isolate_flag(Scene *scene,
while (lc_parent != layer_collection) {
outliner_layer_or_collection_pointer_create(
- scene, lc_parent, collection ? lc_parent->collection : NULL, &ptr);
+ scene, lc_parent, collection ? lc_parent->collection : nullptr, &ptr);
RNA_property_boolean_set(&ptr, layer_or_collection_prop, !is_hide);
LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_parent->layer_collections) {
@@ -555,7 +565,7 @@ void outliner_collection_isolate_flag(Scene *scene,
else {
CollectionParent *parent;
Collection *child = collection;
- while ((parent = child->parents.first)) {
+ while ((parent = reinterpret_cast<CollectionParent *>(child->parents.first))) {
if (parent->collection->flag & COLLECTION_IS_MASTER) {
break;
}
@@ -594,8 +604,8 @@ static void outliner_collection_set_flag_recursive_fn(bContext *C,
PropertyRNA *layer_or_collection_prop = RNA_struct_type_find_property(struct_rna, propname);
const bool value = RNA_property_boolean_get(&ptr, layer_or_collection_prop);
- PropertyRNA *base_or_object_prop = NULL;
- if (layer_collection != NULL) {
+ PropertyRNA *base_or_object_prop = nullptr;
+ if (layer_collection != nullptr) {
/* If we are toggling Layer collections we still want to change the properties of the base
* or the objects. If we have a matching property, toggle it as well, it can be NULL. */
struct_rna = collection ? &RNA_Object : &RNA_ObjectBase;
@@ -634,9 +644,9 @@ static void view_layer__layer_collection_set_flag_recursive_fn(bContext *C,
void *poin,
void *poin2)
{
- LayerCollection *layer_collection = poin;
- char *propname = poin2;
- outliner_collection_set_flag_recursive_fn(C, layer_collection, NULL, propname);
+ LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(poin);
+ char *propname = reinterpret_cast<char *>(poin2);
+ outliner_collection_set_flag_recursive_fn(C, layer_collection, nullptr, propname);
}
/**
@@ -645,8 +655,8 @@ static void view_layer__layer_collection_set_flag_recursive_fn(bContext *C,
*/
static void view_layer__collection_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
{
- LayerCollection *layer_collection = poin;
- char *propname = poin2;
+ LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(poin);
+ char *propname = reinterpret_cast<char *>(poin2);
outliner_collection_set_flag_recursive_fn(
C, layer_collection, layer_collection->collection, propname);
}
@@ -657,18 +667,20 @@ static void view_layer__collection_set_flag_recursive_fn(bContext *C, void *poin
*/
static void scenes__collection_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
{
- Collection *collection = poin;
- char *propname = poin2;
- outliner_collection_set_flag_recursive_fn(C, NULL, collection, propname);
+ Collection *collection = reinterpret_cast<Collection *>(poin);
+ char *propname = reinterpret_cast<char *>(poin2);
+ outliner_collection_set_flag_recursive_fn(C, nullptr, collection, propname);
}
+/* FIXME: See comment above #WM_msg_publish_rna_prop(). */
+extern "C" {
static void namebutton_fn(bContext *C, void *tsep, char *oldname)
{
Main *bmain = CTX_data_main(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
struct wmMsgBus *mbus = CTX_wm_message_bus(C);
BLI_mempool *ts = space_outliner->treestore;
- TreeStoreElem *tselem = tsep;
+ TreeStoreElem *tselem = reinterpret_cast<TreeStoreElem *>(tsep);
if (ts && tselem) {
TreeElement *te = outliner_find_tree_element(&space_outliner->tree, tselem);
@@ -680,16 +692,16 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
switch (GS(tselem->id->name)) {
case ID_MA:
- WM_event_add_notifier(C, NC_MATERIAL, NULL);
+ WM_event_add_notifier(C, NC_MATERIAL, nullptr);
break;
case ID_TE:
- WM_event_add_notifier(C, NC_TEXTURE, NULL);
+ WM_event_add_notifier(C, NC_TEXTURE, nullptr);
break;
case ID_IM:
- WM_event_add_notifier(C, NC_IMAGE, NULL);
+ WM_event_add_notifier(C, NC_IMAGE, nullptr);
break;
case ID_SCE:
- WM_event_add_notifier(C, NC_SCENE, NULL);
+ WM_event_add_notifier(C, NC_SCENE, nullptr);
break;
case ID_OB: {
Object *ob = (Object *)tselem->id;
@@ -702,7 +714,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
default:
break;
}
- WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_RENAME, nullptr);
/* Check the library target exists */
if (te->idcode == ID_LI) {
@@ -732,7 +744,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
switch (tselem->type) {
case TSE_DEFGROUP: {
Object *ob = (Object *)tselem->id;
- bDeformGroup *vg = te->directdata;
+ bDeformGroup *vg = reinterpret_cast<bDeformGroup *>(te->directdata);
BKE_object_defgroup_unique_name(vg, ob);
WM_msg_publish_rna_prop(mbus, &ob->id, vg, VertexGroup, name);
break;
@@ -746,7 +758,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
case TSE_EBONE: {
bArmature *arm = (bArmature *)tselem->id;
if (arm->edbo) {
- EditBone *ebone = te->directdata;
+ EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata);
char newname[sizeof(ebone->name)];
/* restore bone name */
@@ -754,7 +766,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
BLI_strncpy(ebone->name, oldname, sizeof(ebone->name));
ED_armature_bone_rename(bmain, arm, oldname, newname);
WM_msg_publish_rna_prop(mbus, &arm->id, ebone, EditBone, name);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
}
break;
}
@@ -764,7 +776,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
outliner_viewcontext_init(C, &tvc);
bArmature *arm = (bArmature *)tselem->id;
- Bone *bone = te->directdata;
+ Bone *bone = reinterpret_cast<Bone *>(te->directdata);
char newname[sizeof(bone->name)];
/* always make current object active */
@@ -775,7 +787,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
BLI_strncpy(bone->name, oldname, sizeof(bone->name));
ED_armature_bone_rename(bmain, arm, oldname, newname);
WM_msg_publish_rna_prop(mbus, &arm->id, bone, Bone, name);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
break;
}
case TSE_POSE_CHANNEL: {
@@ -784,7 +796,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
Object *ob = (Object *)tselem->id;
bArmature *arm = (bArmature *)ob->data;
- bPoseChannel *pchan = te->directdata;
+ bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata);
char newname[sizeof(pchan->name)];
/* always make current pose-bone active */
@@ -795,14 +807,15 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
/* restore bone name */
BLI_strncpy(newname, pchan->name, sizeof(pchan->name));
BLI_strncpy(pchan->name, oldname, sizeof(pchan->name));
- ED_armature_bone_rename(bmain, ob->data, oldname, newname);
+ ED_armature_bone_rename(
+ bmain, reinterpret_cast<bArmature *>(ob->data), oldname, newname);
WM_msg_publish_rna_prop(mbus, &arm->id, pchan->bone, Bone, name);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
break;
}
case TSE_POSEGRP: {
Object *ob = (Object *)tselem->id; /* id = object. */
- bActionGroup *grp = te->directdata;
+ bActionGroup *grp = reinterpret_cast<bActionGroup *>(te->directdata);
BLI_uniquename(&ob->pose->agroups,
grp,
@@ -816,7 +829,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
}
case TSE_GP_LAYER: {
bGPdata *gpd = (bGPdata *)tselem->id; /* id = GP Datablock */
- bGPDlayer *gpl = te->directdata;
+ bGPDlayer *gpl = reinterpret_cast<bGPDlayer *>(te->directdata);
/* always make layer active */
BKE_gpencil_layer_active_set(gpd, gpl);
@@ -832,7 +845,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
}
case TSE_R_LAYER: {
Scene *scene = (Scene *)tselem->id;
- ViewLayer *view_layer = te->directdata;
+ ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata);
/* Restore old name. */
char newname[sizeof(view_layer->name)];
@@ -842,7 +855,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
/* Rename, preserving animation and compositing data. */
BKE_view_layer_rename(bmain, scene, view_layer, newname);
WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, ViewLayer, name);
- WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_RENAME, nullptr);
break;
}
case TSE_LAYER_COLLECTION: {
@@ -850,7 +863,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
Collection *collection = (Collection *)tselem->id;
BLI_libblock_ensure_unique_name(bmain, collection->id.name);
WM_msg_publish_rna_prop(mbus, &collection->id, &collection->id, ID, name);
- WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_RENAME, nullptr);
break;
}
}
@@ -858,8 +871,9 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
tselem->flag &= ~TSE_TEXTBUT;
}
}
+}
-typedef struct RestrictProperties {
+struct RestrictProperties {
bool initialized;
PropertyRNA *object_hide_viewport, *object_hide_select, *object_hide_render;
@@ -870,11 +884,11 @@ typedef struct RestrictProperties {
PropertyRNA *modifier_show_viewport, *modifier_show_render;
PropertyRNA *constraint_enable;
PropertyRNA *bone_hide_viewport;
-} RestrictProperties;
+};
/* We don't care about the value of the property
* but whether the property should be active or grayed out. */
-typedef struct RestrictPropertiesActive {
+struct RestrictPropertiesActive {
bool object_hide_viewport;
bool object_hide_select;
bool object_hide_render;
@@ -890,7 +904,7 @@ typedef struct RestrictPropertiesActive {
bool modifier_show_render;
bool constraint_enable;
bool bone_hide_viewport;
-} RestrictPropertiesActive;
+};
static void outliner_restrict_properties_enable_collection_set(
PointerRNA *collection_ptr, RestrictProperties *props, RestrictPropertiesActive *props_active)
@@ -982,8 +996,9 @@ static bool outliner_restrict_properties_collection_set(Scene *scene,
RestrictPropertiesActive *props_active)
{
TreeStoreElem *tselem = TREESTORE(te);
- LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ? te->directdata :
- NULL;
+ LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ?
+ reinterpret_cast<LayerCollection *>(te->directdata) :
+ nullptr;
Collection *collection = outliner_collection_from_tree_element(te);
if (collection->flag & COLLECTION_IS_MASTER) {
@@ -992,7 +1007,7 @@ static bool outliner_restrict_properties_collection_set(Scene *scene,
/* Create the PointerRNA. */
RNA_id_pointer_create(&collection->id, collection_ptr);
- if (layer_collection != NULL) {
+ if (layer_collection != nullptr) {
RNA_pointer_create(&scene->id, &RNA_LayerCollection, layer_collection, layer_collection_ptr);
}
@@ -1096,7 +1111,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
ELEM(space_outliner->outlinevis, SO_SCENES, SO_VIEW_LAYER)) {
if (space_outliner->show_restrict_flags & SO_RESTRICT_RENDER) {
/* View layer render toggle. */
- ViewLayer *layer = te->directdata;
+ ViewLayer *layer = reinterpret_cast<ViewLayer *>(te->directdata);
bt = uiDefIconButBitS(block,
UI_BTYPE_ICON_TOGGLE_N,
@@ -1113,7 +1128,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
0,
0,
TIP_("Use view layer for rendering"));
- UI_but_func_set(bt, restrictbutton_r_lay_fn, tselem->id, NULL);
+ UI_but_func_set(bt, restrictbutton_r_lay_fn, tselem->id, nullptr);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE);
}
@@ -1256,7 +1271,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
0,
-1,
-1,
- NULL);
+ nullptr);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
if (!props_active.constraint_enable) {
UI_but_flag_enable(bt, UI_BUT_INACTIVE);
@@ -1285,7 +1300,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
0,
-1,
-1,
- NULL);
+ nullptr);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
if (!props_active.modifier_show_viewport) {
UI_but_flag_enable(bt, UI_BUT_INACTIVE);
@@ -1308,7 +1323,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
0,
-1,
-1,
- NULL);
+ nullptr);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
if (!props_active.modifier_show_render) {
UI_but_flag_enable(bt, UI_BUT_INACTIVE);
@@ -1320,7 +1335,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
bPoseChannel *pchan = (bPoseChannel *)te->directdata;
Bone *bone = pchan->bone;
Object *ob = (Object *)tselem->id;
- bArmature *arm = ob->data;
+ bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
RNA_pointer_create(&arm->id, &RNA_Bone, bone, &ptr);
@@ -1342,7 +1357,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
-1,
TIP_("Restrict visibility in the 3D View\n"
"* Shift to set children"));
- UI_but_func_set(bt, restrictbutton_bone_visibility_fn, bone, NULL);
+ UI_but_func_set(bt, restrictbutton_bone_visibility_fn, bone, nullptr);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE);
}
@@ -1470,11 +1485,12 @@ static void outliner_draw_restrictbuts(uiBlock *block,
scene, te, &collection_ptr, &layer_collection_ptr, &props, &props_active)) {
LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ?
- te->directdata :
- NULL;
+ reinterpret_cast<LayerCollection *>(
+ te->directdata) :
+ nullptr;
Collection *collection = outliner_collection_from_tree_element(te);
- if (layer_collection != NULL) {
+ if (layer_collection != nullptr) {
if (space_outliner->show_restrict_flags & SO_RESTRICT_ENABLE) {
bt = uiDefIconButR_prop(block,
UI_BTYPE_ICON_TOGGLE,
@@ -1491,7 +1507,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
0,
0,
0,
- NULL);
+ nullptr);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
}
@@ -1605,7 +1621,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
TIP_("Globally disable in viewports\n"
"* Ctrl to isolate collection\n"
"* Shift to set inside collections and objects"));
- if (layer_collection != NULL) {
+ if (layer_collection != nullptr) {
UI_but_func_set(bt,
view_layer__collection_set_flag_recursive_fn,
layer_collection,
@@ -1642,7 +1658,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
TIP_("Globally disable in renders\n"
"* Ctrl to isolate collection\n"
"* Shift to set inside collections and objects"));
- if (layer_collection != NULL) {
+ if (layer_collection != nullptr) {
UI_but_func_set(bt,
view_layer__collection_set_flag_recursive_fn,
layer_collection,
@@ -1677,7 +1693,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
TIP_("Disable selection in viewport\n"
"* Ctrl to isolate collection\n"
"* Shift to set inside collections and objects"));
- if (layer_collection != NULL) {
+ if (layer_collection != nullptr) {
UI_but_func_set(bt,
view_layer__collection_set_flag_recursive_fn,
layer_collection,
@@ -1721,7 +1737,7 @@ static void outliner_draw_userbuts(uiBlock *block,
if (tselem->type == TSE_SOME_ID) {
uiBut *bt;
ID *id = tselem->id;
- const char *tip = NULL;
+ const char *tip = nullptr;
char buf[16] = "";
int but_flag = UI_BUT_DRAG_LOCK;
@@ -1738,7 +1754,7 @@ static void outliner_draw_userbuts(uiBlock *block,
te->ys,
UI_UNIT_X,
UI_UNIT_Y,
- NULL,
+ nullptr,
0.0,
0.0,
0,
@@ -1767,7 +1783,7 @@ static void outliner_draw_userbuts(uiBlock *block,
0,
0,
tip);
- UI_but_func_set(bt, restrictbutton_id_user_toggle, id, NULL);
+ UI_but_func_set(bt, restrictbutton_id_user_toggle, id, nullptr);
UI_but_flag_enable(bt, but_flag);
}
}
@@ -1791,7 +1807,7 @@ static bool outliner_draw_overrides_buts(uiBlock *block,
const bool do_draw = (te->ys + 2 * UI_UNIT_Y >= region->v2d.cur.ymin &&
te->ys <= region->v2d.cur.ymax);
int but_flag = UI_BUT_DRAG_LOCK;
- const char *tip = NULL;
+ const char *tip = nullptr;
TreeStoreElem *tselem = TREESTORE(te);
switch (tselem->type) {
@@ -1838,7 +1854,7 @@ static bool outliner_draw_overrides_buts(uiBlock *block,
if (do_draw &&
(item_has_warnings || (any_child_has_warnings && !TSELEM_OPEN(tselem, space_outliner)))) {
- if (tip == NULL) {
+ if (tip == nullptr) {
tip = TIP_("Some sub-items require attention");
}
uiBut *bt = uiDefIconBut(block,
@@ -1849,7 +1865,7 @@ static bool outliner_draw_overrides_buts(uiBlock *block,
te->ys,
UI_UNIT_X,
UI_UNIT_Y,
- NULL,
+ nullptr,
0.0,
0.0,
0.0,
@@ -1894,20 +1910,20 @@ static void outliner_draw_rnacols(ARegion *region, int sizex)
static void outliner_draw_rnabuts(
uiBlock *block, ARegion *region, SpaceOutliner *space_outliner, int sizex, ListBase *lb)
{
- PointerRNA *ptr;
+ PointerRNA ptr;
PropertyRNA *prop;
LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
if (te->ys + 2 * UI_UNIT_Y >= region->v2d.cur.ymin && te->ys <= region->v2d.cur.ymax) {
- if (tselem->type == TSE_RNA_PROPERTY) {
- ptr = &te->rnaptr;
- prop = te->directdata;
+ if (TreeElementRNAProperty *te_rna_prop = tree_element_cast<TreeElementRNAProperty>(te)) {
+ ptr = te_rna_prop->getPointerRNA();
+ prop = te_rna_prop->getPropertyRNA();
if (!TSELEM_OPEN(tselem, space_outliner)) {
if (RNA_property_type(prop) == PROP_POINTER) {
uiBut *but = uiDefAutoButR(block,
- ptr,
+ &ptr,
prop,
-1,
"",
@@ -1920,10 +1936,10 @@ static void outliner_draw_rnabuts(
}
else if (RNA_property_type(prop) == PROP_ENUM) {
uiDefAutoButR(block,
- ptr,
+ &ptr,
prop,
-1,
- NULL,
+ nullptr,
ICON_NONE,
sizex,
te->ys,
@@ -1932,7 +1948,7 @@ static void outliner_draw_rnabuts(
}
else {
uiDefAutoButR(block,
- ptr,
+ &ptr,
prop,
-1,
"",
@@ -1944,12 +1960,13 @@ static void outliner_draw_rnabuts(
}
}
}
- else if (tselem->type == TSE_RNA_ARRAY_ELEM) {
- ptr = &te->rnaptr;
- prop = te->directdata;
+ else if (TreeElementRNAArrayElement *te_rna_array_elem =
+ tree_element_cast<TreeElementRNAArrayElement>(te)) {
+ ptr = te_rna_array_elem->getPointerRNA();
+ prop = te_rna_array_elem->getPropertyRNA();
uiDefAutoButR(block,
- ptr,
+ &ptr,
prop,
te->index,
"",
@@ -1983,13 +2000,13 @@ static void outliner_buttons(const bContext *C,
/* If we add support to rename Sequence, need change this. */
if (tselem->type == TSE_EBONE) {
- len = sizeof(((EditBone *)0)->name);
+ len = sizeof(((EditBone *)nullptr)->name);
}
else if (tselem->type == TSE_MODIFIER) {
- len = sizeof(((ModifierData *)0)->name);
+ len = sizeof(((ModifierData *)nullptr)->name);
}
else if (tselem->id && GS(tselem->id->name) == ID_LI) {
- len = sizeof(((Library *)0)->filepath);
+ len = sizeof(((Library *)nullptr)->filepath);
}
else {
len = MAX_ID_NAME - 2;
@@ -2019,7 +2036,7 @@ static void outliner_buttons(const bContext *C,
tselem->flag &= ~TSE_TEXTBUT;
/* Bad! (notifier within draw) without this, we don't get a refresh. */
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, nullptr);
}
}
@@ -2036,7 +2053,7 @@ static void outliner_mode_toggle_fn(bContext *C, void *tselem_poin, void *UNUSED
}
/* Check that the item is actually an object. */
- BLI_assert(tselem->id != NULL && GS(tselem->id->name) == ID_OB);
+ BLI_assert(tselem->id != nullptr && GS(tselem->id->name) == ID_OB);
Object *ob = (Object *)tselem->id;
const bool object_data_shared = (ob->data == tvc.obact->data);
@@ -2105,13 +2122,13 @@ static void outliner_draw_mode_column_toggle(uiBlock *block,
te->ys,
UI_UNIT_X,
UI_UNIT_Y,
- NULL,
+ nullptr,
0.0,
0.0,
0.0,
0.0,
tip);
- UI_but_func_set(but, outliner_mode_toggle_fn, tselem, NULL);
+ UI_but_func_set(but, outliner_mode_toggle_fn, tselem, nullptr);
UI_but_flag_enable(but, UI_BUT_DRAG_LOCK);
/* Mode toggling handles its own undo state because undo steps need to be grouped. */
UI_but_flag_disable(but, UI_BUT_UNDO);
@@ -2143,12 +2160,86 @@ static void outliner_draw_mode_column(const bContext *C,
}
}
+/* Returns `true` if some warning was drawn for that element or one of its sub-elements (if it is
+ * not open). */
+static bool outliner_draw_warning_tree_element(uiBlock *block,
+ SpaceOutliner *space_outliner,
+ TreeElement *te,
+ TreeStoreElem *tselem,
+ const bool use_mode_column,
+ const int te_ys)
+{
+ if ((te->flag & TE_HAS_WARNING) == 0) {
+ /* If given element has no warning, recursively try to display the first sub-elements' warning.
+ */
+ if (!TSELEM_OPEN(tselem, space_outliner)) {
+ LISTBASE_FOREACH (TreeElement *, sub_te, &te->subtree) {
+ TreeStoreElem *sub_tselem = TREESTORE(sub_te);
+
+ if (outliner_draw_warning_tree_element(
+ block, space_outliner, sub_te, sub_tselem, use_mode_column, te_ys)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ int icon = ICON_NONE;
+ const char *tip = "";
+ const bool has_warning = tree_element_warnings_get(te, &icon, &tip);
+ BLI_assert(has_warning);
+ UNUSED_VARS_NDEBUG(has_warning);
+
+ /* Move the warnings a unit left in view layer mode. */
+ const short mode_column_offset = (use_mode_column && (space_outliner->outlinevis == SO_SCENES)) ?
+ UI_UNIT_X :
+ 0;
+
+ UI_block_emboss_set(block, UI_EMBOSS_NONE_OR_STATUS);
+ uiBut *but = uiDefIconBut(block,
+ UI_BTYPE_ICON_TOGGLE,
+ 0,
+ icon,
+ mode_column_offset,
+ te_ys,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ nullptr,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ tip);
+ /* No need for undo here, this is a pure info widget. */
+ UI_but_flag_disable(but, UI_BUT_UNDO);
+
+ return true;
+}
+
+static void outliner_draw_warning_column(const bContext *C,
+ uiBlock *block,
+ SpaceOutliner *space_outliner,
+ const bool use_mode_column,
+ ListBase *tree)
+{
+ LISTBASE_FOREACH (TreeElement *, te, tree) {
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ outliner_draw_warning_tree_element(block, space_outliner, te, tselem, use_mode_column, te->ys);
+
+ if (TSELEM_OPEN(tselem, space_outliner)) {
+ outliner_draw_warning_column(C, block, space_outliner, use_mode_column, &te->subtree);
+ }
+ }
+}
+
/* ****************************************************** */
/* Normal Drawing... */
TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
{
- TreeElementIcon data = {0};
+ TreeElementIcon data = {nullptr};
if (tselem->type != TSE_SOME_ID) {
switch (tselem->type) {
@@ -2182,7 +2273,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
data.drag_id = tselem->id;
break;
case TSE_CONSTRAINT: {
- bConstraint *con = te->directdata;
+ bConstraint *con = reinterpret_cast<bConstraint *>(te->directdata);
data.drag_id = tselem->id;
switch ((eBConstraint_Types)con->type) {
case CONSTRAINT_TYPE_CAMERASOLVER:
@@ -2295,9 +2386,11 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
data.drag_id = tselem->id;
if (ob->type != OB_GPENCIL) {
- ModifierData *md = BLI_findlink(&ob->modifiers, tselem->nr);
- const ModifierTypeInfo *modifier_type = BKE_modifier_get_info(md->type);
- if (modifier_type != NULL) {
+ ModifierData *md = reinterpret_cast<ModifierData *>(
+ BLI_findlink(&ob->modifiers, tselem->nr));
+ const ModifierTypeInfo *modifier_type = reinterpret_cast<const ModifierTypeInfo *>(
+ BKE_modifier_get_info((ModifierType)md->type));
+ if (modifier_type != nullptr) {
data.icon = modifier_type->icon;
}
else {
@@ -2306,7 +2399,8 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
}
else {
/* grease pencil modifiers */
- GpencilModifierData *md = BLI_findlink(&ob->greasepencil_modifiers, tselem->nr);
+ GpencilModifierData *md = reinterpret_cast<GpencilModifierData *>(
+ BLI_findlink(&ob->greasepencil_modifiers, tselem->nr));
switch ((GpencilModifierType)md->type) {
case eGpencilModifierType_Noise:
data.icon = ICON_MOD_NOISE;
@@ -2462,22 +2556,26 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case TSE_SEQUENCE_DUP:
data.icon = ICON_SEQ_STRIP_DUPLICATE;
break;
- case TSE_RNA_STRUCT:
- if (RNA_struct_is_ID(te->rnaptr.type)) {
- data.drag_id = (ID *)te->rnaptr.data;
- data.icon = RNA_struct_ui_icon(te->rnaptr.type);
+ case TSE_RNA_STRUCT: {
+ const TreeElementRNAStruct *te_rna_struct = tree_element_cast<TreeElementRNAStruct>(te);
+ const PointerRNA &ptr = te_rna_struct->getPointerRNA();
+
+ if (RNA_struct_is_ID(ptr.type)) {
+ data.drag_id = reinterpret_cast<ID *>(ptr.data);
+ data.icon = RNA_struct_ui_icon(ptr.type);
}
else {
- data.icon = RNA_struct_ui_icon(te->rnaptr.type);
+ data.icon = RNA_struct_ui_icon(ptr.type);
}
break;
+ }
case TSE_LAYER_COLLECTION:
case TSE_SCENE_COLLECTION_BASE:
case TSE_VIEW_COLLECTION_BASE: {
Collection *collection = outliner_collection_from_tree_element(te);
if (collection && !(collection->flag & COLLECTION_IS_MASTER)) {
data.drag_id = tselem->id;
- data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : NULL;
+ data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : nullptr;
}
data.icon = ICON_OUTLINER_COLLECTION;
@@ -2499,7 +2597,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
}
else if (tselem->id) {
data.drag_id = tselem->id;
- data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : NULL;
+ data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : nullptr;
if (GS(tselem->id->name) == ID_OB) {
Object *ob = (Object *)tselem->id;
@@ -2639,7 +2737,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
break;
case ID_TXT: {
Text *text = (Text *)tselem->id;
- if (text->filepath == NULL || (text->flags & TXT_ISMEM)) {
+ if (text->filepath == nullptr || (text->flags & TXT_ISMEM)) {
data.icon = ICON_FILE_TEXT;
}
else {
@@ -2772,7 +2870,7 @@ static void tselem_draw_icon(uiBlock *block,
UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, color, true);
}
else {
- UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, NULL, false);
+ UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, nullptr, false);
}
}
else {
@@ -2784,7 +2882,7 @@ static void tselem_draw_icon(uiBlock *block,
y,
UI_UNIT_X,
UI_UNIT_Y,
- NULL,
+ nullptr,
0.0,
0.0,
1.0,
@@ -2805,18 +2903,15 @@ static void outliner_draw_iconrow_number(const uiFontStyle *fstyle,
const float color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
float ufac = 0.25f * UI_UNIT_X;
float offset_x = (float)offsx + UI_UNIT_X * 0.35f;
+ rctf rect{};
+ BLI_rctf_init(&rect,
+ offset_x + ufac,
+ offset_x + UI_UNIT_X - ufac,
+ (float)ys - UI_UNIT_Y * 0.2f + ufac,
+ (float)ys - UI_UNIT_Y * 0.2f + UI_UNIT_Y - ufac);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_aa(
- &(const rctf){
- .xmin = offset_x + ufac,
- .xmax = offset_x + UI_UNIT_X - ufac,
- .ymin = (float)ys - UI_UNIT_Y * 0.2f + ufac,
- .ymax = (float)ys - UI_UNIT_Y * 0.2f + UI_UNIT_Y - ufac,
- },
- true,
- (float)UI_UNIT_Y / 2.0f - ufac,
- color);
+ UI_draw_roundbox_aa(&rect, true, (float)UI_UNIT_Y / 2.0f - ufac, color);
/* Now the numbers. */
uchar text_col[4];
@@ -2829,7 +2924,7 @@ static void outliner_draw_iconrow_number(const uiFontStyle *fstyle,
/* We treat +99 as 4 digits to make sure the (eyeballed) alignment looks nice. */
int num_digits = 4;
- char number_text[4] = "+99\0";
+ char number_text[4] = "+99";
if (num_elements < 100) {
BLI_snprintf(number_text, sizeof(number_text), "%d", num_elements);
num_digits = num_elements < 10 ? 1 : 2;
@@ -2864,28 +2959,12 @@ static void outliner_draw_active_indicator(const float minx,
{
const float ufac = UI_UNIT_X / 20.0f;
const float radius = UI_UNIT_Y / 4.0f;
+ rctf rect{};
+ BLI_rctf_init(&rect, minx, maxx, miny + ufac, maxy - ufac);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_aa(
- &(const rctf){
- .xmin = minx,
- .xmax = maxx,
- .ymin = miny + ufac,
- .ymax = maxy - ufac,
- },
- true,
- radius,
- icon_color);
- UI_draw_roundbox_aa(
- &(const rctf){
- .xmin = minx,
- .xmax = maxx,
- .ymin = miny + ufac,
- .ymax = maxy - ufac,
- },
- false,
- radius,
- icon_border);
+ UI_draw_roundbox_aa(&rect, true, radius, icon_color);
+ UI_draw_roundbox_aa(&rect, false, radius, icon_border);
GPU_blend(GPU_BLEND_ALPHA); /* Roundbox disables. */
}
@@ -2952,11 +3031,11 @@ int tree_element_id_type_to_index(TreeElement *te)
return id_index + OB_TYPE_MAX;
}
-typedef struct MergedIconRow {
+struct MergedIconRow {
eOLDrawState active[INDEX_ID_MAX + OB_TYPE_MAX];
int num_elements[INDEX_ID_MAX + OB_TYPE_MAX];
TreeElement *tree_element[INDEX_ID_MAX + OB_TYPE_MAX];
-} MergedIconRow;
+};
static void outliner_draw_iconrow(bContext *C,
uiBlock *block,
@@ -3014,7 +3093,7 @@ static void outliner_draw_iconrow(bContext *C,
else {
const int index = tree_element_id_type_to_index(te);
merged->num_elements[index]++;
- if ((merged->tree_element[index] == NULL) || (active > merged->active[index])) {
+ if ((merged->tree_element[index] == nullptr) || (active > merged->active[index])) {
merged->tree_element[index] = te;
}
merged->active[index] = MAX2(active, merged->active[index]);
@@ -3091,7 +3170,7 @@ static bool element_should_draw_faded(const TreeViewContext *tvc,
const Base *base = (te->directdata) ? (const Base *)te->directdata :
BKE_view_layer_base_find(
(ViewLayer *)tvc->view_layer, (Object *)ob);
- const bool is_visible = (base != NULL) && (base->flag & BASE_VISIBLE_VIEWLAYER);
+ const bool is_visible = (base != nullptr) && (base->flag & BASE_VISIBLE_VIEWLAYER);
if (!is_visible) {
return true;
}
@@ -3140,7 +3219,7 @@ static void outliner_draw_tree_element(bContext *C,
const float alpha_fac = element_should_draw_faded(tvc, te, tselem) ? 0.5f : 1.0f;
int xmax = region->v2d.cur.xmax;
- if ((tselem->flag & TSE_TEXTBUT) && (*te_edit == NULL)) {
+ if ((tselem->flag & TSE_TEXTBUT) && (*te_edit == nullptr)) {
*te_edit = te;
}
@@ -3157,7 +3236,7 @@ static void outliner_draw_tree_element(bContext *C,
Object *ob = (Object *)tselem->id;
Base *base = (te->directdata) ? (Base *)te->directdata :
BKE_view_layer_base_find(tvc->view_layer, ob);
- const bool is_selected = (base != NULL) && ((base->flag & BASE_SELECTED) != 0);
+ const bool is_selected = (base != nullptr) && ((base->flag & BASE_SELECTED) != 0);
if (ob == tvc->obact) {
active = OL_DRAWSEL_ACTIVE;
@@ -3246,9 +3325,10 @@ static void outliner_draw_tree_element(bContext *C,
offsx += 2 * ufac;
}
+ const TreeElementRNAStruct *te_rna_struct = tree_element_cast<TreeElementRNAStruct>(te);
if (ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION) ||
- ((tselem->type == TSE_RNA_STRUCT) && RNA_struct_is_ID(te->rnaptr.type))) {
- const BIFIconID lib_icon = UI_icon_from_library(tselem->id);
+ (te_rna_struct && RNA_struct_is_ID(te_rna_struct->getPointerRNA().type))) {
+ const BIFIconID lib_icon = (BIFIconID)UI_icon_from_library(tselem->id);
if (lib_icon != ICON_NONE) {
UI_icon_draw_alpha(
(float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, lib_icon, alpha_fac);
@@ -3281,7 +3361,7 @@ static void outliner_draw_tree_element(bContext *C,
GPU_blend(GPU_BLEND_ALPHA);
- MergedIconRow merged = {{0}};
+ MergedIconRow merged{};
outliner_draw_iconrow(C,
block,
fstyle,
@@ -3352,7 +3432,7 @@ static void outliner_draw_hierarchy_line(
/* Small vertical padding. */
const short line_padding = UI_UNIT_Y / 4.0f;
- /* >= is 1.0 for undashed lines. */
+ /* >= is 1.0 for un-dashed lines. */
immUniform1f("dash_factor", draw_dashed ? 0.5f : 1.0f);
immBegin(GPU_PRIM_LINES, 2);
@@ -3612,17 +3692,22 @@ static void outliner_draw_tree(bContext *C,
SpaceOutliner *space_outliner,
const float restrict_column_width,
const bool use_mode_column,
+ const bool use_warning_column,
TreeElement **te_edit)
{
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
int starty, startx;
/* Move the tree a unit left in view layer mode */
- short mode_column_offset = (use_mode_column && (space_outliner->outlinevis == SO_SCENES)) ?
- UI_UNIT_X :
- 0;
+ short columns_offset = (use_mode_column && (space_outliner->outlinevis == SO_SCENES)) ?
+ UI_UNIT_X :
+ 0;
if (!use_mode_column && (space_outliner->outlinevis == SO_VIEW_LAYER)) {
- mode_column_offset -= UI_UNIT_X;
+ columns_offset -= UI_UNIT_X;
+ }
+
+ if (use_warning_column) {
+ columns_offset += UI_UNIT_X;
}
GPU_blend(GPU_BLEND_ALPHA); /* Only once. */
@@ -3650,12 +3735,12 @@ static void outliner_draw_tree(bContext *C,
/* Draw hierarchy lines for collections and object children. */
starty = (int)region->v2d.tot.ymax - OL_Y_OFFSET;
- startx = mode_column_offset + UI_UNIT_X / 2 - (U.pixelsize + 1) / 2;
+ startx = columns_offset + UI_UNIT_X / 2 - (U.pixelsize + 1) / 2;
outliner_draw_hierarchy_lines(space_outliner, &space_outliner->tree, startx, &starty);
/* Items themselves. */
starty = (int)region->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET;
- startx = mode_column_offset;
+ startx = columns_offset;
LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
outliner_draw_tree_element(C,
block,
@@ -3755,7 +3840,7 @@ void draw_outliner(const bContext *C)
View2D *v2d = &region->v2d;
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
uiBlock *block;
- TreeElement *te_edit = NULL;
+ TreeElement *te_edit = nullptr;
TreeViewContext tvc;
outliner_viewcontext_init(C, &tvc);
@@ -3786,6 +3871,11 @@ void draw_outliner(const bContext *C)
const bool use_mode_column = (space_outliner->flag & SO_MODE_COLUMN) &&
(ELEM(space_outliner->outlinevis, SO_VIEW_LAYER, SO_SCENES));
+ const bool use_warning_column = ELEM(space_outliner->outlinevis,
+ SO_LIBRARIES,
+ SO_OVERRIDES_LIBRARY) &&
+ space_outliner->runtime->tree_display->hasWarnings();
+
/* Draw outliner stuff (background, hierarchy lines and names). */
const float restrict_column_width = outliner_restrict_columns_width(space_outliner);
outliner_back(region);
@@ -3797,6 +3887,7 @@ void draw_outliner(const bContext *C)
space_outliner,
restrict_column_width,
use_mode_column,
+ use_warning_column,
&te_edit);
/* Compute outliner dimensions after it has been drawn. */
@@ -3841,6 +3932,11 @@ void draw_outliner(const bContext *C)
outliner_draw_mode_column(C, block, &tvc, space_outliner, &space_outliner->tree);
}
+ /* Draw warning icons */
+ if (use_warning_column) {
+ outliner_draw_warning_column(C, block, space_outliner, use_mode_column, &space_outliner->tree);
+ }
+
UI_block_emboss_set(block, UI_EMBOSS);
/* Draw edit buttons if necessary. */
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.cc
index 9d4b14a1f57..b41b260b14a 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.cc
@@ -21,7 +21,7 @@
* \ingroup spoutliner
*/
-#include <string.h>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -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"
@@ -71,7 +73,10 @@
#include "GPU_material.h"
-#include "outliner_intern.h"
+#include "outliner_intern.hh"
+#include "tree/tree_element_rna.hh"
+
+using namespace blender::ed::outliner;
static void outliner_show_active(SpaceOutliner *space_outliner,
ARegion *region,
@@ -105,11 +110,11 @@ static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const
TreeElement *hovered_te = outliner_find_item_at_y(
space_outliner, &space_outliner->tree, view_mval[1]);
- TreeElement *icon_te = NULL;
+ TreeElement *icon_te = nullptr;
bool is_over_icon = false;
if (hovered_te) {
icon_te = outliner_find_item_at_x_in_row(
- space_outliner, hovered_te, view_mval[0], NULL, &is_over_icon);
+ space_outliner, hovered_te, view_mval[0], nullptr, &is_over_icon);
}
bool changed = false;
@@ -181,11 +186,11 @@ void outliner_item_openclose(SpaceOutliner *space_outliner,
}
}
-typedef struct OpenCloseData {
+struct OpenCloseData {
TreeStoreElem *prev_tselem;
bool open;
int x_location;
-} OpenCloseData;
+};
static int outliner_item_openclose_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
@@ -216,7 +221,7 @@ static int outliner_item_openclose_modal(bContext *C, wmOperator *op, const wmEv
data->prev_tselem = TREESTORE(te);
}
else {
- data->prev_tselem = NULL;
+ data->prev_tselem = nullptr;
}
}
else if (event->val == KM_RELEASE) {
@@ -256,7 +261,7 @@ static int outliner_item_openclose_invoke(bContext *C, wmOperator *op, const wmE
}
/* Store last expanded tselem and x coordinate of disclosure triangle */
- OpenCloseData *toggle_data = MEM_callocN(sizeof(OpenCloseData), "open_close_data");
+ OpenCloseData *toggle_data = MEM_cnew<OpenCloseData>("open_close_data");
toggle_data->prev_tselem = tselem;
toggle_data->open = open;
toggle_data->x_location = te->xs;
@@ -373,7 +378,7 @@ static TreeElement *outliner_item_rename_find_active(const SpaceOutliner *space_
if (!active_element) {
BKE_report(reports, RPT_WARNING, "No active item to rename");
- return NULL;
+ return nullptr;
}
return active_element;
@@ -391,7 +396,7 @@ static TreeElement *outliner_item_rename_find_hovered(const SpaceOutliner *space
return hovered;
}
- return NULL;
+ return nullptr;
}
static int outliner_item_rename(bContext *C, wmOperator *op, const wmEvent *event)
@@ -450,12 +455,12 @@ static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeSto
Main *bmain = CTX_data_main(C);
ID *id = tselem->id;
- BLI_assert(id != NULL);
+ BLI_assert(id != nullptr);
BLI_assert(((tselem->type == TSE_SOME_ID) && (te->idcode != 0)) ||
(tselem->type == TSE_LAYER_COLLECTION));
UNUSED_VARS_NDEBUG(te);
- if (te->idcode == ID_LI && ((Library *)id)->parent != NULL) {
+ if (te->idcode == ID_LI && ((Library *)id)->parent != nullptr) {
BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked library '%s'", id->name);
return;
}
@@ -481,7 +486,7 @@ static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeSto
BKE_id_delete(bmain, id);
- WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_WINDOW, nullptr);
}
void id_delete_fn(bContext *C,
@@ -573,13 +578,13 @@ static int outliner_id_remap_exec(bContext *C, wmOperator *op)
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
const short id_type = (short)RNA_enum_get(op->ptr, "id_type");
- ID *old_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type),
- RNA_enum_get(op->ptr, "old_id"));
- ID *new_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type),
- RNA_enum_get(op->ptr, "new_id"));
+ ID *old_id = reinterpret_cast<ID *>(
+ BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "old_id")));
+ ID *new_id = reinterpret_cast<ID *>(
+ BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "new_id")));
/* check for invalid states */
- if (space_outliner == NULL) {
+ if (space_outliner == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -612,7 +617,7 @@ static int outliner_id_remap_exec(bContext *C, wmOperator *op)
* such as lights so freeing correctly refreshes. */
GPU_materials_free(bmain);
- WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_WINDOW, nullptr);
return OPERATOR_FINISHED;
}
@@ -627,8 +632,6 @@ static bool outliner_id_remap_find_tree_element(bContext *C,
TreeStoreElem *tselem = TREESTORE(te);
if ((tselem->type == TSE_SOME_ID) && tselem->id) {
- printf("found id %s (%p)!\n", tselem->id->name, tselem->id);
-
RNA_enum_set(op->ptr, "id_type", GS(tselem->id->name));
RNA_enum_set_identifier(C, op->ptr, "new_id", tselem->id->name + 2);
RNA_enum_set_identifier(C, op->ptr, "old_id", tselem->id->name + 2);
@@ -654,7 +657,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,
@@ -662,18 +665,18 @@ static const EnumPropertyItem *outliner_id_itemf(bContext *C,
PropertyRNA *UNUSED(prop),
bool *r_free)
{
- if (C == NULL) {
+ if (C == nullptr) {
return DummyRNA_NULL_items;
}
- EnumPropertyItem item_tmp = {0}, *item = NULL;
+ EnumPropertyItem item_tmp = {0}, *item = nullptr;
int totitem = 0;
int i = 0;
short id_type = (short)RNA_enum_get(ptr, "id_type");
- ID *id = which_libbase(CTX_data_main(C), id_type)->first;
+ ID *id = reinterpret_cast<ID *>(which_libbase(CTX_data_main(C), id_type)->first);
- for (; id; id = id->next) {
+ for (; id; id = reinterpret_cast<ID *>(id->next)) {
item_tmp.identifier = item_tmp.name = id->name + 2;
item_tmp.value = i++;
RNA_enum_item_add(&item, &totitem, &item_tmp);
@@ -703,10 +706,13 @@ 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);
- RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE | PROP_HIDDEN);
+ RNA_def_property_enum_funcs_runtime(prop, nullptr, nullptr, outliner_id_itemf);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_ENUM_NO_TRANSLATE | PROP_HIDDEN));
ot->prop = RNA_def_enum(ot->srna,
"new_id",
@@ -714,7 +720,7 @@ void OUTLINER_OT_id_remap(wmOperatorType *ot)
0,
"New ID",
"New ID to remap all selected IDs' users to");
- RNA_def_property_enum_funcs_runtime(ot->prop, NULL, NULL, outliner_id_itemf);
+ RNA_def_property_enum_funcs_runtime(ot->prop, nullptr, nullptr, outliner_id_itemf);
RNA_def_property_flag(ot->prop, PROP_ENUM_NO_TRANSLATE);
}
@@ -729,7 +735,7 @@ void id_remap_fn(bContext *C,
wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_id_remap", false);
PointerRNA op_props;
- BLI_assert(tselem->id != NULL);
+ BLI_assert(tselem->id != nullptr);
WM_operator_properties_create_ptr(&op_props, ot);
@@ -826,7 +832,7 @@ static int outliner_id_paste_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_WINDOW, nullptr);
BKE_reportf(op->reports, RPT_INFO, "%d data-block(s) pasted", num_pasted);
@@ -860,7 +866,7 @@ static int lib_relocate(
PointerRNA op_props;
int ret = 0;
- BLI_assert(te->idcode == ID_LI && tselem->id != NULL);
+ BLI_assert(te->idcode == ID_LI && tselem->id != nullptr);
UNUSED_VARS_NDEBUG(te);
WM_operator_properties_create_ptr(&op_props, ot);
@@ -1252,17 +1258,18 @@ static TreeElement *outliner_show_active_get_element(bContext *C,
Object *obact = OBACT(view_layer);
if (!obact) {
- return NULL;
+ return nullptr;
}
te = outliner_find_id(space_outliner, &space_outliner->tree, &obact->id);
- if (te != NULL && obact->type == OB_ARMATURE) {
+ if (te != nullptr && obact->type == OB_ARMATURE) {
/* traverse down the bone hierarchy in case of armature */
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);
}
@@ -1385,7 +1392,7 @@ void OUTLINER_OT_scroll_page(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
/* properties */
- prop = RNA_def_boolean(ot->srna, "up", 0, "Up", "Scroll up one page");
+ prop = RNA_def_boolean(ot->srna, "up", false, "Up", "Scroll up one page");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
@@ -1429,14 +1436,14 @@ static TreeElement *outliner_find_name(
}
/* nothing valid found */
- return NULL;
+ return nullptr;
}
static void outliner_find_panel(
Scene *UNUSED(scene), ARegion *region, SpaceOutliner *space_outliner, int again, int flags)
{
- ReportList *reports = NULL; /* CTX_wm_reports(C); */
- TreeElement *te = NULL;
+ ReportList *reports = nullptr; /* CTX_wm_reports(C); */
+ TreeElement *te = nullptr;
TreeElement *last_find;
TreeStoreElem *tselem;
int ytop, xdelta, prevFound = 0;
@@ -1453,7 +1460,7 @@ static void outliner_find_panel(
/* try to find matching element */
te = outliner_find_name(space_outliner, &space_outliner->tree, name, flags, last_find, &prevFound);
- if (te == NULL) {
+ if (te == nullptr) {
/* no more matches after previous, start from beginning again */
prevFound = 1;
te = outliner_find_name(space_outliner, &space_outliner->tree, name, flags, last_find, &prevFound);
@@ -1462,10 +1469,10 @@ static void outliner_find_panel(
else {
/* pop up panel - no previous, or user didn't want search after previous */
name[0] = '\0';
- /* XXX if (sbutton(name, 0, sizeof(name) - 1, "Find: ") && name[0]) { */
- /* te = outliner_find_name(space_outliner, &space_outliner->tree, name, flags, NULL, &prevFound); */
- /* } */
- /* else return; XXX RETURN! XXX */
+ // XXX if (sbutton(name, 0, sizeof(name) - 1, "Find: ") && name[0]) {
+ // te = outliner_find_name(space_outliner, &space_outliner->tree, name, flags, nullptr, &prevFound);
+ // }
+ // else return; XXX RETURN! XXX
}
/* do selection and reveal */
@@ -1481,7 +1488,7 @@ static void outliner_find_panel(
outliner_flag_set(space_outliner, &space_outliner->tree, TSE_SELECTED, 0);
tselem->flag |= TSE_SELECTED;
- /* make te->ys center of view */
+ /* Make `te->ys` center of view. */
ytop = (int)(te->ys + BLI_rctf_size_y(&region->v2d.mask) / 2);
if (ytop > 0) {
ytop = 0;
@@ -1489,7 +1496,7 @@ static void outliner_find_panel(
region->v2d.cur.ymax = (float)ytop;
region->v2d.cur.ymin = (float)(ytop - BLI_rctf_size_y(&region->v2d.mask));
- /* make te->xs ==> te->xend center of view */
+ /* Make `te->xs` ==> `te->xend` center of view. */
xdelta = (int)(te->xs - region->v2d.cur.xmin);
region->v2d.cur.xmin += xdelta;
region->v2d.cur.xmax += xdelta;
@@ -1582,7 +1589,7 @@ void OUTLINER_OT_show_one_level(wmOperatorType *ot)
/* no undo or registry, UI option */
/* properties */
- prop = RNA_def_boolean(ot->srna, "open", 1, "Open", "Expand all entries one level deep");
+ prop = RNA_def_boolean(ot->srna, "open", true, "Open", "Expand all entries one level deep");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
@@ -1694,7 +1701,7 @@ static bool ed_operator_outliner_datablocks_active(bContext *C)
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
return (space_outliner->outlinevis == SO_DATA_API);
}
- return 0;
+ return false;
}
/* Helper func to extract an RNA path from selected tree element
@@ -1709,13 +1716,8 @@ static void tree_element_to_path(TreeElement *te,
short *flag,
short *UNUSED(groupmode))
{
- ListBase hierarchy = {NULL, NULL};
- LinkData *ld;
- TreeElement *tem, *temnext;
- TreeStoreElem *tse /* , *tsenext */ /* UNUSED */;
- PointerRNA *ptr, *nextptr;
- PropertyRNA *prop;
- char *newpath = NULL;
+ ListBase hierarchy = {nullptr, nullptr};
+ char *newpath = nullptr;
/* optimize tricks:
* - Don't do anything if the selected item is a 'struct', but arrays are allowed
@@ -1734,20 +1736,19 @@ static void tree_element_to_path(TreeElement *te,
*/
/* step 1: flatten out hierarchy of parents into a flat chain */
- for (tem = te->parent; tem; tem = tem->parent) {
- ld = MEM_callocN(sizeof(LinkData), "LinkData for tree_element_to_path()");
+ for (TreeElement *tem = te->parent; tem; tem = tem->parent) {
+ LinkData *ld = MEM_cnew<LinkData>("LinkData for tree_element_to_path()");
ld->data = tem;
BLI_addhead(&hierarchy, ld);
}
/* step 2: step down hierarchy building the path
* (NOTE: addhead in previous loop was needed so that we can loop like this) */
- for (ld = hierarchy.first; ld; ld = ld->next) {
+ LISTBASE_FOREACH (LinkData *, ld, &hierarchy) {
/* get data */
- tem = (TreeElement *)ld->data;
- tse = TREESTORE(tem);
- ptr = &tem->rnaptr;
- prop = tem->directdata;
+ TreeElement *tem = (TreeElement *)ld->data;
+ TreeElementRNACommon *tem_rna = tree_element_cast<TreeElementRNACommon>(tem);
+ PointerRNA ptr = tem_rna->getPointerRNA();
/* check if we're looking for first ID, or appending to path */
if (*id) {
@@ -1755,23 +1756,23 @@ static void tree_element_to_path(TreeElement *te,
* - to prevent memory leaks, we must write to newpath not path,
* then free old path + swap them.
*/
- if (tse->type == TSE_RNA_PROPERTY) {
+ if (TreeElementRNAProperty *tem_rna_prop = tree_element_cast<TreeElementRNAProperty>(tem)) {
+ PropertyRNA *prop = tem_rna_prop->getPropertyRNA();
+
if (RNA_property_type(prop) == PROP_POINTER) {
/* for pointer we just append property name */
- newpath = RNA_path_append(*path, ptr, prop, 0, NULL);
+ newpath = RNA_path_append(*path, &ptr, prop, 0, nullptr);
}
else if (RNA_property_type(prop) == PROP_COLLECTION) {
char buf[128], *name;
- temnext = (TreeElement *)(ld->next->data);
- // tsenext = TREESTORE(temnext); /* UNUSED */
-
- nextptr = &temnext->rnaptr;
- name = RNA_struct_name_get_alloc(nextptr, buf, sizeof(buf), NULL);
+ TreeElement *temnext = (TreeElement *)(ld->next->data);
+ PointerRNA nextptr = tree_element_cast<TreeElementRNACommon>(temnext)->getPointerRNA();
+ name = RNA_struct_name_get_alloc(&nextptr, buf, sizeof(buf), nullptr);
if (name) {
/* if possible, use name as a key in the path */
- newpath = RNA_path_append(*path, NULL, prop, 0, name);
+ newpath = RNA_path_append(*path, nullptr, prop, 0, name);
if (name != buf) {
MEM_freeN(name);
@@ -1785,8 +1786,9 @@ static void tree_element_to_path(TreeElement *te,
if (temsub == temnext) {
break;
}
+ index++;
}
- newpath = RNA_path_append(*path, NULL, prop, index, NULL);
+ newpath = RNA_path_append(*path, nullptr, prop, index, nullptr);
}
ld = ld->next;
@@ -1798,22 +1800,22 @@ static void tree_element_to_path(TreeElement *te,
MEM_freeN(*path);
}
*path = newpath;
- newpath = NULL;
+ newpath = nullptr;
}
}
else {
/* no ID, so check if entry is RNA-struct,
* and if that RNA-struct is an ID datablock to extract info from. */
- if (tse->type == TSE_RNA_STRUCT) {
+ if (tree_element_cast<TreeElementRNAStruct>(tem)) {
/* ptr->data not ptr->owner_id seems to be the one we want,
* since ptr->data is sometimes the owner of this ID? */
- if (RNA_struct_is_ID(ptr->type)) {
- *id = ptr->data;
+ if (RNA_struct_is_ID(ptr.type)) {
+ *id = reinterpret_cast<ID *>(ptr.data);
/* clear path */
if (*path) {
MEM_freeN(*path);
- path = NULL;
+ path = nullptr;
}
}
}
@@ -1823,8 +1825,7 @@ static void tree_element_to_path(TreeElement *te,
/* step 3: if we've got an ID, add the current item to the path */
if (*id) {
/* add the active property to the path */
- ptr = &te->rnaptr;
- prop = te->directdata;
+ PropertyRNA *prop = tree_element_cast<TreeElementRNACommon>(te)->getPropertyRNA();
/* array checks */
if (tselem->type == TSE_RNA_ARRAY_ELEM) {
@@ -1837,7 +1838,7 @@ static void tree_element_to_path(TreeElement *te,
}
/* path */
- newpath = RNA_path_append(*path, NULL, prop, 0, NULL);
+ newpath = RNA_path_append(*path, nullptr, prop, 0, nullptr);
if (*path) {
MEM_freeN(*path);
}
@@ -1876,15 +1877,18 @@ static void do_outliner_drivers_editop(SpaceOutliner *space_outliner,
/* if item is selected, perform operation */
if (tselem->flag & TSE_SELECTED) {
- ID *id = NULL;
- char *path = NULL;
+ ID *id = nullptr;
+ char *path = nullptr;
int array_index = 0;
short flag = 0;
short groupmode = KSP_GROUP_KSNAME;
+ TreeElementRNACommon *te_rna = tree_element_cast<TreeElementRNACommon>(te);
+ PointerRNA ptr = te_rna ? te_rna->getPointerRNA() : PointerRNA_NULL;
+ PropertyRNA *prop = te_rna ? te_rna->getPropertyRNA() : nullptr;
+
/* check if RNA-property described by this selected element is an animatable prop */
- if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM) &&
- RNA_property_animateable(&te->rnaptr, te->directdata)) {
+ if (prop && RNA_property_animateable(&ptr, prop)) {
/* get id + path + index info from the selected element */
tree_element_to_path(te, tselem, &id, &path, &array_index, &flag, &groupmode);
}
@@ -1897,7 +1901,7 @@ static void do_outliner_drivers_editop(SpaceOutliner *space_outliner,
/* array checks */
if (flag & KSP_FLAG_WHOLE_ARRAY) {
/* entire array was selected, so add drivers for all */
- arraylen = RNA_property_array_length(&te->rnaptr, te->directdata);
+ arraylen = RNA_property_array_length(&ptr, prop);
}
else {
arraylen = array_index;
@@ -1948,7 +1952,7 @@ static int outliner_drivers_addsel_exec(bContext *C, wmOperator *op)
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
/* check for invalid states */
- if (space_outliner == NULL) {
+ if (space_outliner == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -1957,7 +1961,7 @@ static int outliner_drivers_addsel_exec(bContext *C, wmOperator *op)
space_outliner, &space_outliner->tree, op->reports, DRIVERS_EDITMODE_ADD);
/* send notifiers */
- WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); /* XXX */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, nullptr); /* XXX */
return OPERATOR_FINISHED;
}
@@ -1988,7 +1992,7 @@ static int outliner_drivers_deletesel_exec(bContext *C, wmOperator *op)
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
/* check for invalid states */
- if (space_outliner == NULL) {
+ if (space_outliner == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -1997,7 +2001,7 @@ static int outliner_drivers_deletesel_exec(bContext *C, wmOperator *op)
space_outliner, &space_outliner->tree, op->reports, DRIVERS_EDITMODE_REMOVE);
/* send notifiers */
- WM_event_add_notifier(C, ND_KEYS, NULL); /* XXX */
+ WM_event_add_notifier(C, ND_KEYS, nullptr); /* XXX */
return OPERATOR_FINISHED;
}
@@ -2038,22 +2042,23 @@ enum {
/* TODO: should this be an API func? */
static KeyingSet *verify_active_keyingset(Scene *scene, short add)
{
- KeyingSet *ks = NULL;
+ KeyingSet *ks = nullptr;
/* sanity check */
- if (scene == NULL) {
- return NULL;
+ if (scene == nullptr) {
+ return nullptr;
}
/* try to find one from scene */
if (scene->active_keyingset > 0) {
- ks = BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1);
+ ks = reinterpret_cast<KeyingSet *>(
+ BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1));
}
/* Add if none found */
/* XXX the default settings have yet to evolve. */
- if ((add) && (ks == NULL)) {
- ks = BKE_keyingset_add(&scene->keyingsets, NULL, NULL, KEYINGSET_ABSOLUTE, 0);
+ if ((add) && (ks == nullptr)) {
+ ks = BKE_keyingset_add(&scene->keyingsets, nullptr, nullptr, KEYINGSET_ABSOLUTE, 0);
scene->active_keyingset = BLI_listbase_count(&scene->keyingsets);
}
@@ -2071,15 +2076,17 @@ static void do_outliner_keyingset_editop(SpaceOutliner *space_outliner,
/* if item is selected, perform operation */
if (tselem->flag & TSE_SELECTED) {
- ID *id = NULL;
- char *path = NULL;
+ ID *id = nullptr;
+ char *path = nullptr;
int array_index = 0;
short flag = 0;
short groupmode = KSP_GROUP_KSNAME;
/* check if RNA-property described by this selected element is an animatable prop */
- if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM) &&
- RNA_property_animateable(&te->rnaptr, te->directdata)) {
+ const TreeElementRNACommon *te_rna = tree_element_cast<TreeElementRNACommon>(te);
+ PointerRNA ptr = te_rna->getPointerRNA();
+ if (te_rna && te_rna->getPropertyRNA() &&
+ RNA_property_animateable(&ptr, te_rna->getPropertyRNA())) {
/* get id + path + index info from the selected element */
tree_element_to_path(te, tselem, &id, &path, &array_index, &flag, &groupmode);
}
@@ -2092,13 +2099,13 @@ static void do_outliner_keyingset_editop(SpaceOutliner *space_outliner,
/* add a new path with the information obtained (only if valid) */
/* TODO: what do we do with group name?
* for now, we don't supply one, and just let this use the KeyingSet name */
- BKE_keyingset_add_path(ks, id, NULL, path, array_index, flag, groupmode);
+ BKE_keyingset_add_path(ks, id, nullptr, path, array_index, flag, groupmode);
ks->active_path = BLI_listbase_count(&ks->paths);
break;
}
case KEYINGSET_EDITMODE_REMOVE: {
/* find the relevant path, then remove it from the KeyingSet */
- KS_Path *ksp = BKE_keyingset_find_path(ks, id, NULL, path, array_index, groupmode);
+ KS_Path *ksp = BKE_keyingset_find_path(ks, id, nullptr, path, array_index, groupmode);
if (ksp) {
/* free path's data */
@@ -2135,11 +2142,11 @@ static int outliner_keyingset_additems_exec(bContext *C, wmOperator *op)
KeyingSet *ks = verify_active_keyingset(scene, 1);
/* check for invalid states */
- if (ks == NULL) {
+ if (ks == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Operation requires an active keying set");
return OPERATOR_CANCELLED;
}
- if (space_outliner == NULL) {
+ if (space_outliner == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -2147,7 +2154,7 @@ static int outliner_keyingset_additems_exec(bContext *C, wmOperator *op)
do_outliner_keyingset_editop(space_outliner, ks, &space_outliner->tree, KEYINGSET_EDITMODE_ADD);
/* send notifiers */
- WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, nullptr);
return OPERATOR_FINISHED;
}
@@ -2180,7 +2187,7 @@ static int outliner_keyingset_removeitems_exec(bContext *C, wmOperator *UNUSED(o
KeyingSet *ks = verify_active_keyingset(scene, 1);
/* check for invalid states */
- if (space_outliner == NULL) {
+ if (space_outliner == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -2189,7 +2196,7 @@ static int outliner_keyingset_removeitems_exec(bContext *C, wmOperator *UNUSED(o
space_outliner, ks, &space_outliner->tree, KEYINGSET_EDITMODE_REMOVE);
/* send notifiers */
- WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, nullptr);
return OPERATOR_FINISHED;
}
@@ -2218,7 +2225,7 @@ void OUTLINER_OT_keyingset_remove_selected(wmOperatorType *ot)
static bool ed_operator_outliner_id_orphans_active(bContext *C)
{
ScrArea *area = CTX_wm_area(C);
- if (area != NULL && area->spacetype == SPACE_OUTLINER) {
+ if (area != nullptr && area->spacetype == SPACE_OUTLINER) {
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
return (space_outliner->outlinevis == SO_ID_ORPHANS);
}
@@ -2303,14 +2310,14 @@ static int outliner_orphans_purge_exec(bContext *C, wmOperator *op)
* outliner several mouse events can be handled in one cycle without
* handling notifiers/redraw which leads to deleting the same object twice.
* cleanup tree here to prevent such cases. */
- if ((area != NULL) && (area->spacetype == SPACE_OUTLINER)) {
+ if ((area != nullptr) && (area->spacetype == SPACE_OUTLINER)) {
outliner_cleanup_tree(space_outliner);
}
DEG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_ID | NA_REMOVED, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_REMOVED, nullptr);
/* Force full redraw of the UI. */
- WM_main_add_notifier(NC_WINDOW, NULL);
+ WM_main_add_notifier(NC_WINDOW, nullptr);
return OPERATOR_FINISHED;
}
@@ -2332,7 +2339,7 @@ void OUTLINER_OT_orphans_purge(wmOperatorType *ot)
/* properties */
PropertyRNA *prop = RNA_def_int(ot->srna, "num_deleted", 0, 0, INT_MAX, "", "", 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_SKIP_SAVE | PROP_HIDDEN));
RNA_def_boolean(ot->srna,
"do_local_ids",
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.hh
index 3439e4fa219..9db1d73dc76 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.hh
@@ -23,8 +23,13 @@
#pragma once
+#include <memory>
+
#include "RNA_types.h"
+/* Needed for `tree_element_cast()`. */
+#include "tree/tree_element.hh"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -47,15 +52,25 @@ struct bPoseChannel;
struct wmKeyConfig;
struct wmOperatorType;
-typedef struct SpaceOutliner_Runtime {
- /** Internal C++ object to create and manage the tree for a specific display type (View Layers,
- * Scenes, Blender File, etc.). */
- struct TreeDisplay *tree_display;
+namespace blender::ed::outliner {
+class AbstractTreeDisplay;
+class AbstractTreeElement;
+} // namespace blender::ed::outliner
+
+struct SpaceOutliner_Runtime {
+ /** Object to create and manage the tree for a specific display type (View Layers, Scenes,
+ * Blender File, etc.). */
+ std::unique_ptr<blender::ed::outliner::AbstractTreeDisplay> tree_display;
/** Pointers to tree-store elements, grouped by `(id, type, nr)`
* in hash-table for faster searching. */
struct GHash *treehash;
-} SpaceOutliner_Runtime;
+
+ SpaceOutliner_Runtime() = default;
+ /** Used for copying runtime data to a duplicated space. */
+ SpaceOutliner_Runtime(const SpaceOutliner_Runtime &);
+ ~SpaceOutliner_Runtime();
+};
typedef enum TreeElementInsertType {
TE_INSERT_BEFORE,
@@ -82,7 +97,7 @@ typedef struct TreeElement {
* #TreeElement. Step by step, data should be moved to it and operations based on the type should
* become virtual methods of the class hierarchy.
*/
- struct TreeElementType *type;
+ std::unique_ptr<blender::ed::outliner::AbstractTreeElement> type;
ListBase subtree;
int xs, ys; /* Do selection. */
@@ -92,8 +107,7 @@ typedef struct TreeElement {
short idcode; /* From TreeStore id. */
short xend; /* Width of item display, for select. */
const char *name;
- void *directdata; /* Armature Bones, Base, Sequence, Strip... */
- PointerRNA rnaptr; /* RNA Pointer. */
+ void *directdata; /* Armature Bones, Base, ... */
} TreeElement;
typedef struct TreeElementIcon {
@@ -158,6 +172,8 @@ enum {
/* Child elements of the same type in the icon-row are drawn merged as one icon.
* This flag is set for an element that is part of these merged child icons. */
TE_ICONROW_MERGED = (1 << 7),
+ /* This element has some warning to be displayed. */
+ TE_HAS_WARNING = (1 << 8),
};
/* button events */
@@ -211,7 +227,7 @@ typedef enum {
* - not searching into RNA items helps but isn't the complete solution
*/
-#define SEARCHING_OUTLINER(sov) (sov->search_flags & SO_SEARCH_RECURSIVE)
+#define SEARCHING_OUTLINER(sov) ((sov)->search_flags & SO_SEARCH_RECURSIVE)
/* is the current element open? if so we also show children */
#define TSELEM_OPEN(telm, sv) \
@@ -267,6 +283,10 @@ void outliner_build_tree(struct Main *mainvar,
struct SpaceOutliner *space_outliner,
struct ARegion *region);
+struct TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner,
+ struct Collection *collection,
+ TreeElement *ten);
+
bool outliner_requires_rebuild_on_select_or_active_change(
const struct SpaceOutliner *space_outliner);
/**
@@ -296,7 +316,7 @@ void outliner_collection_isolate_flag(struct Scene *scene,
struct Collection *collection,
struct PropertyRNA *layer_or_collection_prop,
const char *propname,
- const bool value);
+ bool value);
/**
* Return the index to use based on the TreeElement ID and object type
@@ -314,7 +334,7 @@ void tree_element_type_active_set(struct bContext *C,
const TreeViewContext *tvc,
TreeElement *te,
TreeStoreElem *tselem,
- const eOLSetState set,
+ eOLSetState set,
bool recursive);
/**
* Generic call for non-id data to check the active state in UI.
@@ -329,8 +349,8 @@ eOLDrawState tree_element_type_active_state_get(const struct bContext *C,
void tree_element_activate(struct bContext *C,
const TreeViewContext *tvc,
TreeElement *te,
- const eOLSetState set,
- const bool handle_all_types);
+ eOLSetState set,
+ bool handle_all_types);
eOLDrawState tree_element_active_state_get(const TreeViewContext *tvc,
const TreeElement *te,
const TreeStoreElem *tselem);
@@ -343,7 +363,7 @@ struct bPoseChannel *outliner_find_parent_bone(TreeElement *te, TreeElement **r_
void outliner_item_select(struct bContext *C,
struct SpaceOutliner *space_outliner,
struct TreeElement *te,
- const short select_flag);
+ short select_flag);
/**
* Find if x coordinate is over an icon or name.
@@ -366,7 +386,7 @@ bool outliner_is_co_within_mode_column(SpaceOutliner *space_outliner, const floa
void outliner_item_mode_toggle(struct bContext *C,
TreeViewContext *tvc,
TreeElement *te,
- const bool do_extend);
+ bool do_extend);
/* outliner_edit.c ---------------------------------------------- */
typedef void (*outliner_operation_fn)(struct bContext *C,
@@ -396,7 +416,7 @@ void outliner_do_object_operation(struct bContext *C,
struct ListBase *lb,
outliner_operation_fn operation_fn);
-int outliner_flag_is_any_test(ListBase *lb, short flag, const int curlevel);
+int outliner_flag_is_any_test(ListBase *lb, short flag, int curlevel);
/**
* Set or unset \a flag for all outliner elements in \a lb and sub-trees.
* \return if any flag was modified.
@@ -592,7 +612,7 @@ TreeElement *outliner_find_item_at_x_in_row(const SpaceOutliner *space_outliner,
bool *r_is_merged_icon,
bool *r_is_over_icon);
/**
- * `tse` is not in the treestore, we use its contents to find a match.
+ * `tse` is not in the tree-store, we use its contents to find a match.
*/
TreeElement *outliner_find_tse(struct SpaceOutliner *space_outliner, const TreeStoreElem *tse);
/**
@@ -606,7 +626,7 @@ TreeElement *outliner_find_parent_element(ListBase *lb,
TreeElement *parent_te,
const TreeElement *child_te);
/**
- * Find treestore that refers to given ID.
+ * Find tree-store that refers to given ID.
*/
TreeElement *outliner_find_id(struct SpaceOutliner *space_outliner,
ListBase *lb,
@@ -631,7 +651,7 @@ bool outliner_tree_traverse(const SpaceOutliner *space_outliner,
void *customdata);
float outliner_restrict_columns_width(const struct SpaceOutliner *space_outliner);
/**
- * Find first tree element in tree with matching treestore flag.
+ * Find first tree element in tree with matching tree-store flag.
*/
TreeElement *outliner_find_element_with_flag(const ListBase *lb, short flag);
/**
@@ -668,3 +688,19 @@ int outliner_context(const struct bContext *C,
#ifdef __cplusplus
}
#endif
+
+namespace blender::ed::outliner {
+
+/**
+ * Helper to safely "cast" a #TreeElement to its new C++ #AbstractTreeElement, if possible.
+ * \return nullptr if the tree-element doesn't match the requested type \a TreeElementT or the
+ * element doesn't hold a C++ #AbstractTreeElement pendant yet.
+ */
+template<typename TreeElementT> TreeElementT *tree_element_cast(const TreeElement *te)
+{
+ static_assert(std::is_base_of_v<AbstractTreeElement, TreeElementT>,
+ "Requested tree-element type must be an AbstractTreeElement");
+ return dynamic_cast<TreeElementT *>(te->type.get());
+}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.cc
index 7e5b0c90714..4664a3150a1 100644
--- a/source/blender/editors/space_outliner/outliner_ops.c
+++ b/source/blender/editors/space_outliner/outliner_ops.cc
@@ -25,7 +25,7 @@
#include "ED_screen.h"
-#include "outliner_intern.h"
+#include "outliner_intern.hh"
/* ************************** registration **********************************/
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.cc
index 855975eb2dc..3ff8b9e973f 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.cc
@@ -21,7 +21,7 @@
* \ingroup spoutliner
*/
-#include <stdlib.h>
+#include <cstdlib>
#include "MEM_guardedalloc.h"
@@ -79,7 +79,10 @@
#include "RNA_access.h"
#include "RNA_define.h"
-#include "outliner_intern.h"
+#include "outliner_intern.hh"
+#include "tree/tree_element_seq.hh"
+
+using namespace blender::ed::outliner;
/**
* \note changes to selection are by convention and not essential.
@@ -96,14 +99,14 @@ static void do_outliner_item_editmode_toggle(bContext *C, Scene *scene, Base *ba
changed = ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA);
if (changed) {
ED_object_base_select(base, BA_DESELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, nullptr);
}
}
else {
changed = ED_object_editmode_enter_ex(CTX_data_main(C), scene, ob, EM_NO_CONTEXT);
if (changed) {
ED_object_base_select(base, BA_SELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, nullptr);
}
}
@@ -134,14 +137,14 @@ static void do_outliner_item_posemode_toggle(bContext *C, Scene *scene, Base *ba
changed = ED_object_posemode_exit_ex(bmain, ob);
if (changed) {
ED_object_base_select(base, BA_DESELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, nullptr);
}
}
else {
changed = ED_object_posemode_enter_ex(bmain, ob);
if (changed) {
ED_object_base_select(base, BA_SELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_POSE, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_POSE, nullptr);
}
}
@@ -165,7 +168,7 @@ static void do_outliner_item_posemode_toggle(bContext *C, Scene *scene, Base *ba
*/
static void do_outliner_item_mode_toggle_generic(bContext *C, TreeViewContext *tvc, Base *base)
{
- const int active_mode = tvc->obact->mode;
+ const eObjectMode active_mode = (eObjectMode)tvc->obact->mode;
ED_undo_group_begin(C);
if (ED_object_mode_set(C, OB_MODE_OBJECT)) {
@@ -222,13 +225,13 @@ static void tree_element_viewlayer_activate(bContext *C, TreeElement *te)
return;
}
- ViewLayer *view_layer = te->directdata;
+ ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata);
wmWindow *win = CTX_wm_window(C);
Scene *scene = WM_window_get_active_scene(win);
if (BLI_findindex(&scene->view_layers, view_layer) != -1) {
WM_window_set_active_view_layer(win, view_layer);
- WM_event_add_notifier(C, NC_SCREEN | ND_LAYER, NULL);
+ WM_event_add_notifier(C, NC_SCREEN | ND_LAYER, nullptr);
}
}
@@ -241,7 +244,7 @@ static void do_outliner_object_select_recursive(ViewLayer *view_layer,
{
Base *base;
- for (base = FIRSTBASE(view_layer); base; base = base->next) {
+ for (base = reinterpret_cast<Base *>(FIRSTBASE(view_layer)); base; base = base->next) {
Object *ob = base->object;
if ((((base->flag & BASE_VISIBLE_DEPSGRAPH) != 0) &&
BKE_object_is_child_recursive(ob_parent, ob))) {
@@ -252,8 +255,7 @@ static void do_outliner_object_select_recursive(ViewLayer *view_layer,
static void do_outliner_bone_select_recursive(bArmature *arm, Bone *bone_parent, bool select)
{
- Bone *bone;
- for (bone = bone_parent->childbase.first; bone; bone = bone->next) {
+ LISTBASE_FOREACH (Bone *, bone, &bone_parent->childbase) {
if (select && PBONE_SELECTABLE(arm, bone)) {
bone->flag |= BONE_SELECTED;
}
@@ -287,11 +289,11 @@ static void tree_element_object_activate(bContext *C,
bool recursive)
{
TreeStoreElem *tselem = TREESTORE(te);
- TreeStoreElem *parent_tselem = NULL;
- TreeElement *parent_te = NULL;
+ TreeStoreElem *parent_tselem = nullptr;
+ TreeElement *parent_te = nullptr;
Scene *sce;
Base *base;
- Object *ob = NULL;
+ Object *ob = nullptr;
/* if id is not object, we search back */
if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
@@ -309,7 +311,7 @@ static void tree_element_object_activate(bContext *C,
}
}
}
- if (ob == NULL) {
+ if (ob == nullptr) {
return;
}
@@ -323,9 +325,9 @@ static void tree_element_object_activate(bContext *C,
base = BKE_view_layer_base_find(view_layer, ob);
if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) {
- if (base != NULL) {
+ if (base != nullptr) {
Object *obact = OBACT(view_layer);
- const eObjectMode object_mode = obact ? obact->mode : OB_MODE_OBJECT;
+ const eObjectMode object_mode = obact ? (eObjectMode)obact->mode : OB_MODE_OBJECT;
if (base && !BKE_object_is_mode_compat(base->object, object_mode)) {
if (object_mode == OB_MODE_OBJECT) {
struct Main *bmain = CTX_data_main(C);
@@ -333,7 +335,7 @@ static void tree_element_object_activate(bContext *C,
ED_object_mode_generic_exit(bmain, depsgraph, scene, base->object);
}
if (!BKE_object_is_mode_compat(base->object, object_mode)) {
- base = NULL;
+ base = nullptr;
}
}
}
@@ -356,7 +358,7 @@ static void tree_element_object_activate(bContext *C,
}
}
else {
- /* deleselect all */
+ /* De-select all. */
/* Only in object mode so we can switch the active object,
* keeping all objects in the current 'mode' selected, useful for multi-pose/edit mode.
@@ -390,8 +392,8 @@ static void tree_element_material_activate(bContext *C, ViewLayer *view_layer, T
{
/* we search for the object parent */
Object *ob = (Object *)outliner_search_back(te, ID_OB);
- /* Note : ob->matbits can be NULL when a local object points to a library mesh. */
- if (ob == NULL || ob != OBACT(view_layer) || ob->matbits == NULL) {
+ /* Note : ob->matbits can be nullptr when a local object points to a library mesh. */
+ if (ob == nullptr || ob != OBACT(view_layer) || ob->matbits == nullptr) {
return; /* just paranoia */
}
@@ -411,7 +413,7 @@ static void tree_element_material_activate(bContext *C, ViewLayer *view_layer, T
* for render views to update. See T42973.
* Note that RNA material update does it too, see e.g. rna_MaterialSlot_update(). */
DEG_id_tag_update((ID *)ob, ID_RECALC_TRANSFORM);
- WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, NULL);
+ WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, nullptr);
}
static void tree_element_camera_activate(bContext *C, Scene *scene, TreeElement *te)
@@ -421,17 +423,17 @@ static void tree_element_camera_activate(bContext *C, Scene *scene, TreeElement
scene->camera = ob;
Main *bmain = CTX_data_main(C);
- wmWindowManager *wm = bmain->wm.first;
+ wmWindowManager *wm = reinterpret_cast<wmWindowManager *>(bmain->wm.first);
WM_windows_scene_data_sync(&wm->windows, scene);
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_SCENE | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_SCENE | NA_EDITED, nullptr);
}
static void tree_element_world_activate(bContext *C, Scene *scene, TreeElement *te)
{
- Scene *sce = NULL;
+ Scene *sce = nullptr;
TreeElement *tep = te->parent;
if (tep) {
@@ -461,7 +463,7 @@ static void tree_element_defgroup_activate(bContext *C, TreeElement *te, TreeSto
static void tree_element_gplayer_activate(bContext *C, TreeElement *te, TreeStoreElem *tselem)
{
bGPdata *gpd = (bGPdata *)tselem->id;
- bGPDlayer *gpl = te->directdata;
+ bGPDlayer *gpl = reinterpret_cast<bGPDlayer *>(te->directdata);
/* We can only have a single "active" layer at a time
* and there must always be an active layer... */
@@ -489,30 +491,29 @@ static void tree_element_posechannel_activate(bContext *C,
bool recursive)
{
Object *ob = (Object *)tselem->id;
- bArmature *arm = ob->data;
- bPoseChannel *pchan = te->directdata;
+ bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
+ bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata);
if (!(pchan->bone->flag & BONE_HIDDEN_P)) {
if (set != OL_SETSEL_EXTEND) {
/* Single select forces all other bones to get unselected. */
uint objects_len = 0;
- Object **objects = BKE_object_pose_array_get_unique(view_layer, NULL, &objects_len);
+ Object **objects = BKE_object_pose_array_get_unique(view_layer, nullptr, &objects_len);
for (uint object_index = 0; object_index < objects_len; object_index++) {
Object *ob_iter = BKE_object_pose_armature_get(objects[object_index]);
/* Sanity checks. */
- if (ELEM(NULL, ob_iter, ob_iter->pose, ob_iter->data)) {
+ if (ELEM(nullptr, ob_iter, ob_iter->pose, ob_iter->data)) {
continue;
}
- bPoseChannel *pchannel;
- for (pchannel = ob_iter->pose->chanbase.first; pchannel; pchannel = pchannel->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchannel, &ob_iter->pose->chanbase) {
pchannel->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
}
if (ob != ob_iter) {
- DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT);
+ DEG_id_tag_update(reinterpret_cast<ID *>(ob_iter->data), ID_RECALC_SELECT);
}
}
MEM_freeN(objects);
@@ -545,14 +546,14 @@ static void tree_element_bone_activate(bContext *C,
bool recursive)
{
bArmature *arm = (bArmature *)tselem->id;
- Bone *bone = te->directdata;
+ Bone *bone = reinterpret_cast<Bone *>(te->directdata);
if (!(bone->flag & BONE_HIDDEN_P)) {
Object *ob = OBACT(view_layer);
if (ob) {
if (set != OL_SETSEL_EXTEND) {
/* single select forces all other bones to get unselected */
- for (Bone *bone_iter = arm->bonebase.first; bone_iter != NULL;
+ for (Bone *bone_iter = reinterpret_cast<Bone *>(arm->bonebase.first); bone_iter != nullptr;
bone_iter = bone_iter->next) {
bone_iter->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
do_outliner_bone_select_recursive(arm, bone_iter, false);
@@ -594,13 +595,18 @@ static void tree_element_ebone_activate(bContext *C,
bool recursive)
{
bArmature *arm = (bArmature *)tselem->id;
- EditBone *ebone = te->directdata;
+ EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata);
if (set == OL_SETSEL_NORMAL) {
if (!(ebone->flag & BONE_HIDDEN_A)) {
uint bases_len = 0;
- Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
- view_layer, NULL, &bases_len);
+
+ ObjectsInModeParams ob_params{};
+ ob_params.object_mode = OB_MODE_EDIT;
+ ob_params.no_dup_data = true;
+
+ Base **bases = BKE_view_layer_array_from_bases_in_mode_params(
+ view_layer, nullptr, &bases_len, &ob_params);
ED_armature_edit_deselect_all_multi_ex(bases, bases_len);
MEM_freeN(bases);
@@ -673,12 +679,13 @@ static void tree_element_sequence_activate(bContext *C,
TreeElement *te,
const eOLSetState set)
{
- Sequence *seq = (Sequence *)te->directdata;
+ const TreeElementSequence *te_seq = tree_element_cast<TreeElementSequence>(te);
+ Sequence *seq = &te_seq->getSequence();
Editing *ed = SEQ_editing_get(scene);
if (BLI_findindex(ed->seqbasep, seq) != -1) {
if (set == OL_SETSEL_EXTEND) {
- SEQ_select_active_set(scene, NULL);
+ SEQ_select_active_set(scene, nullptr);
}
ED_sequencer_deselect_all(scene);
@@ -701,7 +708,7 @@ static void tree_element_sequence_dup_activate(Scene *scene, TreeElement *UNUSED
#if 0
select_single_seq(seq, 1);
#endif
- Sequence *p = ed->seqbasep->first;
+ Sequence *p = reinterpret_cast<Sequence *>(ed->seqbasep->first);
while (p) {
if ((!p->strip) || (!p->strip->stripdata) || (p->strip->stripdata->name[0] == '\0')) {
p = p->next;
@@ -720,22 +727,23 @@ static void tree_element_sequence_dup_activate(Scene *scene, TreeElement *UNUSED
static void tree_element_master_collection_activate(const bContext *C)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- LayerCollection *layer_collection = view_layer->layer_collections.first;
+ LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(
+ view_layer->layer_collections.first);
BKE_layer_collection_activate(view_layer, layer_collection);
/* A very precise notifier - ND_LAYER alone is quite vague, we want to avoid unnecessary work
* when only the active collection changes. */
- WM_main_add_notifier(NC_SCENE | ND_LAYER | NS_LAYER_COLLECTION | NA_ACTIVATED, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER | NS_LAYER_COLLECTION | NA_ACTIVATED, nullptr);
}
static void tree_element_layer_collection_activate(bContext *C, TreeElement *te)
{
Scene *scene = CTX_data_scene(C);
- LayerCollection *layer_collection = te->directdata;
+ LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(te->directdata);
ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, layer_collection);
BKE_layer_collection_activate(view_layer, layer_collection);
/* A very precise notifier - ND_LAYER alone is quite vague, we want to avoid unnecessary work
* when only the active collection changes. */
- WM_main_add_notifier(NC_SCENE | ND_LAYER | NS_LAYER_COLLECTION | NA_ACTIVATED, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER | NS_LAYER_COLLECTION | NA_ACTIVATED, nullptr);
}
static void tree_element_text_activate(bContext *C, TreeElement *te)
@@ -854,7 +862,7 @@ static eOLDrawState tree_element_bone_state_get(const ViewLayer *view_layer,
const TreeStoreElem *tselem)
{
const bArmature *arm = (const bArmature *)tselem->id;
- const Bone *bone = te->directdata;
+ const Bone *bone = reinterpret_cast<Bone *>(te->directdata);
const Object *ob = OBACT(view_layer);
if (ob && ob->data == arm) {
if (bone->flag & BONE_SELECTED) {
@@ -866,7 +874,7 @@ static eOLDrawState tree_element_bone_state_get(const ViewLayer *view_layer,
static eOLDrawState tree_element_ebone_state_get(const TreeElement *te)
{
- const EditBone *ebone = te->directdata;
+ const EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata);
if (ebone->flag & BONE_SELECTED) {
return OL_DRAWSEL_NORMAL;
}
@@ -894,7 +902,7 @@ static eOLDrawState tree_element_pose_state_get(const ViewLayer *view_layer,
const Object *ob = (const Object *)tselem->id;
/* This will just lookup in a cache, it will not change the arguments. */
const Base *base = BKE_view_layer_base_find((ViewLayer *)view_layer, (Object *)ob);
- if (base == NULL) {
+ if (base == nullptr) {
/* Armature not instantiated in current scene (e.g. inside an appended group). */
return OL_DRAWSEL_NONE;
}
@@ -910,7 +918,7 @@ static eOLDrawState tree_element_posechannel_state_get(const Object *ob_pose,
const TreeStoreElem *tselem)
{
const Object *ob = (const Object *)tselem->id;
- const bPoseChannel *pchan = te->directdata;
+ const bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata);
if (ob == ob_pose && ob->pose) {
if (pchan->bone->flag & BONE_SELECTED) {
return OL_DRAWSEL_NORMAL;
@@ -926,7 +934,7 @@ static eOLDrawState tree_element_viewlayer_state_get(const bContext *C, const Tr
return OL_DRAWSEL_NONE;
}
- const ViewLayer *view_layer = te->directdata;
+ const ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata);
if (CTX_data_view_layer(C) == view_layer) {
return OL_DRAWSEL_NORMAL;
@@ -950,7 +958,8 @@ static eOLDrawState tree_element_posegroup_state_get(const ViewLayer *view_layer
static eOLDrawState tree_element_sequence_state_get(const Scene *scene, const TreeElement *te)
{
- const Sequence *seq = (const Sequence *)te->directdata;
+ const TreeElementSequence *te_seq = tree_element_cast<TreeElementSequence>(te);
+ const Sequence *seq = &te_seq->getSequence();
const Editing *ed = scene->ed;
if (ed && ed->act_seq == seq && seq->flag & SELECT) {
@@ -961,7 +970,9 @@ static eOLDrawState tree_element_sequence_state_get(const Scene *scene, const Tr
static eOLDrawState tree_element_sequence_dup_state_get(const TreeElement *te)
{
- const Sequence *seq = (const Sequence *)te->directdata;
+ const TreeElementSequenceStripDuplicate *te_dup =
+ tree_element_cast<TreeElementSequenceStripDuplicate>(te);
+ const Sequence *seq = &te_dup->getSequence();
if (seq->flag & SELECT) {
return OL_DRAWSEL_NORMAL;
}
@@ -1002,8 +1013,8 @@ static eOLDrawState tree_element_active_material_get(const ViewLayer *view_layer
{
/* we search for the object parent */
const Object *ob = (const Object *)outliner_search_back((TreeElement *)te, ID_OB);
- /* Note : ob->matbits can be NULL when a local object points to a library mesh. */
- if (ob == NULL || ob != OBACT(view_layer) || ob->matbits == NULL) {
+ /* Note : ob->matbits can be nullptr when a local object points to a library mesh. */
+ if (ob == nullptr || ob != OBACT(view_layer) || ob->matbits == nullptr) {
return OL_DRAWSEL_NONE; /* just paranoia */
}
@@ -1042,7 +1053,7 @@ static eOLDrawState tree_element_active_scene_get(const TreeViewContext *tvc,
static eOLDrawState tree_element_active_world_get(const Scene *scene, const TreeElement *te)
{
const TreeElement *tep = te->parent;
- if (tep == NULL) {
+ if (tep == nullptr) {
return OL_DRAWSEL_NORMAL;
}
@@ -1138,7 +1149,7 @@ bPoseChannel *outliner_find_parent_bone(TreeElement *te, TreeElement **r_bone_te
te = te->parent;
}
- return NULL;
+ return nullptr;
}
static void outliner_sync_to_properties_editors(const bContext *C,
@@ -1161,7 +1172,7 @@ static void outliner_sync_to_properties_editors(const bContext *C,
static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreElem *tselem)
{
- PointerRNA ptr = {0};
+ PointerRNA ptr = {nullptr};
int context = 0;
/* ID Types */
@@ -1209,7 +1220,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
break;
case TSE_CONSTRAINT_BASE:
case TSE_CONSTRAINT: {
- TreeElement *bone_te = NULL;
+ TreeElement *bone_te = nullptr;
bPoseChannel *pchan = outliner_find_parent_bone(te, &bone_te);
if (pchan) {
@@ -1223,7 +1234,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
/* Expand the selected constraint in the properties editor. */
if (tselem->type != TSE_CONSTRAINT_BASE) {
- BKE_constraint_panel_expand(te->directdata);
+ BKE_constraint_panel_expand(reinterpret_cast<bConstraint *>(te->directdata));
}
break;
}
@@ -1236,7 +1247,8 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
Object *ob = (Object *)tselem->id;
if (ob->type == OB_GPENCIL) {
- BKE_gpencil_modifier_panel_expand(te->directdata);
+ BKE_gpencil_modifier_panel_expand(
+ reinterpret_cast<GpencilModifierData *>(te->directdata));
}
else {
ModifierData *md = (ModifierData *)te->directdata;
@@ -1269,12 +1281,12 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
context = BCONTEXT_SHADERFX;
if (tselem->type != TSE_GPENCIL_EFFECT_BASE) {
- BKE_shaderfx_panel_expand(te->directdata);
+ BKE_shaderfx_panel_expand(reinterpret_cast<ShaderFxData *>(te->directdata));
}
break;
case TSE_BONE: {
bArmature *arm = (bArmature *)tselem->id;
- Bone *bone = te->directdata;
+ Bone *bone = reinterpret_cast<Bone *>(te->directdata);
RNA_pointer_create(&arm->id, &RNA_Bone, bone, &ptr);
context = BCONTEXT_BONE;
@@ -1282,7 +1294,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
}
case TSE_EBONE: {
bArmature *arm = (bArmature *)tselem->id;
- EditBone *ebone = te->directdata;
+ EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata);
RNA_pointer_create(&arm->id, &RNA_EditBone, ebone, &ptr);
context = BCONTEXT_BONE;
@@ -1290,8 +1302,8 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
}
case TSE_POSE_CHANNEL: {
Object *ob = (Object *)tselem->id;
- bArmature *arm = ob->data;
- bPoseChannel *pchan = te->directdata;
+ bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
+ bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata);
RNA_pointer_create(&arm->id, &RNA_PoseBone, pchan, &ptr);
context = BCONTEXT_BONE;
@@ -1299,7 +1311,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
}
case TSE_POSE_BASE: {
Object *ob = (Object *)tselem->id;
- bArmature *arm = ob->data;
+ bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
RNA_pointer_create(&arm->id, &RNA_Armature, arm, &ptr);
context = BCONTEXT_DATA;
@@ -1307,7 +1319,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
}
case TSE_R_LAYER_BASE:
case TSE_R_LAYER: {
- ViewLayer *view_layer = te->directdata;
+ ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata);
RNA_pointer_create(tselem->id, &RNA_ViewLayer, view_layer, &ptr);
context = BCONTEXT_VIEW_LAYER;
@@ -1316,7 +1328,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
case TSE_POSEGRP_BASE:
case TSE_POSEGRP: {
Object *ob = (Object *)tselem->id;
- bArmature *arm = ob->data;
+ bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
RNA_pointer_create(&arm->id, &RNA_Armature, arm, &ptr);
context = BCONTEXT_DATA;
@@ -1392,7 +1404,7 @@ static void do_outliner_item_activate_tree_element(bContext *C,
Collection *gr = (Collection *)tselem->id;
if (extend) {
- int sel = BA_SELECT;
+ eObjectSelect_Mode sel = BA_SELECT;
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (gr, object) {
Base *base = BKE_view_layer_base_find(tvc->view_layer, object);
if (base && (base->flag & BASE_SELECTED)) {
@@ -1416,7 +1428,7 @@ static void do_outliner_item_activate_tree_element(bContext *C,
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (gr, object) {
Base *base = BKE_view_layer_base_find(tvc->view_layer, object);
/* Object may not be in this scene */
- if (base != NULL) {
+ if (base != nullptr) {
if ((base->flag & BASE_SELECTED) == 0) {
ED_object_base_select(base, BA_SELECT);
}
@@ -1730,7 +1742,7 @@ static int outliner_box_select_exec(bContext *C, wmOperator *op)
ARegion *region = CTX_wm_region(C);
rctf rectf;
- const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
+ const eSelectOp sel_op = (eSelectOp)RNA_enum_get(op->ptr, "mode");
const bool select = (sel_op != SEL_OP_SUB);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
outliner_flag_set(&space_outliner->tree, TSE_SELECTED, 0);
@@ -1816,7 +1828,7 @@ static TreeElement *outliner_find_rightmost_visible_child(SpaceOutliner *space_o
{
while (te->subtree.last) {
if (TSELEM_OPEN(TREESTORE(te), space_outliner)) {
- te = te->subtree.last;
+ te = reinterpret_cast<TreeElement *>(te->subtree.last);
}
else {
break;
@@ -1860,7 +1872,7 @@ static TreeElement *outliner_find_next_element(SpaceOutliner *space_outliner, Tr
TreeStoreElem *tselem = TREESTORE(te);
if (TSELEM_OPEN(tselem, space_outliner) && te->subtree.first) {
- te = te->subtree.first;
+ te = reinterpret_cast<TreeElement *>(te->subtree.first);
}
else if (te->next) {
te = te->next;
@@ -1897,7 +1909,7 @@ static TreeElement *outliner_walk_right(SpaceOutliner *space_outliner,
/* Only walk down a level if the element is open and not toggling expand */
if (!toggle_all && TSELEM_OPEN(tselem, space_outliner) && !BLI_listbase_is_empty(&te->subtree)) {
- te = te->subtree.first;
+ te = reinterpret_cast<TreeElement *>(te->subtree.first);
}
else {
outliner_item_openclose(space_outliner, te, true, toggle_all);
@@ -1948,7 +1960,7 @@ static TreeElement *find_walk_select_start_element(SpaceOutliner *space_outliner
/* If no active element exists, use the first element in the tree */
if (!active_te) {
- active_te = space_outliner->tree.first;
+ active_te = reinterpret_cast<TreeElement *>(space_outliner->tree.first);
*changed = true;
}
diff --git a/source/blender/editors/space_outliner/outliner_sync.c b/source/blender/editors/space_outliner/outliner_sync.cc
index d95a0dde858..74416024b03 100644
--- a/source/blender/editors/space_outliner/outliner_sync.c
+++ b/source/blender/editors/space_outliner/outliner_sync.cc
@@ -21,7 +21,7 @@
* \ingroup spoutliner
*/
-#include <stdio.h>
+#include <cstdio>
#include "DNA_armature_types.h"
#include "DNA_layer_types.h"
@@ -50,7 +50,7 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "outliner_intern.h"
+#include "outliner_intern.hh"
void ED_outliner_select_sync_from_object_tag(bContext *C)
{
@@ -93,7 +93,8 @@ void ED_outliner_select_sync_flag_outliners(const bContext *C)
Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
- for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (bScreen *screen = reinterpret_cast<bScreen *>(bmain->screens.first); screen;
+ screen = reinterpret_cast<bScreen *>(screen->id.next)) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_OUTLINER) {
@@ -114,12 +115,12 @@ void ED_outliner_select_sync_flag_outliners(const bContext *C)
* outliner display mode also needs to be considered. This stores the types of data
* to sync to increase code clarity.
*/
-typedef struct SyncSelectTypes {
+struct SyncSelectTypes {
bool object;
bool edit_bone;
bool pose_bone;
bool sequence;
-} SyncSelectTypes;
+};
/**
* Set which types of data to sync when syncing selection from the outliner based on object
@@ -173,11 +174,11 @@ static bool outliner_sync_select_to_outliner_set_types(const bContext *C,
* Stores items selected from a sync from the outliner. Prevents syncing the selection
* state of the last instance of an object linked in multiple collections.
*/
-typedef struct SelectedItems {
+struct SelectedItems {
GSet *objects;
GSet *edit_bones;
GSet *pose_bones;
-} SelectedItems;
+};
static void selected_items_init(SelectedItems *selected_items)
{
@@ -188,9 +189,9 @@ static void selected_items_init(SelectedItems *selected_items)
static void selected_items_free(SelectedItems *selected_items)
{
- BLI_gset_free(selected_items->objects, NULL);
- BLI_gset_free(selected_items->edit_bones, NULL);
- BLI_gset_free(selected_items->pose_bones, NULL);
+ BLI_gset_free(selected_items->objects, nullptr);
+ BLI_gset_free(selected_items->edit_bones, nullptr);
+ BLI_gset_free(selected_items->pose_bones, nullptr);
}
/* Check if an instance of this object been selected by the sync */
@@ -274,7 +275,7 @@ static void outliner_select_sync_to_pose_bone(TreeElement *te,
GSet *selected_pbones)
{
Object *ob = (Object *)tselem->id;
- bArmature *arm = ob->data;
+ bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
bPoseChannel *pchan = (bPoseChannel *)te->directdata;
short bone_flag = pchan->bone->flag;
@@ -403,7 +404,7 @@ static void outliner_select_sync_from_object(ViewLayer *view_layer,
Object *ob = (Object *)tselem->id;
Base *base = (te->directdata) ? (Base *)te->directdata :
BKE_view_layer_base_find(view_layer, ob);
- const bool is_selected = (base != NULL) && ((base->flag & BASE_SELECTED) != 0);
+ const bool is_selected = (base != nullptr) && ((base->flag & BASE_SELECTED) != 0);
if (base && (ob == obact)) {
tselem->flag |= TSE_ACTIVE;
@@ -486,12 +487,12 @@ static void outliner_select_sync_from_sequence(Sequence *sequence_active, TreeSt
* Contains active object, bones, and sequence for syncing to prevent getting active data
* repeatedly throughout syncing to the outliner.
*/
-typedef struct SyncSelectActiveData {
+struct SyncSelectActiveData {
Object *object;
EditBone *edit_bone;
bPoseChannel *pose_channel;
Sequence *sequence;
-} SyncSelectActiveData;
+};
/** Sync select and active flags from active view layer, bones, and sequences to the outliner. */
static void outliner_sync_selection_to_outliner(ViewLayer *view_layer,
@@ -561,7 +562,7 @@ void outliner_sync_selection(const bContext *C, SpaceOutliner *space_outliner)
outliner_sync_selection_to_outliner(
view_layer, space_outliner, &space_outliner->tree, &active_data, &sync_types);
- /* Keep any unsynced data in the dirty flag */
+ /* Keep any un-synced data in the dirty flag. */
if (sync_types.object) {
space_outliner->sync_select_dirty &= ~WM_OUTLINER_SYNC_SELECT_FROM_OBJECT;
}
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.cc
index 01f0feec771..fa31025b550 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.cc
@@ -95,10 +95,14 @@
#include "SEQ_relations.h"
#include "SEQ_sequencer.h"
-#include "outliner_intern.h"
+#include "outliner_intern.hh"
+#include "tree/tree_element_rna.hh"
+#include "tree/tree_element_seq.hh"
static CLG_LogRef LOG = {"ed.outliner.tools"};
+using namespace blender::ed::outliner;
+
/* -------------------------------------------------------------------- */
/** \name ID/Library/Data Set/Un-link Utilities
* \{ */
@@ -208,7 +212,7 @@ static bool outliner_operation_tree_element_poll(bContext *C)
}
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
TreeElement *te = get_target_element(space_outliner);
- if (te == NULL) {
+ if (te == nullptr) {
return false;
}
@@ -223,8 +227,8 @@ static void unlink_action_fn(bContext *C,
TreeStoreElem *UNUSED(tselem),
void *UNUSED(user_data))
{
- /* just set action to NULL */
- BKE_animdata_set_action(CTX_wm_reports(C), tsep->id, NULL);
+ /* just set action to nullptr */
+ BKE_animdata_set_action(CTX_wm_reports(C), tsep->id, nullptr);
}
static void unlink_material_fn(bContext *UNUSED(C),
@@ -235,7 +239,7 @@ static void unlink_material_fn(bContext *UNUSED(C),
TreeStoreElem *UNUSED(tselem),
void *UNUSED(user_data))
{
- Material **matar = NULL;
+ Material **matar = nullptr;
int a, totcol = 0;
if (GS(tsep->id->name) == ID_OB) {
@@ -277,11 +281,11 @@ static void unlink_material_fn(bContext *UNUSED(C),
BLI_assert(0);
}
- if (LIKELY(matar != NULL)) {
+ if (LIKELY(matar != nullptr)) {
for (a = 0; a < totcol; a++) {
if (a == te->index && matar[a]) {
id_us_min(&matar[a]->id);
- matar[a] = NULL;
+ matar[a] = nullptr;
}
}
}
@@ -295,7 +299,7 @@ static void unlink_texture_fn(bContext *UNUSED(C),
TreeStoreElem *UNUSED(tselem),
void *UNUSED(user_data))
{
- MTex **mtex = NULL;
+ MTex **mtex = nullptr;
int a;
if (GS(tsep->id->name) == ID_LS) {
@@ -310,7 +314,7 @@ static void unlink_texture_fn(bContext *UNUSED(C),
if (a == te->index && mtex[a]) {
if (mtex[a]->tex) {
id_us_min(&mtex[a]->tex->id);
- mtex[a]->tex = NULL;
+ mtex[a]->tex = nullptr;
}
}
}
@@ -330,7 +334,7 @@ static void unlink_collection_fn(bContext *C,
if (tsep) {
if (GS(tsep->id->name) == ID_OB) {
Object *ob = (Object *)tsep->id;
- ob->instance_collection = NULL;
+ ob->instance_collection = nullptr;
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
DEG_relations_tag_update(bmain);
}
@@ -369,7 +373,7 @@ static void unlink_object_fn(bContext *C,
TreeElement *te_parent = te->parent;
while (tsep && GS(tsep->id->name) == ID_OB) {
te_parent = te_parent->parent;
- tsep = te_parent ? TREESTORE(te_parent) : NULL;
+ tsep = te_parent ? TREESTORE(te_parent) : nullptr;
}
}
@@ -404,7 +408,7 @@ static void unlink_world_fn(bContext *UNUSED(C),
/* need to use parent scene not just scene, otherwise may end up getting wrong one */
id_us_min(&wo->id);
- parscene->world = NULL;
+ parscene->world = nullptr;
}
static void outliner_do_libdata_operation(bContext *C,
@@ -420,7 +424,7 @@ static void outliner_do_libdata_operation(bContext *C,
if (tselem->flag & TSE_SELECTED) {
if (((tselem->type == TSE_SOME_ID) && (te->idcode != 0)) ||
tselem->type == TSE_LAYER_COLLECTION) {
- TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL;
+ TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : nullptr;
operation_fn(C, reports, scene, te, tsep, tselem, user_data);
}
}
@@ -437,13 +441,13 @@ static void outliner_do_libdata_operation(bContext *C,
/** \name Scene Menu Operator
* \{ */
-typedef enum eOutliner_PropSceneOps {
+enum eOutliner_PropSceneOps {
OL_SCENE_OP_DELETE = 1,
-} eOutliner_PropSceneOps;
+};
static const EnumPropertyItem prop_scene_op_types[] = {
{OL_SCENE_OP_DELETE, "DELETE", ICON_X, "Delete", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
static bool outliner_do_scene_operation(
@@ -488,7 +492,7 @@ static bool scene_fn(bContext *C,
static int outliner_scene_operation_exec(bContext *C, wmOperator *op)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- const eOutliner_PropSceneOps event = RNA_enum_get(op->ptr, "type");
+ const eOutliner_PropSceneOps event = (eOutliner_PropSceneOps)RNA_enum_get(op->ptr, "type");
if (outliner_do_scene_operation(C, event, &space_outliner->tree, scene_fn) == false) {
return OPERATOR_CANCELLED;
@@ -534,10 +538,10 @@ void OUTLINER_OT_scene_operation(wmOperatorType *ot)
* the merged select popup menu. The sub-tree of the parent is searched and
* the child is needed to only show elements of the same type in the popup.
*/
-typedef struct MergedSearchData {
+struct MergedSearchData {
TreeElement *parent_element;
TreeElement *select_element;
-} MergedSearchData;
+};
static void merged_element_search_fn_recursive(
const ListBase *tree, short tselem_type, short type, const char *str, uiSearchItems *items)
@@ -615,13 +619,13 @@ static uiBlock *merged_element_search_menu(bContext *C, ARegion *region, void *d
but = uiDefSearchBut(
block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 10, menu_width, UI_UNIT_Y, 0, 0, "");
UI_but_func_search_set(but,
- NULL,
+ nullptr,
merged_element_search_update_fn,
data,
false,
- NULL,
+ nullptr,
merged_element_search_exec_fn,
- NULL);
+ nullptr);
UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
/* Fake button to hold space for search items */
@@ -633,15 +637,16 @@ static uiBlock *merged_element_search_menu(bContext *C, ARegion *region, void *d
10 - UI_searchbox_size_y(),
menu_width,
UI_searchbox_size_y(),
- NULL,
+ nullptr,
0,
0,
0,
0,
- NULL);
+ nullptr);
/* Center the menu on the cursor */
- UI_block_bounds_set_popup(block, 6, (const int[2]){-(menu_width / 2), 0});
+ const int offset[2] = {-(menu_width / 2), 0};
+ UI_block_bounds_set_popup(block, 6, offset);
return block;
}
@@ -650,7 +655,7 @@ void merged_element_search_menu_invoke(bContext *C,
TreeElement *parent_te,
TreeElement *activate_te)
{
- MergedSearchData *select_data = MEM_callocN(sizeof(MergedSearchData), "merge_search_data");
+ MergedSearchData *select_data = MEM_cnew<MergedSearchData>("merge_search_data");
select_data->parent_element = parent_te;
select_data->select_element = activate_te;
@@ -773,7 +778,7 @@ static void object_proxy_to_override_convert_fn(bContext *C,
Object *ob_proxy = (Object *)id_proxy;
Scene *scene = CTX_data_scene(C);
- if (ob_proxy->proxy == NULL) {
+ if (ob_proxy->proxy == nullptr) {
return;
}
@@ -788,17 +793,17 @@ static void object_proxy_to_override_convert_fn(bContext *C,
}
DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE);
- WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_WINDOW, nullptr);
}
-typedef struct OutlinerLibOverrideData {
+struct OutlinerLibOverrideData {
bool do_hierarchy;
/**
* For resync operation, force keeping newly created override IDs (or original linked IDs)
* instead of re-applying relevant existing ID pointer property override operations. Helps
* solving broken overrides while not losing *all* of your overrides. */
bool do_resync_hierarchy_enforce;
-} OutlinerLibOverrideData;
+};
static void id_override_library_create_fn(bContext *C,
ReportList *reports,
@@ -810,14 +815,14 @@ static void id_override_library_create_fn(bContext *C,
{
BLI_assert(TSE_IS_REAL_ID(tselem));
ID *id_root = tselem->id;
- OutlinerLibOverrideData *data = user_data;
+ OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data);
const bool do_hierarchy = data->do_hierarchy;
bool success = false;
- ID *id_reference = NULL;
+ ID *id_reference = nullptr;
bool is_override_instancing_object = false;
- if (tsep != NULL && tsep->type == TSE_SOME_ID && tsep->id != NULL &&
- GS(tsep->id->name) == ID_OB) {
+ if (tsep != nullptr && tsep->type == TSE_SOME_ID && tsep->id != nullptr &&
+ GS(tsep->id->name) == ID_OB && !ID_IS_OVERRIDE_LIBRARY(tsep->id)) {
Object *ob = (Object *)tsep->id;
if (ob->type == OB_EMPTY && &ob->instance_collection->id == id_root) {
BLI_assert(GS(id_root->name) == ID_GR);
@@ -847,7 +852,7 @@ static void id_override_library_create_fn(bContext *C,
if (do_hierarchy) {
/* Tag all linked parents in tree hierarchy to be also overridden. */
- while ((te = te->parent) != NULL) {
+ while ((te = te->parent) != nullptr) {
if (!TSE_IS_REAL_ID(te->store_elem)) {
continue;
}
@@ -869,10 +874,10 @@ static void id_override_library_create_fn(bContext *C,
}
success = BKE_lib_override_library_create(
- bmain, CTX_data_scene(C), CTX_data_view_layer(C), id_root, id_reference, NULL);
+ bmain, CTX_data_scene(C), CTX_data_view_layer(C), id_root, id_reference, nullptr);
}
else if (ID_IS_OVERRIDABLE_LIBRARY(id_root)) {
- success = BKE_lib_override_library_create_from_id(bmain, id_root, true) != NULL;
+ success = BKE_lib_override_library_create_from_id(bmain, id_root, true) != nullptr;
/* Cleanup. */
BKE_main_id_newptr_and_tag_clear(bmain);
@@ -903,7 +908,7 @@ static void id_override_library_reset_fn(bContext *C,
{
BLI_assert(TSE_IS_REAL_ID(tselem));
ID *id_root = tselem->id;
- OutlinerLibOverrideData *data = user_data;
+ OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data);
const bool do_hierarchy = data->do_hierarchy;
if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) {
@@ -916,8 +921,8 @@ static void id_override_library_reset_fn(bContext *C,
BKE_lib_override_library_id_reset(bmain, id_root);
}
- WM_event_add_notifier(C, NC_WM | ND_DATACHANGED, NULL);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ WM_event_add_notifier(C, NC_WM | ND_DATACHANGED, nullptr);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, nullptr);
}
else {
CLOG_WARN(&LOG, "Could not reset library override of data block '%s'", id_root->name);
@@ -934,7 +939,7 @@ static void id_override_library_resync_fn(bContext *C,
{
BLI_assert(TSE_IS_REAL_ID(tselem));
ID *id_root = tselem->id;
- OutlinerLibOverrideData *data = user_data;
+ OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data);
const bool do_hierarchy_enforce = data->do_resync_hierarchy_enforce;
if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) {
@@ -943,7 +948,7 @@ static void id_override_library_resync_fn(bContext *C,
id_root->tag |= LIB_TAG_DOIT;
/* Tag all linked parents in tree hierarchy to be also overridden. */
- while ((te = te->parent) != NULL) {
+ while ((te = te->parent) != nullptr) {
if (!TSE_IS_REAL_ID(te->store_elem)) {
continue;
}
@@ -953,16 +958,12 @@ static void id_override_library_resync_fn(bContext *C,
te->store_elem->id->tag |= LIB_TAG_DOIT;
}
- BKE_lib_override_library_resync(bmain,
- scene,
- CTX_data_view_layer(C),
- id_root,
- NULL,
- do_hierarchy_enforce,
- true,
- &(struct BlendFileReadReport){.reports = reports});
+ BlendFileReadReport report{};
+ report.reports = reports;
+ BKE_lib_override_library_resync(
+ bmain, scene, CTX_data_view_layer(C), id_root, nullptr, do_hierarchy_enforce, &report);
- WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_WINDOW, nullptr);
}
else {
CLOG_WARN(&LOG, "Could not resync library override of data block '%s'", id_root->name);
@@ -986,7 +987,7 @@ static void id_override_library_delete_fn(bContext *C,
id_root->tag |= LIB_TAG_DOIT;
/* Tag all linked parents in tree hierarchy to be also overridden. */
- while ((te = te->parent) != NULL) {
+ while ((te = te->parent) != nullptr) {
if (!TSE_IS_REAL_ID(te->store_elem)) {
continue;
}
@@ -998,7 +999,7 @@ static void id_override_library_delete_fn(bContext *C,
BKE_lib_override_library_delete(bmain, id_root);
- WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_WINDOW, nullptr);
}
else {
CLOG_WARN(&LOG, "Could not delete library override of data block '%s'", id_root->name);
@@ -1062,7 +1063,7 @@ static void singleuser_action_fn(bContext *C,
if (id) {
IdAdtTemplate *iat = (IdAdtTemplate *)tsep->id;
- PointerRNA ptr = {NULL};
+ PointerRNA ptr = {nullptr};
PropertyRNA *prop;
RNA_pointer_create(&iat->id, &RNA_AnimData, iat->adt, &ptr);
@@ -1085,7 +1086,7 @@ static void singleuser_world_fn(bContext *C,
/* need to use parent scene not just scene, otherwise may end up getting wrong one */
if (id) {
Scene *parscene = (Scene *)tsep->id;
- PointerRNA ptr = {NULL};
+ PointerRNA ptr = {nullptr};
PropertyRNA *prop;
RNA_id_pointer_create(&parscene->id, &ptr);
@@ -1115,10 +1116,10 @@ void outliner_do_object_operation_ex(bContext *C,
WM_window_set_active_scene(CTX_data_main(C), C, CTX_wm_window(C), scene_owner);
}
/* Important to use 'scene_owner' not scene_act else deleting objects can crash.
- * only use 'scene_act' when 'scene_owner' is NULL, which can happen when the
+ * only use 'scene_act' when 'scene_owner' is nullptr, which can happen when the
* outliner isn't showing scenes: Visible Layer draw mode for eg. */
operation_fn(
- C, reports, scene_owner ? scene_owner : scene_act, te, NULL, tselem, user_data);
+ C, reports, scene_owner ? scene_owner : scene_act, te, nullptr, tselem, user_data);
select_handled = true;
}
}
@@ -1130,7 +1131,7 @@ void outliner_do_object_operation_ex(bContext *C,
space_outliner,
&te->subtree,
operation_fn,
- NULL,
+ nullptr,
recurse_selected);
}
}
@@ -1145,7 +1146,7 @@ void outliner_do_object_operation(bContext *C,
outliner_operation_fn operation_fn)
{
outliner_do_object_operation_ex(
- C, reports, scene_act, space_outliner, lb, operation_fn, NULL, true);
+ C, reports, scene_act, space_outliner, lb, operation_fn, nullptr, true);
}
/** \} */
@@ -1168,8 +1169,8 @@ static void unlinkact_animdata_fn(int UNUSED(event),
TreeStoreElem *tselem,
void *UNUSED(arg))
{
- /* just set action to NULL */
- BKE_animdata_set_action(NULL, tselem->id, NULL);
+ /* just set action to nullptr */
+ BKE_animdata_set_action(nullptr, tselem->id, nullptr);
DEG_id_tag_update(tselem->id, ID_RECALC_ANIMATION);
}
@@ -1209,25 +1210,25 @@ static void refreshdrivers_animdata_fn(int UNUSED(event),
/** \name Object Operation Utilities
* \{ */
-typedef enum eOutliner_PropDataOps {
+enum eOutliner_PropDataOps {
OL_DOP_SELECT = 1,
OL_DOP_DESELECT,
OL_DOP_HIDE,
OL_DOP_UNHIDE,
OL_DOP_SELECT_LINKED,
-} eOutliner_PropDataOps;
+};
-typedef enum eOutliner_PropConstraintOps {
+enum eOutliner_PropConstraintOps {
OL_CONSTRAINTOP_ENABLE = 1,
OL_CONSTRAINTOP_DISABLE,
OL_CONSTRAINTOP_DELETE,
-} eOutliner_PropConstraintOps;
+};
-typedef enum eOutliner_PropModifierOps {
+enum eOutliner_PropModifierOps {
OL_MODIFIER_OP_TOGVIS = 1,
OL_MODIFIER_OP_TOGREN,
OL_MODIFIER_OP_DELETE,
-} eOutliner_PropModifierOps;
+};
static void pchan_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg))
{
@@ -1288,7 +1289,8 @@ static void ebone_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem),
static void sequence_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *scene_ptr)
{
- Sequence *seq = (Sequence *)te->directdata;
+ TreeElementSequence *te_seq = tree_element_cast<TreeElementSequence>(te);
+ Sequence *seq = &te_seq->getSequence();
Scene *scene = (Scene *)scene_ptr;
Editing *ed = SEQ_editing_get(scene);
if (BLI_findindex(ed->seqbasep, seq) != -1) {
@@ -1339,10 +1341,16 @@ static void data_select_linked_fn(int event,
TreeStoreElem *UNUSED(tselem),
void *C_v)
{
+ const TreeElementRNAStruct *te_rna_struct = tree_element_cast<TreeElementRNAStruct>(te);
+ if (!te_rna_struct) {
+ return;
+ }
+
if (event == OL_DOP_SELECT_LINKED) {
- if (RNA_struct_is_ID(te->rnaptr.type)) {
+ const PointerRNA &ptr = te_rna_struct->getPointerRNA();
+ if (RNA_struct_is_ID(ptr.type)) {
bContext *C = (bContext *)C_v;
- ID *id = te->rnaptr.data;
+ ID *id = reinterpret_cast<ID *>(ptr.data);
ED_object_select_linked_by_id(C, id);
}
@@ -1351,7 +1359,7 @@ static void data_select_linked_fn(int event,
static void constraint_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *C_v)
{
- bContext *C = C_v;
+ bContext *C = reinterpret_cast<bContext *>(C_v);
Main *bmain = CTX_data_main(C);
bConstraint *constraint = (bConstraint *)te->directdata;
Object *ob = (Object *)outliner_search_back(te, ID_OB);
@@ -1367,7 +1375,7 @@ static void constraint_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
}
else if (event == OL_CONSTRAINTOP_DELETE) {
- ListBase *lb = NULL;
+ ListBase *lb = nullptr;
if (TREESTORE(te->parent->parent)->type == TSE_POSE_CHANNEL) {
lb = &((bPoseChannel *)te->parent->parent->directdata)->constraints;
@@ -1378,7 +1386,7 @@ static void constraint_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel
if (BKE_constraint_remove_ex(lb, ob, constraint, true)) {
/* there's no active constraint now, so make sure this is the case */
- BKE_constraints_active_set(&ob->constraints, NULL);
+ BKE_constraints_active_set(&ob->constraints, nullptr);
/* needed to set the flags on posebones correctly */
ED_object_constraint_update(bmain, ob);
@@ -1408,7 +1416,7 @@ static void modifier_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
}
else if (event == OL_MODIFIER_OP_DELETE) {
- ED_object_modifier_remove(NULL, bmain, scene, ob, md);
+ ED_object_modifier_remove(nullptr, bmain, scene, ob, md);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER | NA_REMOVED, ob);
te->store_elem->flag &= ~TSE_SELECTED;
}
@@ -1442,11 +1450,12 @@ static Base *outliner_batch_delete_hierarchy(
Object *object, *parent;
if (!base) {
- return NULL;
+ return nullptr;
}
object = base->object;
- for (child_base = view_layer->object_bases.first; child_base; child_base = base_next) {
+ for (child_base = reinterpret_cast<Base *>(view_layer->object_bases.first); child_base;
+ child_base = base_next) {
base_next = child_base->next;
for (parent = child_base->object->parent; parent && (parent != object);
parent = parent->parent) {
@@ -1540,7 +1549,7 @@ static const EnumPropertyItem prop_object_op_types[] = {
0,
"Convert Proxy to Override",
"Convert a Proxy object to a full library override, including all its dependencies"},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
static int outliner_object_operation_exec(bContext *C, wmOperator *op)
@@ -1550,11 +1559,11 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
wmWindow *win = CTX_wm_window(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
int event;
- const char *str = NULL;
+ const char *str = nullptr;
bool selection_changed = false;
/* check for invalid states */
- if (space_outliner == NULL) {
+ if (space_outliner == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -1579,7 +1588,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
space_outliner,
&space_outliner->tree,
object_select_hierarchy_fn,
- NULL,
+ nullptr,
false);
if (scene != sce) {
WM_window_set_active_scene(bmain, C, win, sce);
@@ -1595,7 +1604,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
}
else if (event == OL_OP_REMAP) {
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, id_remap_fn, NULL);
+ C, op->reports, scene, space_outliner, &space_outliner->tree, id_remap_fn, nullptr);
/* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
* trick does not work here). */
}
@@ -1624,7 +1633,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
ED_outliner_select_sync_from_object_tag(C);
}
- if (str != NULL) {
+ if (str != nullptr) {
ED_undo_push(C, str);
}
@@ -1653,13 +1662,13 @@ void OUTLINER_OT_object_operation(wmOperatorType *ot)
/** \name Delete Object/Collection Operator
* \{ */
-typedef void (*OutlinerDeleteFunc)(bContext *C, ReportList *reports, Scene *scene, Object *ob);
+using OutlinerDeleteFn = void (*)(bContext *C, ReportList *reports, Scene *scene, Object *ob);
static void outliner_do_object_delete(bContext *C,
ReportList *reports,
Scene *scene,
GSet *objects_to_delete,
- OutlinerDeleteFunc delete_fn)
+ OutlinerDeleteFn delete_fn)
{
GSetIterator objects_to_delete_iter;
GSET_ITER (objects_to_delete_iter, objects_to_delete) {
@@ -1678,7 +1687,8 @@ static TreeTraversalAction outliner_find_objects_to_delete(TreeElement *te, void
return TRAVERSE_CONTINUE;
}
- if ((tselem->type != TSE_SOME_ID) || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) {
+ if ((tselem->type != TSE_SOME_ID) || (tselem->id == nullptr) ||
+ (GS(tselem->id->name) != ID_OB)) {
return TRAVERSE_SKIP_CHILDS;
}
@@ -1687,6 +1697,8 @@ static TreeTraversalAction outliner_find_objects_to_delete(TreeElement *te, void
return TRAVERSE_CONTINUE;
}
+/* FIXME: See comment above #WM_msg_publish_rna_prop(). */
+extern "C" {
static int outliner_delete_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -1720,7 +1732,7 @@ static int outliner_delete_exec(bContext *C, wmOperator *op)
outliner_do_object_delete(C, op->reports, scene, objects_to_delete, outliner_object_delete_fn);
}
- BLI_gset_free(objects_to_delete, NULL);
+ BLI_gset_free(objects_to_delete, nullptr);
outliner_collection_delete(C, bmain, scene, op->reports, delete_hierarchy);
@@ -1746,6 +1758,7 @@ static int outliner_delete_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+}
void OUTLINER_OT_delete(wmOperatorType *ot)
{
@@ -1773,7 +1786,7 @@ void OUTLINER_OT_delete(wmOperatorType *ot)
/** \name ID-Data Menu Operator
* \{ */
-typedef enum eOutlinerIdOpTypes {
+enum eOutlinerIdOpTypes {
OUTLINER_IDOP_INVALID = 0,
OUTLINER_IDOP_UNLINK,
@@ -1798,7 +1811,7 @@ typedef enum eOutlinerIdOpTypes {
OUTLINER_IDOP_RENAME,
OUTLINER_IDOP_SELECT_LINKED,
-} eOutlinerIdOpTypes;
+};
/* TODO: implement support for changing the ID-block used. */
static const EnumPropertyItem prop_id_op_types[] = {
@@ -1811,7 +1824,7 @@ static const EnumPropertyItem prop_id_op_types[] = {
0,
"Remap Users",
"Make all users of selected data-blocks to use instead current (clicked) one"},
- {0, "", 0, NULL, NULL},
+ {0, "", 0, nullptr, nullptr},
{OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE,
"OVERRIDE_LIBRARY_CREATE",
0,
@@ -1856,10 +1869,10 @@ static const EnumPropertyItem prop_id_op_types[] = {
"Delete Library Override Hierarchy",
"Delete this local override (including its hierarchy of override dependencies) and relink "
"its usages to the linked data-blocks"},
- {0, "", 0, NULL, NULL},
+ {0, "", 0, nullptr, nullptr},
{OUTLINER_IDOP_COPY, "COPY", ICON_COPYDOWN, "Copy", ""},
{OUTLINER_IDOP_PASTE, "PASTE", ICON_PASTEDOWN, "Paste", ""},
- {0, "", 0, NULL, NULL},
+ {0, "", 0, nullptr, nullptr},
{OUTLINER_IDOP_FAKE_ADD,
"ADD_FAKE",
0,
@@ -1869,7 +1882,7 @@ static const EnumPropertyItem prop_id_op_types[] = {
{OUTLINER_IDOP_FAKE_CLEAR, "CLEAR_FAKE", 0, "Clear Fake User", ""},
{OUTLINER_IDOP_RENAME, "RENAME", 0, "Rename", ""},
{OUTLINER_IDOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
static bool outliner_id_operation_item_poll(bContext *C,
@@ -1903,7 +1916,7 @@ static bool outliner_id_operation_item_poll(bContext *C,
if (GS(tselem->id->name) == ID_OB) {
Object *ob = (Object *)tselem->id;
- if ((ob != NULL) && (ob->proxy != NULL)) {
+ if ((ob != nullptr) && (ob->proxy != nullptr)) {
return true;
}
}
@@ -1935,13 +1948,13 @@ static const EnumPropertyItem *outliner_id_operation_itemf(bContext *C,
PropertyRNA *prop,
bool *r_free)
{
- EnumPropertyItem *items = NULL;
+ EnumPropertyItem *items = nullptr;
int totitem = 0;
- if ((C == NULL) || (ED_operator_outliner_active(C) == false)) {
+ if ((C == nullptr) || (ED_operator_outliner_active(C) == false)) {
return prop_id_op_types;
}
- for (const EnumPropertyItem *it = prop_id_op_types; it->identifier != NULL; it++) {
+ for (const EnumPropertyItem *it = prop_id_op_types; it->identifier != nullptr; it++) {
if (!outliner_id_operation_item_poll(C, ptr, prop, it->value)) {
continue;
}
@@ -1961,22 +1974,27 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
/* check for invalid states */
- if (space_outliner == NULL) {
+ if (space_outliner == nullptr) {
return OPERATOR_CANCELLED;
}
TreeElement *te = get_target_element(space_outliner);
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
- eOutlinerIdOpTypes event = RNA_enum_get(op->ptr, "type");
+ eOutlinerIdOpTypes event = (eOutlinerIdOpTypes)RNA_enum_get(op->ptr, "type");
switch (event) {
case OUTLINER_IDOP_UNLINK: {
/* unlink datablock from its parent */
if (objectlevel) {
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, unlink_object_fn, NULL);
-
- WM_event_add_notifier(C, NC_SCENE | ND_LAYER, NULL);
+ outliner_do_libdata_operation(C,
+ op->reports,
+ scene,
+ space_outliner,
+ &space_outliner->tree,
+ unlink_object_fn,
+ nullptr);
+
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER, nullptr);
ED_undo_push(C, "Unlink Object");
break;
}
@@ -1989,9 +2007,9 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
space_outliner,
&space_outliner->tree,
unlink_action_fn,
- NULL);
+ nullptr);
- WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr);
ED_undo_push(C, "Unlink action");
break;
case ID_MA:
@@ -2001,9 +2019,9 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
space_outliner,
&space_outliner->tree,
unlink_material_fn,
- NULL);
+ nullptr);
- WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, nullptr);
ED_undo_push(C, "Unlink material");
break;
case ID_TE:
@@ -2013,16 +2031,21 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
space_outliner,
&space_outliner->tree,
unlink_texture_fn,
- NULL);
+ nullptr);
- WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, nullptr);
ED_undo_push(C, "Unlink texture");
break;
case ID_WO:
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, unlink_world_fn, NULL);
+ outliner_do_libdata_operation(C,
+ op->reports,
+ scene,
+ space_outliner,
+ &space_outliner->tree,
+ unlink_world_fn,
+ nullptr);
- WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_WORLD, nullptr);
ED_undo_push(C, "Unlink world");
break;
case ID_GR:
@@ -2032,9 +2055,9 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
space_outliner,
&space_outliner->tree,
unlink_collection_fn,
- NULL);
+ nullptr);
- WM_event_add_notifier(C, NC_SCENE | ND_LAYER, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER, nullptr);
ED_undo_push(C, "Unlink Collection");
break;
default:
@@ -2046,29 +2069,32 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_LOCAL: {
/* make local */
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, id_local_fn, NULL);
+ C, op->reports, scene, space_outliner, &space_outliner->tree, id_local_fn, nullptr);
ED_undo_push(C, "Localized Data");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE: {
+ OutlinerLibOverrideData override_data{};
outliner_do_libdata_operation(C,
op->reports,
scene,
space_outliner,
&space_outliner->tree,
id_override_library_create_fn,
- &(OutlinerLibOverrideData){.do_hierarchy = false});
+ &override_data);
ED_undo_push(C, "Overridden Data");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY: {
+ OutlinerLibOverrideData override_data{};
+ override_data.do_hierarchy = true;
outliner_do_libdata_operation(C,
op->reports,
scene,
space_outliner,
&space_outliner->tree,
id_override_library_create_fn,
- &(OutlinerLibOverrideData){.do_hierarchy = true});
+ &override_data);
ED_undo_push(C, "Overridden Data Hierarchy");
break;
}
@@ -2083,58 +2109,67 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET: {
+ OutlinerLibOverrideData override_data{};
outliner_do_libdata_operation(C,
op->reports,
scene,
space_outliner,
&space_outliner->tree,
id_override_library_reset_fn,
- &(OutlinerLibOverrideData){.do_hierarchy = false});
+ &override_data);
ED_undo_push(C, "Reset Overridden Data");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY: {
+ OutlinerLibOverrideData override_data{};
+ override_data.do_hierarchy = true;
outliner_do_libdata_operation(C,
op->reports,
scene,
space_outliner,
&space_outliner->tree,
id_override_library_reset_fn,
- &(OutlinerLibOverrideData){.do_hierarchy = true});
+ &override_data);
ED_undo_push(C, "Reset Overridden Data Hierarchy");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY: {
+ OutlinerLibOverrideData override_data{};
+ override_data.do_hierarchy = true;
outliner_do_libdata_operation(C,
op->reports,
scene,
space_outliner,
&space_outliner->tree,
id_override_library_resync_fn,
- &(OutlinerLibOverrideData){.do_hierarchy = true});
+ &override_data);
ED_undo_push(C, "Resync Overridden Data Hierarchy");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE: {
- outliner_do_libdata_operation(
- C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- id_override_library_resync_fn,
- &(OutlinerLibOverrideData){.do_hierarchy = true, .do_resync_hierarchy_enforce = true});
+ OutlinerLibOverrideData override_data{};
+ override_data.do_hierarchy = true;
+ override_data.do_resync_hierarchy_enforce = true;
+ outliner_do_libdata_operation(C,
+ op->reports,
+ scene,
+ space_outliner,
+ &space_outliner->tree,
+ id_override_library_resync_fn,
+ &override_data);
ED_undo_push(C, "Resync Overridden Data Hierarchy");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY: {
+ OutlinerLibOverrideData override_data{};
+ override_data.do_hierarchy = true;
outliner_do_libdata_operation(C,
op->reports,
scene,
space_outliner,
&space_outliner->tree,
id_override_library_delete_fn,
- &(OutlinerLibOverrideData){.do_hierarchy = true});
+ &override_data);
ED_undo_push(C, "Delete Overridden Data Hierarchy");
break;
}
@@ -2148,9 +2183,9 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
space_outliner,
&space_outliner->tree,
singleuser_action_fn,
- NULL);
+ nullptr);
- WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr);
ED_undo_push(C, "Single-User Action");
break;
@@ -2161,9 +2196,9 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
space_outliner,
&space_outliner->tree,
singleuser_world_fn,
- NULL);
+ nullptr);
- WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_WORLD, nullptr);
ED_undo_push(C, "Single-User World");
break;
@@ -2176,7 +2211,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_DELETE: {
if (idlevel > 0) {
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, id_delete_fn, NULL);
+ C, op->reports, scene, space_outliner, &space_outliner->tree, id_delete_fn, nullptr);
ED_undo_push(C, "Delete");
}
break;
@@ -2184,7 +2219,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_REMAP: {
if (idlevel > 0) {
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, id_remap_fn, NULL);
+ C, op->reports, scene, space_outliner, &space_outliner->tree, id_remap_fn, nullptr);
/* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
* trick does not work here). */
}
@@ -2192,14 +2227,14 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
}
case OUTLINER_IDOP_COPY: {
wm->op_undo_depth++;
- WM_operator_name_call(C, "OUTLINER_OT_id_copy", WM_OP_INVOKE_DEFAULT, NULL);
+ WM_operator_name_call(C, "OUTLINER_OT_id_copy", WM_OP_INVOKE_DEFAULT, nullptr);
wm->op_undo_depth--;
/* No need for undo, this operation does not change anything... */
break;
}
case OUTLINER_IDOP_PASTE: {
wm->op_undo_depth++;
- WM_operator_name_call(C, "OUTLINER_OT_id_paste", WM_OP_INVOKE_DEFAULT, NULL);
+ WM_operator_name_call(C, "OUTLINER_OT_id_paste", WM_OP_INVOKE_DEFAULT, nullptr);
wm->op_undo_depth--;
ED_outliner_select_sync_from_all_tag(C);
ED_undo_push(C, "Paste");
@@ -2207,10 +2242,15 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
}
case OUTLINER_IDOP_FAKE_ADD: {
/* set fake user */
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, id_fake_user_set_fn, NULL);
+ outliner_do_libdata_operation(C,
+ op->reports,
+ scene,
+ space_outliner,
+ &space_outliner->tree,
+ id_fake_user_set_fn,
+ nullptr);
- WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
ED_undo_push(C, "Add Fake User");
break;
}
@@ -2222,24 +2262,29 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
space_outliner,
&space_outliner->tree,
id_fake_user_clear_fn,
- NULL);
+ nullptr);
- WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
ED_undo_push(C, "Clear Fake User");
break;
}
case OUTLINER_IDOP_RENAME: {
/* rename */
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn, NULL);
+ C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn, nullptr);
- WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
ED_undo_push(C, "Rename");
break;
}
case OUTLINER_IDOP_SELECT_LINKED:
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, id_select_linked_fn, NULL);
+ outliner_do_libdata_operation(C,
+ op->reports,
+ scene,
+ space_outliner,
+ &space_outliner->tree,
+ id_select_linked_fn,
+ nullptr);
ED_outliner_select_sync_from_all_tag(C);
ED_undo_push(C, "Select");
break;
@@ -2250,10 +2295,10 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
}
/* wrong notifier still... */
- WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
/* XXX: this is just so that outliner is always up to date. */
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, nullptr);
return OPERATOR_FINISHED;
}
@@ -2281,14 +2326,14 @@ void OUTLINER_OT_id_operation(wmOperatorType *ot)
/** \name Library Menu Operator
* \{ */
-typedef enum eOutlinerLibOpTypes {
+enum eOutlinerLibOpTypes {
OL_LIB_INVALID = 0,
OL_LIB_RENAME,
OL_LIB_DELETE,
OL_LIB_RELOCATE,
OL_LIB_RELOAD,
-} eOutlinerLibOpTypes;
+};
static const EnumPropertyItem outliner_lib_op_type_items[] = {
{OL_LIB_RENAME, "RENAME", 0, "Rename", ""},
@@ -2304,7 +2349,7 @@ static const EnumPropertyItem outliner_lib_op_type_items[] = {
"Relocate",
"Select a new path for this library, and reload all its data"},
{OL_LIB_RELOAD, "RELOAD", ICON_FILE_REFRESH, "Reload", "Reload all data from this library"},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
@@ -2314,39 +2359,39 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
/* check for invalid states */
- if (space_outliner == NULL) {
+ if (space_outliner == nullptr) {
return OPERATOR_CANCELLED;
}
TreeElement *te = get_target_element(space_outliner);
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
- eOutlinerLibOpTypes event = RNA_enum_get(op->ptr, "type");
+ eOutlinerLibOpTypes event = (eOutlinerLibOpTypes)RNA_enum_get(op->ptr, "type");
switch (event) {
case OL_LIB_RENAME: {
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn, NULL);
+ C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn, nullptr);
- WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
ED_undo_push(C, "Rename Library");
break;
}
case OL_LIB_DELETE: {
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, id_delete_fn, NULL);
+ C, op->reports, scene, space_outliner, &space_outliner->tree, id_delete_fn, nullptr);
ED_undo_push(C, "Delete Library");
break;
}
case OL_LIB_RELOCATE: {
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, lib_relocate_fn, NULL);
+ C, op->reports, scene, space_outliner, &space_outliner->tree, lib_relocate_fn, nullptr);
/* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
* trick does not work here). */
break;
}
case OL_LIB_RELOAD: {
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, lib_reload_fn, NULL);
+ C, op->reports, scene, space_outliner, &space_outliner->tree, lib_reload_fn, nullptr);
/* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
* trick does not work here). */
break;
@@ -2357,10 +2402,10 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
}
/* wrong notifier still... */
- WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
/* XXX: this is just so that outliner is always up to date */
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, nullptr);
return OPERATOR_FINISHED;
}
@@ -2397,7 +2442,7 @@ static void outliner_do_id_set_operation(
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->flag & TSE_SELECTED) {
if (tselem->type == type) {
- TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL;
+ TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : nullptr;
operation_fn(te, tselem, tsep, newid);
}
}
@@ -2416,14 +2461,14 @@ static void actionset_id_fn(TreeElement *UNUSED(te),
if (tselem->type == TSE_ANIM_DATA) {
/* "animation" entries - action is child of this */
- BKE_animdata_set_action(NULL, tselem->id, act);
+ BKE_animdata_set_action(nullptr, tselem->id, act);
}
/* TODO: if any other "expander" channels which own actions need to support this menu,
* add: tselem->type = ...
*/
else if (tsep && (tsep->type == TSE_ANIM_DATA)) {
/* "animation" entries case again */
- BKE_animdata_set_action(NULL, tsep->id, act);
+ BKE_animdata_set_action(nullptr, tsep->id, act);
}
/* TODO: other cases not supported yet. */
}
@@ -2439,9 +2484,10 @@ static int outliner_action_set_exec(bContext *C, wmOperator *op)
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
/* get action to use */
- act = BLI_findlink(&bmain->actions, RNA_enum_get(op->ptr, "action"));
+ act = reinterpret_cast<bAction *>(
+ BLI_findlink(&bmain->actions, RNA_enum_get(op->ptr, "action")));
- if (act == NULL) {
+ if (act == nullptr) {
BKE_report(op->reports, RPT_ERROR, "No valid action to add");
return OPERATOR_CANCELLED;
}
@@ -2470,7 +2516,7 @@ static int outliner_action_set_exec(bContext *C, wmOperator *op)
}
/* set notifier that things have changed */
- WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr);
ED_undo_push(C, "Set action");
/* done */
@@ -2508,7 +2554,7 @@ void OUTLINER_OT_action_set(wmOperatorType *ot)
/** \name Animation Menu Operator
* \{ */
-typedef enum eOutliner_AnimDataOps {
+enum eOutliner_AnimDataOps {
OUTLINER_ANIMOP_INVALID = 0,
OUTLINER_ANIMOP_CLEAR_ADT,
@@ -2518,7 +2564,7 @@ typedef enum eOutliner_AnimDataOps {
OUTLINER_ANIMOP_REFRESH_DRV,
OUTLINER_ANIMOP_CLEAR_DRV
-} eOutliner_AnimDataOps;
+};
static const EnumPropertyItem prop_animdata_op_types[] = {
{OUTLINER_ANIMOP_CLEAR_ADT,
@@ -2530,7 +2576,7 @@ static const EnumPropertyItem prop_animdata_op_types[] = {
{OUTLINER_ANIMOP_CLEAR_ACT, "CLEAR_ACT", 0, "Unlink Action", ""},
{OUTLINER_ANIMOP_REFRESH_DRV, "REFRESH_DRIVERS", 0, "Refresh Drivers", ""},
{OUTLINER_ANIMOP_CLEAR_DRV, "CLEAR_DRIVERS", 0, "Clear Drivers", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
@@ -2546,21 +2592,21 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
}
/* perform the core operation */
- eOutliner_AnimDataOps event = RNA_enum_get(op->ptr, "type");
+ eOutliner_AnimDataOps event = (eOutliner_AnimDataOps)RNA_enum_get(op->ptr, "type");
switch (event) {
case OUTLINER_ANIMOP_CLEAR_ADT:
/* Remove Animation Data - this may remove the active action, in some cases... */
outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, clear_animdata_fn, NULL);
+ space_outliner, datalevel, event, &space_outliner->tree, clear_animdata_fn, nullptr);
- WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr);
ED_undo_push(C, "Clear Animation Data");
break;
case OUTLINER_ANIMOP_SET_ACT:
/* delegate once again... */
wm->op_undo_depth++;
- WM_operator_name_call(C, "OUTLINER_OT_action_set", WM_OP_INVOKE_REGION_WIN, NULL);
+ WM_operator_name_call(C, "OUTLINER_OT_action_set", WM_OP_INVOKE_REGION_WIN, nullptr);
wm->op_undo_depth--;
ED_undo_push(C, "Set active action");
break;
@@ -2568,9 +2614,9 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_ANIMOP_CLEAR_ACT:
/* clear active action - using standard rules */
outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, unlinkact_animdata_fn, NULL);
+ space_outliner, datalevel, event, &space_outliner->tree, unlinkact_animdata_fn, nullptr);
- WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr);
ED_undo_push(C, "Unlink action");
break;
@@ -2580,17 +2626,21 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
event,
&space_outliner->tree,
refreshdrivers_animdata_fn,
- NULL);
+ nullptr);
- WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, nullptr);
/* ED_undo_push(C, "Refresh Drivers"); No undo needed - shouldn't have any impact? */
break;
case OUTLINER_ANIMOP_CLEAR_DRV:
- outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, cleardrivers_animdata_fn, NULL);
+ outliner_do_data_operation(space_outliner,
+ datalevel,
+ event,
+ &space_outliner->tree,
+ cleardrivers_animdata_fn,
+ nullptr);
- WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, nullptr);
ED_undo_push(C, "Clear Drivers");
break;
@@ -2630,13 +2680,13 @@ static const EnumPropertyItem prop_constraint_op_types[] = {
{OL_CONSTRAINTOP_ENABLE, "ENABLE", ICON_HIDE_OFF, "Enable", ""},
{OL_CONSTRAINTOP_DISABLE, "DISABLE", ICON_HIDE_ON, "Disable", ""},
{OL_CONSTRAINTOP_DELETE, "DELETE", ICON_X, "Delete", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
static int outliner_constraint_operation_exec(bContext *C, wmOperator *op)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- eOutliner_PropConstraintOps event = RNA_enum_get(op->ptr, "type");
+ eOutliner_PropConstraintOps event = (eOutliner_PropConstraintOps)RNA_enum_get(op->ptr, "type");
outliner_do_data_operation(
space_outliner, TSE_CONSTRAINT, event, &space_outliner->tree, constraint_fn, C);
@@ -2677,13 +2727,13 @@ static const EnumPropertyItem prop_modifier_op_types[] = {
{OL_MODIFIER_OP_TOGVIS, "TOGVIS", ICON_RESTRICT_VIEW_OFF, "Toggle Viewport Use", ""},
{OL_MODIFIER_OP_TOGREN, "TOGREN", ICON_RESTRICT_RENDER_OFF, "Toggle Render Use", ""},
{OL_MODIFIER_OP_DELETE, "DELETE", ICON_X, "Delete", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
static int outliner_modifier_operation_exec(bContext *C, wmOperator *op)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- eOutliner_PropModifierOps event = RNA_enum_get(op->ptr, "type");
+ eOutliner_PropModifierOps event = (eOutliner_PropModifierOps)RNA_enum_get(op->ptr, "type");
outliner_do_data_operation(
space_outliner, TSE_MODIFIER, event, &space_outliner->tree, modifier_fn, C);
@@ -2726,28 +2776,28 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op)
TreeElement *te = get_target_element(space_outliner);
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
- eOutliner_PropDataOps event = RNA_enum_get(op->ptr, "type");
+ eOutliner_PropDataOps event = (eOutliner_PropDataOps)RNA_enum_get(op->ptr, "type");
switch (datalevel) {
case TSE_POSE_CHANNEL: {
outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, pchan_fn, NULL);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ space_outliner, datalevel, event, &space_outliner->tree, pchan_fn, nullptr);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
ED_undo_push(C, "PoseChannel operation");
break;
}
case TSE_BONE: {
outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, bone_fn, NULL);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ space_outliner, datalevel, event, &space_outliner->tree, bone_fn, nullptr);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
ED_undo_push(C, "Bone operation");
break;
}
case TSE_EBONE: {
outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, ebone_fn, NULL);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ space_outliner, datalevel, event, &space_outliner->tree, ebone_fn, nullptr);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
ED_undo_push(C, "EditBone operation");
break;
@@ -2763,8 +2813,8 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op)
}
case TSE_GP_LAYER: {
outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, gpencil_layer_fn, NULL);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
+ space_outliner, datalevel, event, &space_outliner->tree, gpencil_layer_fn, nullptr);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, nullptr);
ED_undo_push(C, "Grease Pencil Layer operation");
break;
@@ -2792,17 +2842,17 @@ static const EnumPropertyItem *outliner_data_op_sets_enum_item_fn(bContext *C,
bool *UNUSED(r_free))
{
/* Check for invalid states. */
- if (C == NULL) {
+ if (C == nullptr) {
return DummyRNA_DEFAULT_items;
}
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- if (space_outliner == NULL) {
+ if (space_outliner == nullptr) {
return DummyRNA_DEFAULT_items;
}
TreeElement *te = get_target_element(space_outliner);
- if (te == NULL) {
+ if (te == nullptr) {
return DummyRNA_NULL_items;
}
@@ -2813,10 +2863,11 @@ static const EnumPropertyItem *outliner_data_op_sets_enum_item_fn(bContext *C,
{OL_DOP_DESELECT, "DESELECT", 0, "Deselect", ""},
{OL_DOP_HIDE, "HIDE", 0, "Hide", ""},
{OL_DOP_UNHIDE, "UNHIDE", 0, "Unhide", ""},
- {0, NULL, 0, NULL, NULL}};
+ {0, nullptr, 0, nullptr, nullptr}};
static const EnumPropertyItem optype_sel_linked[] = {
- {OL_DOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""}, {0, NULL, 0, NULL, NULL}};
+ {OL_DOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""},
+ {0, nullptr, 0, nullptr, nullptr}};
if (tselem->type == TSE_RNA_STRUCT) {
return optype_sel_linked;
@@ -2851,7 +2902,7 @@ void OUTLINER_OT_data_operation(wmOperatorType *ot)
static int outliner_operator_menu(bContext *C, const char *opname)
{
wmOperatorType *ot = WM_operatortype_find(opname, false);
- uiPopupMenu *pup = UI_popup_menu_begin(C, WM_operatortype_name(ot, NULL), ICON_NONE);
+ uiPopupMenu *pup = UI_popup_menu_begin(C, WM_operatortype_name(ot, nullptr), ICON_NONE);
uiLayout *layout = UI_popup_menu_layout(pup);
/* set this so the default execution context is the same as submenus */
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.cc
index 3353726de18..eb885eba20d 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.cc
@@ -21,8 +21,8 @@
* \ingroup spoutliner
*/
-#include <math.h>
-#include <string.h>
+#include <cmath>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -74,15 +74,19 @@
#include "RNA_access.h"
#include "UI_interface.h"
+#include "UI_resources.h"
-#include "outliner_intern.h"
-#include "tree/tree_display.h"
-#include "tree/tree_element.h"
+#include "outliner_intern.hh"
+#include "tree/common.hh"
+#include "tree/tree_display.hh"
+#include "tree/tree_element.hh"
#ifdef WIN32
# include "BLI_math_base.h" /* M_PI */
#endif
+using namespace blender::ed::outliner;
+
/* prototypes */
static int outliner_exclude_filter_get(const SpaceOutliner *space_outliner);
@@ -101,7 +105,7 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner)
BLI_mempool_iter iter;
BLI_mempool_iternew(ts, &iter);
- while ((tselem = BLI_mempool_iterstep(&iter))) {
+ while ((tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) {
tselem->used = 0;
}
@@ -111,8 +115,8 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner)
space_outliner->storeflag &= ~SO_TREESTORE_CLEANUP;
BLI_mempool_iternew(ts, &iter);
- while ((tselem = BLI_mempool_iterstep(&iter))) {
- if (tselem->id == NULL) {
+ while ((tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) {
+ if (tselem->id == nullptr) {
unused++;
}
}
@@ -120,10 +124,10 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner)
if (unused) {
if (BLI_mempool_len(ts) == unused) {
BLI_mempool_destroy(ts);
- space_outliner->treestore = NULL;
+ space_outliner->treestore = nullptr;
if (space_outliner->runtime->treehash) {
BKE_outliner_treehash_free(space_outliner->runtime->treehash);
- space_outliner->runtime->treehash = NULL;
+ space_outliner->runtime->treehash = nullptr;
}
}
else {
@@ -131,9 +135,9 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner)
BLI_mempool *new_ts = BLI_mempool_create(
sizeof(TreeStoreElem), BLI_mempool_len(ts) - unused, 512, BLI_MEMPOOL_ALLOW_ITER);
BLI_mempool_iternew(ts, &iter);
- while ((tselem = BLI_mempool_iterstep(&iter))) {
+ while ((tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) {
if (tselem->id) {
- tsenew = BLI_mempool_alloc(new_ts);
+ tsenew = reinterpret_cast<TreeStoreElem *>(BLI_mempool_alloc(new_ts));
*tsenew = *tselem;
}
}
@@ -156,14 +160,14 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner)
static void check_persistent(
SpaceOutliner *space_outliner, TreeElement *te, ID *id, short type, short nr)
{
- if (space_outliner->treestore == NULL) {
+ if (space_outliner->treestore == nullptr) {
/* if treestore was not created in readfile.c, create it here */
space_outliner->treestore = BLI_mempool_create(
sizeof(TreeStoreElem), 1, 512, BLI_MEMPOOL_ALLOW_ITER);
}
- if (space_outliner->runtime->treehash == NULL) {
- space_outliner->runtime->treehash = BKE_outliner_treehash_create_from_treestore(
- space_outliner->treestore);
+ if (space_outliner->runtime->treehash == nullptr) {
+ space_outliner->runtime->treehash = reinterpret_cast<GHash *>(
+ BKE_outliner_treehash_create_from_treestore(space_outliner->treestore));
}
/* find any unused tree element in treestore and mark it as used
@@ -177,7 +181,7 @@ static void check_persistent(
}
/* add 1 element to treestore */
- tselem = BLI_mempool_alloc(space_outliner->treestore);
+ tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_alloc(space_outliner->treestore));
tselem->type = type;
tselem->nr = type ? nr : 0;
tselem->id = id;
@@ -213,8 +217,8 @@ void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree)
if (element->flag & TE_FREE_NAME) {
MEM_freeN((void *)element->name);
}
- outliner_tree_element_type_free(&element->type);
- MEM_freeN(element);
+ element->type = nullptr;
+ MEM_delete(element);
}
/* ********************************************************* */
@@ -253,14 +257,6 @@ static void outliner_add_bone(SpaceOutliner *space_outliner,
}
}
-bool outliner_animdata_test(const AnimData *adt)
-{
- if (adt) {
- return (adt->action || adt->drivers.first || adt->nla_tracks.first);
- }
- return false;
-}
-
#ifdef WITH_FREESTYLE
static void outliner_add_line_styles(SpaceOutliner *space_outliner,
ListBase *lb,
@@ -313,13 +309,13 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
outliner_add_element(space_outliner, &te->subtree, ob->data, te, TSE_SOME_ID, 0);
if (ob->pose) {
- bArmature *arm = ob->data;
+ bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
TreeElement *tenla = outliner_add_element(
space_outliner, &te->subtree, ob, te, TSE_POSE_BASE, 0);
tenla->name = IFACE_("Pose");
/* channels undefined in editmode, but we want the 'tenla' pose icon itself */
- if ((arm->edbo == NULL) && (ob->mode & OB_MODE_POSE)) {
+ if ((arm->edbo == nullptr) && (ob->mode & OB_MODE_POSE)) {
int const_index = 1000; /* ensure unique id for bone constraints */
int a;
LISTBASE_FOREACH_INDEX (bPoseChannel *, pchan, &ob->pose->chanbase, a) {
@@ -359,7 +355,7 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
}
}
/* make hierarchy */
- TreeElement *ten = tenla->subtree.first;
+ TreeElement *ten = reinterpret_cast<TreeElement *>(tenla->subtree.first);
while (ten) {
TreeElement *nten = ten->next, *par;
tselem = TREESTORE(ten);
@@ -714,13 +710,15 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
ebone->temp.p = ten;
}
/* make hierarchy */
- TreeElement *ten = arm->edbo->first ? ((EditBone *)arm->edbo->first)->temp.p : NULL;
+ TreeElement *ten = arm->edbo->first ? reinterpret_cast<TreeElement *>(
+ ((EditBone *)arm->edbo->first)->temp.p) :
+ nullptr;
while (ten) {
TreeElement *nten = ten->next, *par;
EditBone *ebone = (EditBone *)ten->directdata;
if (ebone->parent) {
BLI_remlink(&te->subtree, ten);
- par = ebone->parent->temp.p;
+ par = reinterpret_cast<TreeElement *>(ebone->parent->temp.p);
BLI_addtail(&par->subtree, ten);
ten->parent = par;
}
@@ -812,6 +810,8 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
}
}
+namespace blender::ed::outliner {
+
TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
ListBase *lb,
void *idv,
@@ -819,16 +819,16 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
short type,
short index)
{
- ID *id = idv;
+ ID *id = reinterpret_cast<ID *>(idv);
if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
id = ((PointerRNA *)idv)->owner_id;
if (!id) {
- id = ((PointerRNA *)idv)->data;
+ id = reinterpret_cast<ID *>(((PointerRNA *)idv)->data);
}
}
else if (type == TSE_GP_LAYER) {
- /* idv is the layer its self */
+ /* idv is the layer itself */
id = TREESTORE(parent)->id;
}
@@ -836,8 +836,8 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
if (type == TSE_ID_BASE) {
/* pass */
}
- else if (id == NULL) {
- return NULL;
+ else if (id == nullptr) {
+ return nullptr;
}
if (type == 0) {
@@ -845,7 +845,7 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
BLI_assert(TREESTORE_ID_TYPE(id));
}
- TreeElement *te = MEM_callocN(sizeof(TreeElement), __func__);
+ TreeElement *te = MEM_new<TreeElement>(__func__);
/* add to the visual tree */
BLI_addtail(lb, te);
/* add to the storage */
@@ -860,12 +860,12 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
te->parent = parent;
te->index = index; /* For data arrays. */
- /* New C++ based type handle (`TreeElementType` in C, `AbstractTreeElement` in C++). Only some
- * support this, eventually this should replace `TreeElement` entirely. */
- te->type = outliner_tree_element_type_create(type, te, idv);
+ /* New C++ based type handle. Only some support this, eventually this should replace
+ * `TreeElement` entirely. */
+ te->type = AbstractTreeElement::createFromType(type, *te, idv);
if (te->type) {
/* Element types ported to the new design are expected to have their name set at this point! */
- BLI_assert(te->name != NULL);
+ BLI_assert(te->name != nullptr);
}
if (ELEM(type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) {
@@ -909,14 +909,14 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
te->idcode = GS(id->name);
}
- if (te->type && outliner_tree_element_type_is_expand_valid(te->type)) {
- outliner_tree_element_type_expand(te->type, space_outliner);
+ if (te->type && te->type->isExpandValid()) {
+ tree_element_expand(*te->type, *space_outliner);
}
else if (type == TSE_SOME_ID) {
/* ID types not (fully) ported to new design yet. */
- if (outliner_tree_element_type_expand_poll(te->type, space_outliner)) {
+ if (te->type->expandPoll(*space_outliner)) {
outliner_add_id_contents(space_outliner, te, tselem, id);
- outliner_tree_element_type_post_expand(te->type, space_outliner);
+ te->type->postExpand(*space_outliner);
}
}
else if (ELEM(type,
@@ -925,199 +925,25 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
TSE_NLA,
TSE_NLA_ACTION,
TSE_NLA_TRACK,
- TSE_GP_LAYER)) {
- /* Should already use new AbstractTreeElement design. */
- BLI_assert(0);
- }
- else if (type == TSE_SEQUENCE) {
- Sequence *seq = (Sequence *)idv;
-
- /*
- * The idcode is a little hack, but the outliner
- * only check te->idcode if te->type is equal to zero,
- * so this is "safe".
- */
- te->idcode = seq->type;
- te->directdata = seq;
- te->name = seq->name + 2;
-
- if (!(seq->type & SEQ_TYPE_EFFECT)) {
- /*
- * This work like the sequence.
- * If the sequence have a name (not default name)
- * show it, in other case put the filename.
- */
-
- if (seq->type == SEQ_TYPE_META) {
- LISTBASE_FOREACH (Sequence *, p, &seq->seqbase) {
- outliner_add_element(space_outliner, &te->subtree, (void *)p, te, TSE_SEQUENCE, index);
- }
- }
- else {
- outliner_add_element(
- space_outliner, &te->subtree, (void *)seq->strip, te, TSE_SEQ_STRIP, index);
- }
- }
+ TSE_GP_LAYER,
+ TSE_RNA_STRUCT,
+ TSE_RNA_PROPERTY,
+ TSE_RNA_ARRAY_ELEM,
+ TSE_SEQUENCE,
+ TSE_SEQ_STRIP,
+ TSE_SEQUENCE_DUP)) {
+ BLI_assert_msg(false, "Element type should already use new AbstractTreeElement design");
}
- else if (type == TSE_SEQ_STRIP) {
- Strip *strip = (Strip *)idv;
-
- if (strip->dir[0] != '\0') {
- te->name = strip->dir;
- }
- else {
- te->name = IFACE_("Strip None");
- }
- te->directdata = strip;
- }
- else if (type == TSE_SEQUENCE_DUP) {
- Sequence *seq = (Sequence *)idv;
-
- te->idcode = seq->type;
- te->directdata = seq;
- te->name = seq->strip->stripdata->name;
- }
- else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
- PointerRNA *ptr = (PointerRNA *)idv;
-
- /* Don't display arrays larger, weak but index is stored as a short,
- * also the outliner isn't intended for editing such large data-sets. */
- BLI_STATIC_ASSERT(sizeof(te->index) == 2, "Index is no longer short!")
- const int tot_limit = SHRT_MAX;
-
- /* we do lazy build, for speed and to avoid infinite recursion */
-
- if (ptr->data == NULL) {
- te->name = IFACE_("(empty)");
- }
- else if (type == TSE_RNA_STRUCT) {
- /* struct */
- te->name = RNA_struct_name_get_alloc(ptr, NULL, 0, NULL);
-
- if (te->name) {
- te->flag |= TE_FREE_NAME;
- }
- else {
- te->name = RNA_struct_ui_name(ptr->type);
- }
-
- /* If searching don't expand RNA entries */
- if (SEARCHING_OUTLINER(space_outliner) && BLI_strcasecmp("RNA", te->name) == 0) {
- tselem->flag &= ~TSE_CHILDSEARCH;
- }
-
- PropertyRNA *iterprop = RNA_struct_iterator_property(ptr->type);
- int tot = RNA_property_collection_length(ptr, iterprop);
- CLAMP_MAX(tot, tot_limit);
-
- /* auto open these cases */
- if (!parent || (RNA_property_type(parent->directdata)) == PROP_POINTER) {
- if (!tselem->used) {
- tselem->flag &= ~TSE_CLOSED;
- }
- }
-
- if (TSELEM_OPEN(tselem, space_outliner)) {
- for (int a = 0; a < tot; a++) {
- PointerRNA propptr;
- RNA_property_collection_lookup_int(ptr, iterprop, a, &propptr);
- if (!(RNA_property_flag(propptr.data) & PROP_HIDDEN)) {
- outliner_add_element(
- space_outliner, &te->subtree, (void *)ptr, te, TSE_RNA_PROPERTY, a);
- }
- }
- }
- else if (tot) {
- te->flag |= TE_LAZY_CLOSED;
- }
-
- te->rnaptr = *ptr;
- }
- else if (type == TSE_RNA_PROPERTY) {
- /* property */
- PointerRNA propptr;
- PropertyRNA *iterprop = RNA_struct_iterator_property(ptr->type);
- RNA_property_collection_lookup_int(ptr, iterprop, index, &propptr);
- PropertyRNA *prop = propptr.data;
- PropertyType proptype = RNA_property_type(prop);
-
- te->name = RNA_property_ui_name(prop);
- te->directdata = prop;
- te->rnaptr = *ptr;
-
- /* If searching don't expand RNA entries */
- if (SEARCHING_OUTLINER(space_outliner) && BLI_strcasecmp("RNA", te->name) == 0) {
- tselem->flag &= ~TSE_CHILDSEARCH;
- }
-
- if (proptype == PROP_POINTER) {
- PointerRNA pptr = RNA_property_pointer_get(ptr, prop);
-
- if (pptr.data) {
- if (TSELEM_OPEN(tselem, space_outliner)) {
- outliner_add_element(
- space_outliner, &te->subtree, (void *)&pptr, te, TSE_RNA_STRUCT, -1);
- }
- else {
- te->flag |= TE_LAZY_CLOSED;
- }
- }
- }
- else if (proptype == PROP_COLLECTION) {
- int tot = RNA_property_collection_length(ptr, prop);
- CLAMP_MAX(tot, tot_limit);
-
- if (TSELEM_OPEN(tselem, space_outliner)) {
- for (int a = 0; a < tot; a++) {
- PointerRNA pptr;
- RNA_property_collection_lookup_int(ptr, prop, a, &pptr);
- outliner_add_element(
- space_outliner, &te->subtree, (void *)&pptr, te, TSE_RNA_STRUCT, a);
- }
- }
- else if (tot) {
- te->flag |= TE_LAZY_CLOSED;
- }
- }
- else if (ELEM(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
- int tot = RNA_property_array_length(ptr, prop);
- CLAMP_MAX(tot, tot_limit);
-
- if (TSELEM_OPEN(tselem, space_outliner)) {
- for (int a = 0; a < tot; a++) {
- outliner_add_element(
- space_outliner, &te->subtree, (void *)ptr, te, TSE_RNA_ARRAY_ELEM, a);
- }
- }
- else if (tot) {
- te->flag |= TE_LAZY_CLOSED;
- }
- }
- }
- else if (type == TSE_RNA_ARRAY_ELEM) {
- PropertyRNA *prop = parent->directdata;
-
- te->directdata = prop;
- te->rnaptr = *ptr;
- te->index = index;
-
- char c = RNA_property_array_item_char(prop, index);
-
- te->name = MEM_callocN(sizeof(char[20]), "OutlinerRNAArrayName");
- if (c) {
- sprintf((char *)te->name, " %c", c);
- }
- else {
- sprintf((char *)te->name, " %d", index + 1);
- }
- te->flag |= TE_FREE_NAME;
- }
+ if (tree_element_warnings_get(te, nullptr, nullptr)) {
+ te->flag |= TE_HAS_WARNING;
}
return te;
}
+} // namespace blender::ed::outliner
+
/* ======================================================= */
BLI_INLINE void outliner_add_collection_init(TreeElement *te, Collection *collection)
@@ -1157,43 +983,20 @@ TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner,
/* ======================================================= */
/* Generic Tree Building helpers - order these are called is top to bottom */
-/* Hierarchy --------------------------------------------- */
-
-void outliner_make_object_parent_hierarchy(ListBase *lb)
-{
- /* build hierarchy */
- /* XXX also, set extents here... */
- TreeElement *te = lb->first;
- while (te) {
- TreeElement *ten = te->next;
- TreeStoreElem *tselem = TREESTORE(te);
-
- if ((tselem->type == TSE_SOME_ID) && te->idcode == ID_OB) {
- Object *ob = (Object *)tselem->id;
- if (ob->parent && ob->parent->id.newid) {
- BLI_remlink(lb, te);
- TreeElement *tep = (TreeElement *)ob->parent->id.newid;
- BLI_addtail(&tep->subtree, te);
- te->parent = tep;
- }
- }
- te = ten;
- }
-}
-
/* Sorting ------------------------------------------------------ */
-typedef struct tTreeSort {
+struct tTreeSort {
TreeElement *te;
ID *id;
const char *name;
short idcode;
-} tTreeSort;
+};
/* alphabetical comparator, trying to put objects first */
static int treesort_alpha_ob(const void *v1, const void *v2)
{
- const tTreeSort *x1 = v1, *x2 = v2;
+ const tTreeSort *x1 = reinterpret_cast<const tTreeSort *>(v1);
+ const tTreeSort *x2 = reinterpret_cast<const tTreeSort *>(v2);
/* first put objects last (hierarchy) */
int comp = (x1->idcode == ID_OB);
@@ -1231,7 +1034,8 @@ static int treesort_alpha_ob(const void *v1, const void *v2)
/* Move children that are not in the collection to the end of the list. */
static int treesort_child_not_in_collection(const void *v1, const void *v2)
{
- const tTreeSort *x1 = v1, *x2 = v2;
+ const tTreeSort *x1 = reinterpret_cast<const tTreeSort *>(v1);
+ const tTreeSort *x2 = reinterpret_cast<const tTreeSort *>(v2);
/* Among objects first come the ones in the collection, followed by the ones not on it.
* This way we can have the dashed lines in a separate style connecting the former. */
@@ -1244,7 +1048,8 @@ static int treesort_child_not_in_collection(const void *v1, const void *v2)
/* alphabetical comparator */
static int treesort_alpha(const void *v1, const void *v2)
{
- const tTreeSort *x1 = v1, *x2 = v2;
+ const tTreeSort *x1 = reinterpret_cast<const tTreeSort *>(v1);
+ const tTreeSort *x2 = reinterpret_cast<const tTreeSort *>(v2);
int comp = BLI_strcasecmp_natural(x1->name, x2->name);
@@ -1301,24 +1106,25 @@ static int treesort_obtype_alpha(const void *v1, const void *v2)
/* sort happens on each subtree individual */
static void outliner_sort(ListBase *lb)
{
- TreeElement *te = lb->last;
- if (te == NULL) {
+ TreeElement *last_te = reinterpret_cast<TreeElement *>(lb->last);
+ if (last_te == nullptr) {
return;
}
- TreeStoreElem *tselem = TREESTORE(te);
+ TreeStoreElem *last_tselem = TREESTORE(last_te);
/* Sorting rules; only object lists, ID lists, or deform-groups. */
- if (ELEM(tselem->type, TSE_DEFGROUP, TSE_ID_BASE) ||
- ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB))) {
+ if (ELEM(last_tselem->type, TSE_DEFGROUP, TSE_ID_BASE) ||
+ ((last_tselem->type == TSE_SOME_ID) && (last_te->idcode == ID_OB))) {
int totelem = BLI_listbase_count(lb);
if (totelem > 1) {
- tTreeSort *tear = MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array");
+ tTreeSort *tear = reinterpret_cast<tTreeSort *>(
+ MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array"));
tTreeSort *tp = tear;
int skip = 0;
- for (te = lb->first; te; te = te->next, tp++) {
- tselem = TREESTORE(te);
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
+ TreeStoreElem *tselem = TREESTORE(te);
tp->te = te;
tp->name = te->name;
tp->idcode = te->idcode;
@@ -1331,6 +1137,7 @@ static void outliner_sort(ListBase *lb)
}
tp->id = tselem->id;
+ tp++;
}
/* just sort alphabetically */
@@ -1367,26 +1174,28 @@ static void outliner_sort(ListBase *lb)
static void outliner_collections_children_sort(ListBase *lb)
{
- TreeElement *te = lb->last;
- if (te == NULL) {
+ TreeElement *last_te = reinterpret_cast<TreeElement *>(lb->last);
+ if (last_te == nullptr) {
return;
}
- TreeStoreElem *tselem = TREESTORE(te);
+ TreeStoreElem *last_tselem = TREESTORE(last_te);
/* Sorting rules: only object lists. */
- if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
+ if ((last_tselem->type == TSE_SOME_ID) && (last_te->idcode == ID_OB)) {
int totelem = BLI_listbase_count(lb);
if (totelem > 1) {
- tTreeSort *tear = MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array");
+ tTreeSort *tear = reinterpret_cast<tTreeSort *>(
+ MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array"));
tTreeSort *tp = tear;
- for (te = lb->first; te; te = te->next, tp++) {
- tselem = TREESTORE(te);
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
+ TreeStoreElem *tselem = TREESTORE(te);
tp->te = te;
tp->name = te->name;
tp->idcode = te->idcode;
tp->id = tselem->id;
+ tp++;
}
qsort(tear, totelem, sizeof(tTreeSort), treesort_child_not_in_collection);
@@ -1408,10 +1217,10 @@ static void outliner_collections_children_sort(ListBase *lb)
/* Filtering ----------------------------------------------- */
-typedef struct OutlinerTreeElementFocus {
+struct OutlinerTreeElementFocus {
TreeStoreElem *tselem;
int ys;
-} OutlinerTreeElementFocus;
+};
/**
* Bring the outliner scrolling back to where it was in relation to the original focus element
@@ -1423,12 +1232,12 @@ static void outliner_restore_scrolling_position(SpaceOutliner *space_outliner,
{
View2D *v2d = &region->v2d;
- if (focus->tselem != NULL) {
+ if (focus->tselem != nullptr) {
outliner_set_coordinates(region, space_outliner);
TreeElement *te_new = outliner_find_tree_element(&space_outliner->tree, focus->tselem);
- if (te_new != NULL) {
+ if (te_new != nullptr) {
int ys_new = te_new->ys;
int ys_old = focus->ys;
@@ -1466,17 +1275,16 @@ static TreeElement *outliner_find_first_desired_element_at_y_recursive(
}
if (TSELEM_OPEN(te->store_elem, space_outliner)) {
- TreeElement *te_iter, *te_sub;
- for (te_iter = te->subtree.first; te_iter; te_iter = te_iter->next) {
- te_sub = outliner_find_first_desired_element_at_y_recursive(
+ LISTBASE_FOREACH (TreeElement *, te_iter, &te->subtree) {
+ TreeElement *te_sub = outliner_find_first_desired_element_at_y_recursive(
space_outliner, te_iter, limit, callback_test);
- if (te_sub != NULL) {
+ if (te_sub != nullptr) {
return te_sub;
}
}
}
- return NULL;
+ return nullptr;
}
/**
@@ -1487,7 +1295,7 @@ static TreeElement *outliner_find_first_desired_element_at_y_recursive(
*
* Basically we keep going up and down the outliner tree from that point forward, until we find
* what we are looking for. If we are past the visible range and we can't find a valid element
- * we return NULL.
+ * we return nullptr.
*/
static TreeElement *outliner_find_first_desired_element_at_y(const SpaceOutliner *space_outliner,
const float view_co,
@@ -1504,15 +1312,15 @@ static TreeElement *outliner_find_first_desired_element_at_y(const SpaceOutliner
callback_test = test_collection_callback;
}
- while (te != NULL) {
+ while (te != nullptr) {
TreeElement *te_sub = outliner_find_first_desired_element_at_y_recursive(
space_outliner, te, view_co_limit, callback_test);
- if (te_sub != NULL) {
+ if (te_sub != nullptr) {
/* Skip the element if it was not visible to start with. */
if (te->ys + UI_UNIT_Y > view_co_limit) {
return te_sub;
}
- return NULL;
+ return nullptr;
}
if (te->next) {
@@ -1520,7 +1328,7 @@ static TreeElement *outliner_find_first_desired_element_at_y(const SpaceOutliner
continue;
}
- if (te->parent == NULL) {
+ if (te->parent == nullptr) {
break;
}
@@ -1533,7 +1341,7 @@ static TreeElement *outliner_find_first_desired_element_at_y(const SpaceOutliner
}
}
- return NULL;
+ return nullptr;
}
/**
@@ -1554,12 +1362,12 @@ static void outliner_store_scrolling_position(SpaceOutliner *space_outliner,
TreeElement *te = outliner_find_first_desired_element_at_y(
space_outliner, region->v2d.cur.ymax, limit);
- if (te != NULL) {
+ if (te != nullptr) {
focus->tselem = TREESTORE(te);
focus->ys = te->ys;
}
else {
- focus->tselem = NULL;
+ focus->tselem = nullptr;
}
}
@@ -1617,7 +1425,7 @@ static bool outliner_element_visible_get(ViewLayer *view_layer,
Object *ob = (Object *)tselem->id;
Base *base = (Base *)te->directdata;
- BLI_assert((base == NULL) || (base->object == ob));
+ BLI_assert((base == nullptr) || (base->object == ob));
if (exclude_filter & SO_FILTER_OB_TYPE) {
switch (ob->type) {
@@ -1655,10 +1463,10 @@ static bool outliner_element_visible_get(ViewLayer *view_layer,
}
if (exclude_filter & SO_FILTER_OB_STATE) {
- if (base == NULL) {
+ if (base == nullptr) {
base = BKE_view_layer_base_find(view_layer, ob);
- if (base == NULL) {
+ if (base == nullptr) {
return false;
}
}
@@ -1693,14 +1501,14 @@ static bool outliner_element_visible_get(ViewLayer *view_layer,
return is_visible;
}
- if ((te->parent != NULL) && (TREESTORE(te->parent)->type == TSE_SOME_ID) &&
+ if ((te->parent != nullptr) && (TREESTORE(te->parent)->type == TSE_SOME_ID) &&
(te->parent->idcode == ID_OB)) {
if (exclude_filter & SO_FILTER_NO_CHILDREN) {
return false;
}
}
}
- else if ((te->parent != NULL) && (TREESTORE(te->parent)->type == TSE_SOME_ID) &&
+ else if ((te->parent != nullptr) && (TREESTORE(te->parent)->type == TSE_SOME_ID) &&
(te->parent->idcode == ID_OB)) {
if (exclude_filter & SO_FILTER_NO_OB_CONTENT) {
return false;
@@ -1743,8 +1551,9 @@ static TreeElement *outliner_extract_children_from_subtree(TreeElement *element,
TreeElement *te_next = element->next;
if (outliner_element_is_collection_or_object(element)) {
- TreeElement *te_prev = NULL;
- for (TreeElement *te = element->subtree.last; te; te = te_prev) {
+ TreeElement *te_prev = nullptr;
+ for (TreeElement *te = reinterpret_cast<TreeElement *>(element->subtree.last); te;
+ te = te_prev) {
te_prev = te->prev;
if (!outliner_element_is_collection_or_object(te)) {
@@ -1771,7 +1580,7 @@ static int outliner_filter_subtree(SpaceOutliner *space_outliner,
TreeElement *te, *te_next;
TreeStoreElem *tselem;
- for (te = lb->first; te; te = te_next) {
+ for (te = reinterpret_cast<TreeElement *>(lb->first); te; te = te_next) {
te_next = te->next;
if ((outliner_element_visible_get(view_layer, te, exclude_filter) == false)) {
/* Don't free the tree, but extract the children from the parent and add to this tree. */
@@ -1824,7 +1633,7 @@ static int outliner_filter_subtree(SpaceOutliner *space_outliner,
static void outliner_filter_tree(SpaceOutliner *space_outliner, ViewLayer *view_layer)
{
- char search_buff[sizeof(((struct SpaceOutliner *)NULL)->search_string) + 2];
+ char search_buff[sizeof(((struct SpaceOutliner *)nullptr)->search_string) + 2];
char *search_string;
const int exclude_filter = outliner_exclude_filter_get(space_outliner);
@@ -1850,7 +1659,7 @@ static void outliner_clear_newid_from_main(Main *bmain)
{
ID *id_iter;
FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
- id_iter->newid = NULL;
+ id_iter->newid = nullptr;
}
FOREACH_MAIN_ID_END;
}
@@ -1890,17 +1699,15 @@ void outliner_build_tree(Main *mainvar,
outliner_free_tree(&space_outliner->tree);
outliner_storage_cleanup(space_outliner);
- outliner_tree_display_destroy(&space_outliner->runtime->tree_display);
- space_outliner->runtime->tree_display = outliner_tree_display_create(space_outliner->outlinevis,
- space_outliner);
+ space_outliner->runtime->tree_display = AbstractTreeDisplay::createFromDisplayMode(
+ space_outliner->outlinevis, *space_outliner);
/* All tree displays should be created as sub-classes of AbstractTreeDisplay. */
- BLI_assert(space_outliner->runtime->tree_display != NULL);
+ BLI_assert(space_outliner->runtime->tree_display != nullptr);
- TreeSourceData source_data = {.bmain = mainvar, .scene = scene, .view_layer = view_layer};
- space_outliner->tree = outliner_tree_display_build_tree(space_outliner->runtime->tree_display,
- &source_data);
+ TreeSourceData source_data{*mainvar, *scene, *view_layer};
+ space_outliner->tree = space_outliner->runtime->tree_display->buildTree(source_data);
if ((space_outliner->flag & SO_SKIP_SORT_ALPHA) == 0) {
outliner_sort(&space_outliner->tree);
diff --git a/source/blender/editors/space_outliner/outliner_utils.c b/source/blender/editors/space_outliner/outliner_utils.cc
index d370d508198..86b56a7ec12 100644
--- a/source/blender/editors/space_outliner/outliner_utils.c
+++ b/source/blender/editors/space_outliner/outliner_utils.cc
@@ -21,7 +21,7 @@
* \ingroup spoutliner
*/
-#include <string.h>
+#include <cstring>
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
@@ -42,7 +42,7 @@
#include "UI_interface.h"
#include "UI_view2d.h"
-#include "outliner_intern.h"
+#include "outliner_intern.hh"
/* -------------------------------------------------------------------- */
/** \name Tree View Context
@@ -58,7 +58,7 @@ void outliner_viewcontext_init(const bContext *C, TreeViewContext *tvc)
/* Objects. */
tvc->obact = OBACT(tvc->view_layer);
- if (tvc->obact != NULL) {
+ if (tvc->obact != nullptr) {
tvc->ob_edit = OBEDIT_FROM_OBACT(tvc->obact);
if ((tvc->obact->type == OB_ARMATURE) ||
@@ -104,14 +104,14 @@ TreeElement *outliner_find_item_at_y(const SpaceOutliner *space_outliner,
}
}
- return NULL;
+ return nullptr;
}
static TreeElement *outliner_find_item_at_x_in_row_recursive(const TreeElement *parent_te,
float view_co_x,
bool *r_is_merged_icon)
{
- TreeElement *child_te = parent_te->subtree.first;
+ TreeElement *child_te = reinterpret_cast<TreeElement *>(parent_te->subtree.first);
while (child_te) {
const bool over_element = (view_co_x > child_te->xs) && (view_co_x < child_te->xend);
@@ -168,7 +168,7 @@ TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store
return tes;
}
}
- return NULL;
+ return nullptr;
}
TreeElement *outliner_find_parent_element(ListBase *lb,
@@ -185,25 +185,25 @@ TreeElement *outliner_find_parent_element(ListBase *lb,
return find_te;
}
}
- return NULL;
+ return nullptr;
}
TreeElement *outliner_find_tse(SpaceOutliner *space_outliner, const TreeStoreElem *tse)
{
TreeStoreElem *tselem;
- if (tse->id == NULL) {
- return NULL;
+ if (tse->id == nullptr) {
+ return nullptr;
}
- /* check if 'tse' is in treestore */
+ /* Check if 'tse' is in tree-store. */
tselem = BKE_outliner_treehash_lookup_any(
space_outliner->runtime->treehash, tse->type, tse->nr, tse->id);
if (tselem) {
return outliner_find_tree_element(&space_outliner->tree, tselem);
}
- return NULL;
+ return nullptr;
}
TreeElement *outliner_find_id(SpaceOutliner *space_outliner, ListBase *lb, const ID *id)
@@ -221,7 +221,7 @@ TreeElement *outliner_find_id(SpaceOutliner *space_outliner, ListBase *lb, const
return tes;
}
}
- return NULL;
+ return nullptr;
}
TreeElement *outliner_find_posechannel(ListBase *lb, const bPoseChannel *pchan)
@@ -239,7 +239,7 @@ TreeElement *outliner_find_posechannel(ListBase *lb, const bPoseChannel *pchan)
}
}
}
- return NULL;
+ return nullptr;
}
TreeElement *outliner_find_editbone(ListBase *lb, const EditBone *ebone)
@@ -257,7 +257,7 @@ TreeElement *outliner_find_editbone(ListBase *lb, const EditBone *ebone)
}
}
}
- return NULL;
+ return nullptr;
}
TreeElement *outliner_search_back_te(TreeElement *te, short idcode)
@@ -272,7 +272,7 @@ TreeElement *outliner_search_back_te(TreeElement *te, short idcode)
}
te = te->parent;
}
- return NULL;
+ return nullptr;
}
ID *outliner_search_back(TreeElement *te, short idcode)
@@ -285,7 +285,7 @@ ID *outliner_search_back(TreeElement *te, short idcode)
tselem = TREESTORE(search_te);
return tselem->id;
}
- return NULL;
+ return nullptr;
}
bool outliner_tree_traverse(const SpaceOutliner *space_outliner,
@@ -295,7 +295,8 @@ bool outliner_tree_traverse(const SpaceOutliner *space_outliner,
TreeTraversalFunc func,
void *customdata)
{
- for (TreeElement *te = tree->first, *te_next; te; te = te_next) {
+ for (TreeElement *te = reinterpret_cast<TreeElement *>(tree->first), *te_next; te;
+ te = te_next) {
TreeTraversalAction func_retval = TRAVERSE_CONTINUE;
/* in case te is freed in callback */
TreeStoreElem *tselem = TREESTORE(te);
@@ -382,7 +383,7 @@ TreeElement *outliner_find_element_with_flag(const ListBase *lb, short flag)
return active_element;
}
}
- return NULL;
+ return nullptr;
}
bool outliner_is_element_visible(const TreeElement *te)
@@ -467,7 +468,7 @@ Base *ED_outliner_give_base_under_cursor(bContext *C, const int mval[2])
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
TreeElement *te;
- Base *base = NULL;
+ Base *base = nullptr;
float view_mval[2];
UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &view_mval[0], &view_mval[1]);
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.cc
index 6c45d39e0d8..0fb17fa3f47 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.cc
@@ -21,8 +21,8 @@
* \ingroup spoutliner
*/
-#include <stdio.h>
-#include <string.h>
+#include <cstdio>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -31,6 +31,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_lib_remap.h"
#include "BKE_outliner_treehash.h"
#include "BKE_screen.h"
@@ -49,8 +50,20 @@
#include "UI_resources.h"
#include "UI_view2d.h"
-#include "outliner_intern.h"
-#include "tree/tree_display.h"
+#include "outliner_intern.hh"
+#include "tree/tree_display.hh"
+
+SpaceOutliner_Runtime::SpaceOutliner_Runtime(const SpaceOutliner_Runtime & /*other*/)
+ : tree_display(nullptr), treehash(nullptr)
+{
+}
+
+SpaceOutliner_Runtime::~SpaceOutliner_Runtime()
+{
+ if (treehash) {
+ BKE_outliner_treehash_free(treehash);
+ }
+}
static void outliner_main_region_init(wmWindowManager *wm, ARegion *region)
{
@@ -92,7 +105,7 @@ static void outliner_main_region_draw(const bContext *C, ARegion *region)
UI_view2d_view_restore(C);
/* scrollers */
- UI_view2d_scrollers_draw(v2d, NULL);
+ UI_view2d_scrollers_draw(v2d, nullptr);
}
static void outliner_main_region_free(ARegion *UNUSED(region))
@@ -104,7 +117,7 @@ static void outliner_main_region_listener(const wmRegionListenerParams *params)
ScrArea *area = params->area;
ARegion *region = params->region;
wmNotifier *wmn = params->notifier;
- SpaceOutliner *space_outliner = area->spacedata.first;
+ SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first);
/* context changes */
switch (wmn->category) {
@@ -262,23 +275,25 @@ static void outliner_main_region_listener(const wmRegionListenerParams *params)
}
}
+/* FIXME: See comment above #WM_msg_publish_rna_prop(). */
+extern "C" {
static void outliner_main_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
{
struct wmMsgBus *mbus = params->message_bus;
ScrArea *area = params->area;
ARegion *region = params->region;
- SpaceOutliner *space_outliner = area->spacedata.first;
+ SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first);
- wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
- .owner = region,
- .user_data = region,
- .notify = ED_region_do_msg_notify_tag_redraw,
- };
+ wmMsgSubscribeValue msg_sub_value_region_tag_redraw{};
+ msg_sub_value_region_tag_redraw.owner = region;
+ msg_sub_value_region_tag_redraw.user_data = region;
+ msg_sub_value_region_tag_redraw.notify = ED_region_do_msg_notify_tag_redraw;
if (ELEM(space_outliner->outlinevis, SO_VIEW_LAYER, SO_SCENES, SO_OVERRIDES_LIBRARY)) {
WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_region_tag_redraw);
}
}
+}
/* ************************ header outliner area region *********************** */
@@ -324,7 +339,7 @@ static SpaceLink *outliner_create(const ScrArea *UNUSED(area), const Scene *UNUS
ARegion *region;
SpaceOutliner *space_outliner;
- space_outliner = MEM_callocN(sizeof(SpaceOutliner), "initoutliner");
+ space_outliner = MEM_cnew<SpaceOutliner>("initoutliner");
space_outliner->spacetype = SPACE_OUTLINER;
space_outliner->filter_id_type = ID_GR;
space_outliner->show_restrict_flags = SO_RESTRICT_ENABLE | SO_RESTRICT_HIDE | SO_RESTRICT_RENDER;
@@ -334,14 +349,14 @@ static SpaceLink *outliner_create(const ScrArea *UNUSED(area), const Scene *UNUS
space_outliner->filter = SO_FILTER_NO_VIEW_LAYERS;
/* header */
- region = MEM_callocN(sizeof(ARegion), "header for outliner");
+ region = MEM_cnew<ARegion>("header for outliner");
BLI_addtail(&space_outliner->regionbase, region);
region->regiontype = RGN_TYPE_HEADER;
region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
/* main region */
- region = MEM_callocN(sizeof(ARegion), "main region for outliner");
+ region = MEM_cnew<ARegion>("main region for outliner");
BLI_addtail(&space_outliner->regionbase, region);
region->regiontype = RGN_TYPE_WINDOW;
@@ -359,84 +374,81 @@ static void outliner_free(SpaceLink *sl)
BLI_mempool_destroy(space_outliner->treestore);
}
- if (space_outliner->runtime) {
- outliner_tree_display_destroy(&space_outliner->runtime->tree_display);
- if (space_outliner->runtime->treehash) {
- BKE_outliner_treehash_free(space_outliner->runtime->treehash);
- }
- MEM_freeN(space_outliner->runtime);
- }
+ MEM_delete(space_outliner->runtime);
}
/* spacetype; init callback */
static void outliner_init(wmWindowManager *UNUSED(wm), ScrArea *area)
{
- SpaceOutliner *space_outliner = area->spacedata.first;
+ SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first);
- if (space_outliner->runtime == NULL) {
- space_outliner->runtime = MEM_callocN(sizeof(*space_outliner->runtime),
- "SpaceOutliner_Runtime");
+ if (space_outliner->runtime == nullptr) {
+ space_outliner->runtime = MEM_new<SpaceOutliner_Runtime>("SpaceOutliner_Runtime");
}
}
static SpaceLink *outliner_duplicate(SpaceLink *sl)
{
SpaceOutliner *space_outliner = (SpaceOutliner *)sl;
- SpaceOutliner *space_outliner_new = MEM_dupallocN(space_outliner);
+ SpaceOutliner *space_outliner_new = MEM_new<SpaceOutliner>(__func__, *space_outliner);
BLI_listbase_clear(&space_outliner_new->tree);
- space_outliner_new->treestore = NULL;
+ space_outliner_new->treestore = nullptr;
space_outliner_new->sync_select_dirty = WM_OUTLINER_SYNC_SELECT_FROM_ALL;
if (space_outliner->runtime) {
- space_outliner_new->runtime = MEM_dupallocN(space_outliner->runtime);
- space_outliner_new->runtime->tree_display = NULL;
- space_outliner_new->runtime->treehash = NULL;
+ /* Copy constructor handles details. */
+ space_outliner_new->runtime = MEM_new<SpaceOutliner_Runtime>("SpaceOutliner_runtime dup",
+ *space_outliner->runtime);
}
return (SpaceLink *)space_outliner_new;
}
-static void outliner_id_remap(ScrArea *area, SpaceLink *slink, ID *old_id, ID *new_id)
+static void outliner_id_remap(ScrArea *area, SpaceLink *slink, const struct IDRemapper *mappings)
{
SpaceOutliner *space_outliner = (SpaceOutliner *)slink;
- /* Some early out checks. */
- if (!TREESTORE_ID_TYPE(old_id)) {
- return; /* ID type is not used by outliner. */
- }
+ BKE_id_remapper_apply(mappings, (ID **)&space_outliner->search_tse.id, ID_REMAP_APPLY_DEFAULT);
- if (space_outliner->search_tse.id == old_id) {
- space_outliner->search_tse.id = new_id;
+ if (!space_outliner->treestore) {
+ return;
}
- if (space_outliner->treestore) {
- TreeStoreElem *tselem;
- BLI_mempool_iter iter;
- bool changed = false;
-
- BLI_mempool_iternew(space_outliner->treestore, &iter);
- while ((tselem = BLI_mempool_iterstep(&iter))) {
- if (tselem->id == old_id) {
- tselem->id = new_id;
+ TreeStoreElem *tselem;
+ BLI_mempool_iter iter;
+ bool changed = false;
+ bool unassigned = false;
+
+ BLI_mempool_iternew(space_outliner->treestore, &iter);
+ while ((tselem = static_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) {
+ switch (BKE_id_remapper_apply(mappings, &tselem->id, ID_REMAP_APPLY_DEFAULT)) {
+ case ID_REMAP_RESULT_SOURCE_REMAPPED:
changed = true;
- }
+ break;
+ case ID_REMAP_RESULT_SOURCE_UNASSIGNED:
+ changed = true;
+ unassigned = true;
+ break;
+ case ID_REMAP_RESULT_SOURCE_UNAVAILABLE:
+ case ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE:
+ break;
}
+ }
- /* Note that the Outliner may not be the active editor of the area, and hence not initialized.
- * So runtime data might not have been created yet. */
- if (space_outliner->runtime && space_outliner->runtime->treehash && changed) {
- /* rebuild hash table, because it depends on ids too */
- /* postpone a full rebuild because this can be called many times on-free */
- space_outliner->storeflag |= SO_TREESTORE_REBUILD;
-
- if (new_id == NULL) {
- /* Redraw is needed when removing data for multiple outlines show the same data.
- * without this, the stale data won't get fully flushed when this outliner
- * is not the active outliner the user is interacting with. See T85976. */
- ED_area_tag_redraw(area);
- }
+ /* Note that the Outliner may not be the active editor of the area, and hence not initialized.
+ * So runtime data might not have been created yet. */
+ if (space_outliner->runtime && space_outliner->runtime->treehash && changed) {
+ /* rebuild hash table, because it depends on ids too */
+ /* postpone a full rebuild because this can be called many times on-free */
+ space_outliner->storeflag |= SO_TREESTORE_REBUILD;
+
+ if (unassigned) {
+ /* Redraw is needed when removing data for multiple outlines show the same data.
+ * without this, the stale data won't get fully flushed when this outliner
+ * is not the active outliner the user is interacting with. See T85976. */
+ ED_area_tag_redraw(area);
}
}
}
@@ -444,14 +456,14 @@ static void outliner_id_remap(ScrArea *area, SpaceLink *slink, ID *old_id, ID *n
static void outliner_deactivate(struct ScrArea *area)
{
/* Remove hover highlights */
- SpaceOutliner *space_outliner = area->spacedata.first;
+ SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first);
outliner_flag_set(&space_outliner->tree, TSE_HIGHLIGHTED_ANY, false);
ED_region_tag_redraw_no_rebuild(BKE_area_find_region_type(area, RGN_TYPE_WINDOW));
}
void ED_spacetype_outliner(void)
{
- SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype time");
+ SpaceType *st = MEM_cnew<SpaceType>("spacetype time");
ARegionType *art;
st->spaceid = SPACE_OUTLINER;
@@ -469,7 +481,7 @@ void ED_spacetype_outliner(void)
st->context = outliner_context;
/* regions: main window */
- art = MEM_callocN(sizeof(ARegionType), "spacetype outliner region");
+ art = MEM_cnew<ARegionType>("spacetype outliner region");
art->regionid = RGN_TYPE_WINDOW;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
@@ -481,7 +493,7 @@ void ED_spacetype_outliner(void)
BLI_addhead(&st->regiontypes, art);
/* regions: header */
- art = MEM_callocN(sizeof(ARegionType), "spacetype outliner header region");
+ art = MEM_cnew<ARegionType>("spacetype outliner header region");
art->regionid = RGN_TYPE_HEADER;
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER;
diff --git a/source/blender/editors/space_outliner/tree/common.cc b/source/blender/editors/space_outliner/tree/common.cc
index 306d59288f4..c6b5ee3b7ef 100644
--- a/source/blender/editors/space_outliner/tree/common.cc
+++ b/source/blender/editors/space_outliner/tree/common.cc
@@ -20,10 +20,18 @@
* Functions and helpers shared between tree-display types or other tree related code.
*/
+#include "BLI_listbase.h"
+
#include "BKE_idtype.h"
+#include "DNA_anim_types.h"
+#include "DNA_object_types.h"
+#include "DNA_outliner_types.h"
+
#include "RNA_access.h"
+#include "../outliner_intern.hh"
+#include "common.hh"
#include "tree_display.hh"
/* -------------------------------------------------------------------- */
@@ -38,3 +46,33 @@ const char *outliner_idcode_to_plural(short idcode)
}
/** \} */
+
+void outliner_make_object_parent_hierarchy(ListBase *lb)
+{
+ /* build hierarchy */
+ /* XXX also, set extents here... */
+ TreeElement *te = reinterpret_cast<TreeElement *>(lb->first);
+ while (te) {
+ TreeElement *ten = te->next;
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if ((tselem->type == TSE_SOME_ID) && te->idcode == ID_OB) {
+ Object *ob = (Object *)tselem->id;
+ if (ob->parent && ob->parent->id.newid) {
+ BLI_remlink(lb, te);
+ TreeElement *tep = (TreeElement *)ob->parent->id.newid;
+ BLI_addtail(&tep->subtree, te);
+ te->parent = tep;
+ }
+ }
+ te = ten;
+ }
+}
+
+bool outliner_animdata_test(const AnimData *adt)
+{
+ if (adt) {
+ return (adt->action || adt->drivers.first || adt->nla_tracks.first);
+ }
+ return false;
+}
diff --git a/source/blender/editors/space_node/node_toolbar.cc b/source/blender/editors/space_outliner/tree/common.hh
index c32dcbef91b..1745bfa436e 100644
--- a/source/blender/editors/space_node/node_toolbar.cc
+++ b/source/blender/editors/space_outliner/tree/common.hh
@@ -12,28 +12,17 @@
* 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) 2012 Blender Foundation.
- * All rights reserved.
*/
/** \file
- * \ingroup nodes
+ * \ingroup spoutliner
*/
-#include "BLI_utildefines.h"
-
-#include "DNA_node_types.h"
-
-#include "BKE_context.h"
-#include "BKE_screen.h"
-
-#include "WM_api.h"
+#pragma once
-#include "node_intern.hh" /* own include */
+struct ListBase;
-/* ******************* node toolbar registration ************** */
+const char *outliner_idcode_to_plural(short idcode);
-void node_toolbar_register(ARegionType *UNUSED(art))
-{
-}
+void outliner_make_object_parent_hierarchy(ListBase *lb);
+bool outliner_animdata_test(const struct AnimData *adt);
diff --git a/source/blender/editors/space_outliner/tree/tree_display.cc b/source/blender/editors/space_outliner/tree/tree_display.cc
index 003afd5bdec..d2b6fff6996 100644
--- a/source/blender/editors/space_outliner/tree/tree_display.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display.cc
@@ -19,50 +19,41 @@
*/
#include "DNA_listBase.h"
+#include "DNA_space_types.h"
#include "tree_display.hh"
using namespace blender::ed::outliner;
-TreeDisplay *outliner_tree_display_create(eSpaceOutliner_Mode mode, SpaceOutliner *space_outliner)
-{
- AbstractTreeDisplay *tree_display = nullptr;
+namespace blender::ed::outliner {
- switch (mode) {
+std::unique_ptr<AbstractTreeDisplay> AbstractTreeDisplay::createFromDisplayMode(
+ int /*eSpaceOutliner_Mode*/ mode, SpaceOutliner &space_outliner)
+{
+ switch ((eSpaceOutliner_Mode)mode) {
case SO_SCENES:
- tree_display = new TreeDisplayScenes(*space_outliner);
- break;
+ return std::make_unique<TreeDisplayScenes>(space_outliner);
case SO_LIBRARIES:
- tree_display = new TreeDisplayLibraries(*space_outliner);
- break;
+ return std::make_unique<TreeDisplayLibraries>(space_outliner);
case SO_SEQUENCE:
- tree_display = new TreeDisplaySequencer(*space_outliner);
- break;
+ return std::make_unique<TreeDisplaySequencer>(space_outliner);
case SO_DATA_API:
- tree_display = new TreeDisplayDataAPI(*space_outliner);
- break;
+ return std::make_unique<TreeDisplayDataAPI>(space_outliner);
case SO_ID_ORPHANS:
- tree_display = new TreeDisplayIDOrphans(*space_outliner);
- break;
+ return std::make_unique<TreeDisplayIDOrphans>(space_outliner);
case SO_OVERRIDES_LIBRARY:
- tree_display = new TreeDisplayOverrideLibrary(*space_outliner);
- break;
+ return std::make_unique<TreeDisplayOverrideLibrary>(space_outliner);
case SO_VIEW_LAYER:
+ /* FIXME(Julian): this should not be the default! Return nullptr and handle that as valid
+ * case. */
default:
- tree_display = new TreeDisplayViewLayer(*space_outliner);
- break;
+ return std::make_unique<TreeDisplayViewLayer>(space_outliner);
}
-
- return reinterpret_cast<TreeDisplay *>(tree_display);
}
-void outliner_tree_display_destroy(TreeDisplay **tree_display)
+bool AbstractTreeDisplay::hasWarnings() const
{
- delete reinterpret_cast<AbstractTreeDisplay *>(*tree_display);
- *tree_display = nullptr;
+ return has_warnings;
}
-ListBase outliner_tree_display_build_tree(TreeDisplay *tree_display, TreeSourceData *source_data)
-{
- return reinterpret_cast<AbstractTreeDisplay *>(tree_display)->buildTree(*source_data);
-}
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_display.h b/source/blender/editors/space_outliner/tree/tree_display.h
deleted file mode 100644
index b6dc33ba7b7..00000000000
--- a/source/blender/editors/space_outliner/tree/tree_display.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/** \file
- * \ingroup spoutliner
- *
- * C-API for the Tree-Display types.
- */
-
-#pragma once
-
-#include "DNA_space_types.h"
-
-struct ListBase;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** C alias for an #AbstractTreeDisplay handle. */
-typedef struct TreeDisplay TreeDisplay;
-
-/**
- * \brief The data to build the tree from.
- */
-typedef struct TreeSourceData {
- struct Main *bmain;
- struct Scene *scene;
- struct ViewLayer *view_layer;
-} TreeSourceData;
-
-TreeDisplay *outliner_tree_display_create(eSpaceOutliner_Mode mode, SpaceOutliner *space_outliner);
-void outliner_tree_display_destroy(TreeDisplay **tree_display);
-
-ListBase outliner_tree_display_build_tree(TreeDisplay *tree_display, TreeSourceData *source_data);
-
-/* The following functions are needed to build the tree. They are calls back into C; the way
- * elements are created should be refactored and ported to C++ with a new design/API too. */
-/**
- * TODO: this function needs to be split up! It's getting a bit too large...
- *
- * \note "ID" is not always a real ID.
- * \note If child items are only added to the tree if the item is open,
- * the `TSE_` type _must_ be added to #outliner_element_needs_rebuild_on_open_change().
- */
-struct TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
- ListBase *lb,
- void *idv,
- struct TreeElement *parent,
- short type,
- short index);
-/* make sure elements are correctly nested */
-void outliner_make_object_parent_hierarchy(ListBase *lb);
-bool outliner_animdata_test(const struct AnimData *adt);
-TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner,
- struct Collection *collection,
- TreeElement *ten);
-
-const char *outliner_idcode_to_plural(short idcode);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/source/blender/editors/space_outliner/tree/tree_display.hh b/source/blender/editors/space_outliner/tree/tree_display.hh
index 54e64655b18..68f0f9c562d 100644
--- a/source/blender/editors/space_outliner/tree/tree_display.hh
+++ b/source/blender/editors/space_outliner/tree/tree_display.hh
@@ -34,16 +34,35 @@
#pragma once
-#include "tree_display.h"
+#include <memory>
+struct ID;
+struct LayerCollection;
+struct Library;
struct ListBase;
struct Main;
+struct Scene;
+struct Sequence;
struct SpaceOutliner;
struct TreeElement;
-struct TreeSourceData;
+struct ViewLayer;
namespace blender::ed::outliner {
+/**
+ * \brief The data to build the tree from.
+ */
+struct TreeSourceData {
+ Main *bmain;
+ Scene *scene;
+ ViewLayer *view_layer;
+
+ TreeSourceData(Main &bmain, Scene &scene, ViewLayer &view_layer)
+ : bmain(&bmain), scene(&scene), view_layer(&view_layer)
+ {
+ }
+};
+
/* -------------------------------------------------------------------- */
/* Tree-Display Interface */
@@ -59,13 +78,21 @@ class AbstractTreeDisplay {
}
virtual ~AbstractTreeDisplay() = default;
+ static std::unique_ptr<AbstractTreeDisplay> createFromDisplayMode(
+ int /*eSpaceOutliner_Mode*/ mode, SpaceOutliner &space_outliner);
+
/**
* Build a tree for this display mode with the Blender context data given in \a source_data and
* the view settings in \a space_outliner.
*/
virtual ListBase buildTree(const TreeSourceData &source_data) = 0;
+ /** Accessor to whether given tree has some warnings to display. */
+ bool hasWarnings() const;
+
protected:
+ bool has_warnings = false;
+
/** All derived classes will need a handle to this, so storing it in the base for convenience. */
SpaceOutliner &space_outliner_;
};
@@ -105,7 +132,7 @@ class TreeDisplayLibraries final : public AbstractTreeDisplay {
ListBase buildTree(const TreeSourceData &source_data) override;
private:
- TreeElement *add_library_contents(Main &, ListBase &, Library *) const;
+ TreeElement *add_library_contents(Main &, ListBase &, Library *);
bool library_id_filter_poll(const Library *lib, ID *id) const;
short id_filter_get() const;
};
@@ -123,7 +150,7 @@ class TreeDisplayOverrideLibrary final : public AbstractTreeDisplay {
ListBase buildTree(const TreeSourceData &source_data) override;
private:
- TreeElement *add_library_contents(Main &, ListBase &, Library *) const;
+ TreeElement *add_library_contents(Main &, ListBase &, Library *);
bool override_library_id_filter_poll(const Library *lib, ID *id) const;
short id_filter_get() const;
};
diff --git a/source/blender/editors/space_outliner/tree/tree_display_data.cc b/source/blender/editors/space_outliner/tree/tree_display_data.cc
index 8a5c2e7d9f3..5c88e88bd37 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_data.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_data.cc
@@ -21,10 +21,13 @@
#include "BLI_listbase.h"
#include "BLI_mempool.h"
+#include "DNA_space_types.h"
+
#include "RNA_access.h"
-#include "../outliner_intern.h"
+#include "../outliner_intern.hh"
#include "tree_display.hh"
+#include "tree_element.hh"
namespace blender::ed::outliner {
diff --git a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
index 836f0937cf4..1d77e82612d 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
@@ -25,11 +25,14 @@
#include "BKE_main.h"
#include "DNA_collection_types.h"
+#include "DNA_space_types.h"
#include "BLT_translation.h"
-#include "../outliner_intern.h"
+#include "../outliner_intern.hh"
+#include "common.hh"
#include "tree_display.hh"
+#include "tree_element.hh"
namespace blender::ed::outliner {
@@ -104,9 +107,7 @@ ListBase TreeDisplayLibraries::buildTree(const TreeSourceData &source_data)
return tree;
}
-TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar,
- ListBase &lb,
- Library *lib) const
+TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar, ListBase &lb, Library *lib)
{
const short filter_id_type = id_filter_get();
@@ -149,6 +150,9 @@ TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar,
tenlib = outliner_add_element(&space_outliner_, &lb, &mainvar, nullptr, TSE_ID_BASE, 0);
tenlib->name = IFACE_("Current File");
}
+ if (tenlib->flag & TE_HAS_WARNING) {
+ has_warnings = true;
+ }
}
/* Create data-block list parent element on demand. */
diff --git a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc
index eeb3ca6893a..587f807c40c 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc
@@ -19,6 +19,7 @@
*/
#include "DNA_ID.h"
+#include "DNA_space_types.h"
#include "BLI_listbase.h"
#include "BLI_listbase_wrapper.hh"
@@ -26,8 +27,10 @@
#include "BKE_main.h"
-#include "../outliner_intern.h"
+#include "../outliner_intern.hh"
+#include "common.hh"
#include "tree_display.hh"
+#include "tree_element.hh"
namespace blender::ed::outliner {
diff --git a/source/blender/editors/space_outliner/tree/tree_display_override_library.cc b/source/blender/editors/space_outliner/tree/tree_display_override_library.cc
index 943e182277c..d9a0661d3b4 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_override_library.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_override_library.cc
@@ -25,11 +25,14 @@
#include "BKE_main.h"
#include "DNA_collection_types.h"
+#include "DNA_space_types.h"
#include "BLT_translation.h"
-#include "../outliner_intern.h"
+#include "../outliner_intern.hh"
+#include "common.hh"
#include "tree_display.hh"
+#include "tree_element.hh"
namespace blender::ed::outliner {
@@ -112,7 +115,7 @@ ListBase TreeDisplayOverrideLibrary::buildTree(const TreeSourceData &source_data
TreeElement *TreeDisplayOverrideLibrary::add_library_contents(Main &mainvar,
ListBase &lb,
- Library *lib) const
+ Library *lib)
{
const short filter_id_type = id_filter_get();
@@ -152,6 +155,9 @@ TreeElement *TreeDisplayOverrideLibrary::add_library_contents(Main &mainvar,
tenlib = outliner_add_element(&space_outliner_, &lb, &mainvar, nullptr, TSE_ID_BASE, 0);
tenlib->name = IFACE_("Current File");
}
+ if (tenlib->flag & TE_HAS_WARNING) {
+ has_warnings = true;
+ }
}
/* Create data-block list parent element on demand. */
diff --git a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc
index 29442aace37..ad66e8a7ee5 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc
@@ -18,14 +18,18 @@
* \ingroup spoutliner
*/
+#include "DNA_space_types.h"
+
#include "BLI_listbase.h"
#include "BLI_listbase_wrapper.hh"
#include "BLI_mempool.h"
#include "BKE_main.h"
-#include "../outliner_intern.h"
+#include "../outliner_intern.hh"
+#include "common.hh"
#include "tree_display.hh"
+#include "tree_element.hh"
namespace blender::ed::outliner {
diff --git a/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc b/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc
index aa28b164584..7c5137a72dd 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc
@@ -24,10 +24,14 @@
#include "BLI_listbase_wrapper.hh"
#include "BLI_utildefines.h"
+#include "DNA_sequence_types.h"
+#include "DNA_space_types.h"
+
#include "SEQ_sequencer.h"
-#include "../outliner_intern.h"
+#include "../outliner_intern.hh"
#include "tree_display.hh"
+#include "tree_element.hh"
namespace blender::ed::outliner {
diff --git a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
index ebbc9baaa9f..73990b45562 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
@@ -22,6 +22,7 @@
#include "DNA_collection_types.h"
#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
#include "BKE_layer.h"
@@ -32,8 +33,10 @@
#include "BLT_translation.h"
-#include "../outliner_intern.h"
+#include "../outliner_intern.hh"
+#include "common.hh"
#include "tree_display.hh"
+#include "tree_element.hh"
namespace blender::ed::outliner {
diff --git a/source/blender/editors/space_outliner/tree/tree_element.cc b/source/blender/editors/space_outliner/tree/tree_element.cc
index 36da7fe1944..5685d8964f5 100644
--- a/source/blender/editors/space_outliner/tree/tree_element.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element.cc
@@ -20,6 +20,11 @@
#include "DNA_anim_types.h"
#include "DNA_listBase.h"
+#include "DNA_space_types.h"
+
+#include "UI_resources.h"
+
+#include "BLT_translation.h"
#include "tree_element_anim_data.hh"
#include "tree_element_collection.hh"
@@ -28,15 +33,19 @@
#include "tree_element_id.hh"
#include "tree_element_nla.hh"
#include "tree_element_overrides.hh"
+#include "tree_element_rna.hh"
#include "tree_element_scene_objects.hh"
+#include "tree_element_seq.hh"
#include "tree_element_view_layer.hh"
-#include "tree_element.h"
+#include "../outliner_intern.hh"
#include "tree_element.hh"
namespace blender::ed::outliner {
-static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te, void *idv)
+std::unique_ptr<AbstractTreeElement> AbstractTreeElement::createFromType(const int type,
+ TreeElement &legacy_te,
+ void *idv)
{
ID &id = *static_cast<ID *>(idv);
@@ -56,28 +65,46 @@ static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te
case TSE_SOME_ID:
return TreeElementID::createFromID(legacy_te, id);
case TSE_ANIM_DATA:
- return new TreeElementAnimData(legacy_te, *reinterpret_cast<IdAdtTemplate &>(id).adt);
+ return std::make_unique<TreeElementAnimData>(legacy_te,
+ *reinterpret_cast<IdAdtTemplate &>(id).adt);
case TSE_DRIVER_BASE:
- return new TreeElementDriverBase(legacy_te, *static_cast<AnimData *>(idv));
+ return std::make_unique<TreeElementDriverBase>(legacy_te, *static_cast<AnimData *>(idv));
case TSE_NLA:
- return new TreeElementNLA(legacy_te, *static_cast<AnimData *>(idv));
+ return std::make_unique<TreeElementNLA>(legacy_te, *static_cast<AnimData *>(idv));
case TSE_NLA_TRACK:
- return new TreeElementNLATrack(legacy_te, *static_cast<NlaTrack *>(idv));
+ return std::make_unique<TreeElementNLATrack>(legacy_te, *static_cast<NlaTrack *>(idv));
case TSE_NLA_ACTION:
- return new TreeElementNLAAction(legacy_te, *static_cast<bAction *>(idv));
+ return std::make_unique<TreeElementNLAAction>(legacy_te, *static_cast<bAction *>(idv));
case TSE_GP_LAYER:
- return new TreeElementGPencilLayer(legacy_te, *static_cast<bGPDlayer *>(idv));
+ return std::make_unique<TreeElementGPencilLayer>(legacy_te, *static_cast<bGPDlayer *>(idv));
case TSE_R_LAYER_BASE:
- return new TreeElementViewLayerBase(legacy_te, *static_cast<Scene *>(idv));
+ return std::make_unique<TreeElementViewLayerBase>(legacy_te, *static_cast<Scene *>(idv));
case TSE_SCENE_COLLECTION_BASE:
- return new TreeElementCollectionBase(legacy_te, *static_cast<Scene *>(idv));
+ return std::make_unique<TreeElementCollectionBase>(legacy_te, *static_cast<Scene *>(idv));
case TSE_SCENE_OBJECTS_BASE:
- return new TreeElementSceneObjectsBase(legacy_te, *static_cast<Scene *>(idv));
+ return std::make_unique<TreeElementSceneObjectsBase>(legacy_te, *static_cast<Scene *>(idv));
case TSE_LIBRARY_OVERRIDE_BASE:
- return new TreeElementOverridesBase(legacy_te, id);
+ return std::make_unique<TreeElementOverridesBase>(legacy_te, id);
case TSE_LIBRARY_OVERRIDE:
- return new TreeElementOverridesProperty(legacy_te,
- *static_cast<TreeElementOverridesData *>(idv));
+ return std::make_unique<TreeElementOverridesProperty>(
+ legacy_te, *static_cast<TreeElementOverridesData *>(idv));
+ case TSE_RNA_STRUCT:
+ return std::make_unique<TreeElementRNAStruct>(legacy_te,
+ *reinterpret_cast<PointerRNA *>(idv));
+ case TSE_RNA_PROPERTY:
+ return std::make_unique<TreeElementRNAProperty>(
+ legacy_te, *reinterpret_cast<PointerRNA *>(idv), legacy_te.index);
+ case TSE_RNA_ARRAY_ELEM:
+ return std::make_unique<TreeElementRNAArrayElement>(
+ legacy_te, *reinterpret_cast<PointerRNA *>(idv), legacy_te.index);
+ case TSE_SEQUENCE:
+ return std::make_unique<TreeElementSequence>(legacy_te, *reinterpret_cast<Sequence *>(idv));
+ case TSE_SEQ_STRIP:
+ return std::make_unique<TreeElementSequenceStrip>(legacy_te,
+ *reinterpret_cast<Strip *>(idv));
+ case TSE_SEQUENCE_DUP:
+ return std::make_unique<TreeElementSequenceStripDuplicate>(
+ legacy_te, *reinterpret_cast<Sequence *>(idv));
default:
break;
}
@@ -85,14 +112,7 @@ static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te
return nullptr;
}
-static void tree_element_free(AbstractTreeElement **tree_element)
-{
- delete *tree_element;
- *tree_element = nullptr;
-}
-
-static void tree_element_expand(const AbstractTreeElement &tree_element,
- SpaceOutliner &space_outliner)
+void tree_element_expand(const AbstractTreeElement &tree_element, SpaceOutliner &space_outliner)
{
/* Most types can just expand. IDs optionally expand (hence the poll) and do additional, common
* expanding. Could be done nicer, we could request a small "expander" helper object from the
@@ -104,58 +124,39 @@ static void tree_element_expand(const AbstractTreeElement &tree_element,
tree_element.postExpand(space_outliner);
}
-/**
- * Needed for types that still expand in C, but need to execute the same post-expand logic. Can be
- * removed once all ID types expand entirely using the new design.
- */
-static void tree_element_post_expand_only(const AbstractTreeElement &tree_element,
- SpaceOutliner &space_outliner)
+bool tree_element_warnings_get(TreeElement *te, int *r_icon, const char **r_message)
{
- tree_element.postExpand(space_outliner);
-}
-/**
- * Needed for types that still expand in C, to poll if they should expand in current context. Can
- * be removed once all ID types expand entirely using the new design.
- */
-static bool tree_element_expand_poll(const AbstractTreeElement &tree_element,
- const SpaceOutliner &space_outliner)
-{
- return tree_element.expandPoll(space_outliner);
-}
+ TreeStoreElem *tselem = te->store_elem;
-} // namespace blender::ed::outliner
-
-namespace outliner = blender::ed::outliner;
-
-TreeElementType *outliner_tree_element_type_create(int type, TreeElement *legacy_te, void *idv)
-{
- outliner::AbstractTreeElement *element = outliner::tree_element_create(type, *legacy_te, idv);
- return reinterpret_cast<TreeElementType *>(element);
-}
+ if (tselem->type != TSE_SOME_ID) {
+ return false;
+ }
+ if (te->idcode != ID_LI) {
+ return false;
+ }
-void outliner_tree_element_type_expand(TreeElementType *type, SpaceOutliner *space_outliner)
-{
- outliner::tree_element_expand(reinterpret_cast<outliner::AbstractTreeElement &>(*type),
- *space_outliner);
-}
-bool outliner_tree_element_type_is_expand_valid(TreeElementType *type)
-{
- outliner::AbstractTreeElement &element = reinterpret_cast<outliner::AbstractTreeElement &>(
- *type);
- return element.isExpandValid();
-}
-bool outliner_tree_element_type_expand_poll(TreeElementType *type, SpaceOutliner *space_outliner)
-{
- return outliner::tree_element_expand_poll(
- reinterpret_cast<outliner::AbstractTreeElement &>(*type), *space_outliner);
-}
-void outliner_tree_element_type_post_expand(TreeElementType *type, SpaceOutliner *space_outliner)
-{
- outliner::tree_element_post_expand_only(reinterpret_cast<outliner::AbstractTreeElement &>(*type),
- *space_outliner);
+ Library *library = (Library *)tselem->id;
+ if (library->tag & LIBRARY_TAG_RESYNC_REQUIRED) {
+ if (r_icon) {
+ *r_icon = ICON_ERROR;
+ }
+ if (r_message) {
+ *r_message = TIP_(
+ "Contains linked library overrides that need to be resynced, updating the library is "
+ "recommended");
+ }
+ return true;
+ }
+ if (library->id.tag & LIB_TAG_MISSING) {
+ if (r_icon) {
+ *r_icon = ICON_ERROR;
+ }
+ if (r_message) {
+ *r_message = TIP_("Missing library");
+ }
+ return true;
+ }
+ return false;
}
-void outliner_tree_element_type_free(TreeElementType **type)
-{
- outliner::tree_element_free(reinterpret_cast<outliner::AbstractTreeElement **>(type));
-}
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element.h b/source/blender/editors/space_outliner/tree/tree_element.h
deleted file mode 100644
index 8e5b02278cc..00000000000
--- a/source/blender/editors/space_outliner/tree/tree_element.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/** \file
- * \ingroup spoutliner
- *
- * C-API for the Tree-Element types.
- * This API shouldn't stay for long. All tree building should eventually be done through C++ types,
- * with more type safety and an easier to reason about design.
- */
-
-#pragma once
-
-#include "DNA_space_types.h"
-
-struct TreeElement;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** C alias for an #AbstractTreeElement handle. */
-typedef struct TreeElementType TreeElementType;
-
-TreeElementType *outliner_tree_element_type_create(int type, TreeElement *legacy_te, void *idv);
-void outliner_tree_element_type_free(TreeElementType **type);
-
-void outliner_tree_element_type_expand(TreeElementType *type, SpaceOutliner *space_outliner);
-bool outliner_tree_element_type_is_expand_valid(TreeElementType *type);
-bool outliner_tree_element_type_expand_poll(TreeElementType *type, SpaceOutliner *space_outliner);
-void outliner_tree_element_type_post_expand(TreeElementType *type, SpaceOutliner *space_outliner);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/source/blender/editors/space_outliner/tree/tree_element.hh b/source/blender/editors/space_outliner/tree/tree_element.hh
index 09bd0eec05d..aca5738b91a 100644
--- a/source/blender/editors/space_outliner/tree/tree_element.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element.hh
@@ -20,7 +20,11 @@
#pragma once
-#include "tree_element.h"
+#include <memory>
+
+struct ListBase;
+struct SpaceOutliner;
+struct TreeElement;
namespace blender::ed::outliner {
@@ -39,6 +43,10 @@ class AbstractTreeElement {
public:
virtual ~AbstractTreeElement() = default;
+ static std::unique_ptr<AbstractTreeElement> createFromType(int type,
+ TreeElement &legacy_te,
+ void *idv);
+
/**
* Check if the type is expandable in current context.
*/
@@ -46,12 +54,6 @@ class AbstractTreeElement {
{
return true;
}
- /**
- * Let the type add its own children.
- */
- virtual void expand(SpaceOutliner &) const
- {
- }
virtual void postExpand(SpaceOutliner &) const
{
}
@@ -65,11 +67,46 @@ class AbstractTreeElement {
return true;
}
+ friend void tree_element_expand(const AbstractTreeElement &tree_element,
+ SpaceOutliner &space_outliner);
+
protected:
/* Pseudo-abstract: Only allow creation through derived types. */
AbstractTreeElement(TreeElement &legacy_te) : legacy_te_(legacy_te)
{
}
+
+ /**
+ * Let the type add its own children.
+ */
+ virtual void expand(SpaceOutliner &) const
+ {
+ }
};
+/**
+ * TODO: this function needs to be split up! It's getting a bit too large...
+ *
+ * \note "ID" is not always a real ID.
+ * \note If child items are only added to the tree if the item is open,
+ * the `TSE_` type _must_ be added to #outliner_element_needs_rebuild_on_open_change().
+ */
+struct TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
+ ListBase *lb,
+ void *idv,
+ struct TreeElement *parent,
+ short type,
+ short index);
+
+void tree_element_expand(const AbstractTreeElement &tree_element, SpaceOutliner &space_outliner);
+
+/**
+ * Get actual warning data of a tree element, if any.
+ *
+ * \param r_icon The icon to display as warning.
+ * \param r_message The message to display as warning.
+ * \return true if there is a warning, false otherwise.
+ */
+bool tree_element_warnings_get(struct TreeElement *te, int *r_icon, const char **r_message);
+
} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc b/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc
index c0fef7c98e2..41212f61d5d 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc
@@ -22,11 +22,11 @@
#include "DNA_anim_types.h"
#include "DNA_listBase.h"
+#include "DNA_outliner_types.h"
#include "BLT_translation.h"
-#include "../outliner_intern.h"
-#include "tree_display.h"
+#include "../outliner_intern.hh"
#include "tree_element_anim_data.hh"
diff --git a/source/blender/editors/space_outliner/tree/tree_element_collection.cc b/source/blender/editors/space_outliner/tree/tree_element_collection.cc
index 1add61db7f1..0a7ee21df15 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_collection.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_collection.cc
@@ -19,11 +19,12 @@
*/
#include "DNA_listBase.h"
+#include "DNA_outliner_types.h"
+#include "DNA_scene_types.h"
#include "BLT_translation.h"
-#include "../outliner_intern.h"
-#include "tree_display.h"
+#include "../outliner_intern.hh"
#include "tree_element_collection.hh"
diff --git a/source/blender/editors/space_outliner/tree/tree_element_driver.cc b/source/blender/editors/space_outliner/tree/tree_element_driver.cc
index 42f51908eaa..49d7f91b557 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_driver.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_driver.cc
@@ -24,11 +24,11 @@
#include "DNA_anim_types.h"
#include "DNA_listBase.h"
+#include "DNA_space_types.h"
#include "BLT_translation.h"
-#include "../outliner_intern.h"
-#include "tree_display.h"
+#include "../outliner_intern.hh"
#include "tree_element_driver.hh"
diff --git a/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc
index 91e6fdcde4b..ead83ad6931 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc
@@ -21,8 +21,9 @@
#include "BLI_utildefines.h"
#include "DNA_gpencil_types.h"
+#include "DNA_space_types.h"
-#include "../outliner_intern.h"
+#include "../outliner_intern.hh"
#include "tree_element_gpencil_layer.hh"
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.cc b/source/blender/editors/space_outliner/tree/tree_element_id.cc
index 7ff5a3285f1..afbbd171cf4 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_id.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_id.cc
@@ -19,6 +19,7 @@
*/
#include "DNA_ID.h"
+#include "DNA_space_types.h"
#include "BLI_listbase_wrapper.hh"
#include "BLI_utildefines.h"
@@ -29,8 +30,8 @@
#include "RNA_access.h"
-#include "../outliner_intern.h"
-#include "tree_display.h"
+#include "../outliner_intern.hh"
+#include "common.hh"
#include "tree_element_id_library.hh"
#include "tree_element_id_scene.hh"
@@ -38,13 +39,13 @@
namespace blender::ed::outliner {
-TreeElementID *TreeElementID::createFromID(TreeElement &legacy_te, ID &id)
+std::unique_ptr<TreeElementID> TreeElementID::createFromID(TreeElement &legacy_te, ID &id)
{
switch (ID_Type type = GS(id.name); type) {
case ID_LI:
- return new TreeElementIDLibrary(legacy_te, (Library &)id);
+ return std::make_unique<TreeElementIDLibrary>(legacy_te, (Library &)id);
case ID_SCE:
- return new TreeElementIDScene(legacy_te, (Scene &)id);
+ return std::make_unique<TreeElementIDScene>(legacy_te, (Scene &)id);
case ID_OB:
case ID_ME:
case ID_CU:
@@ -82,7 +83,7 @@ TreeElementID *TreeElementID::createFromID(TreeElement &legacy_te, ID &id)
case ID_PAL:
case ID_PC:
case ID_CF:
- return new TreeElementID(legacy_te, id);
+ return std::make_unique<TreeElementID>(legacy_te, id);
/* Deprecated */
case ID_IP:
BLI_assert_msg(0, "Outliner trying to build tree-element for deprecated ID type");
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.hh b/source/blender/editors/space_outliner/tree/tree_element_id.hh
index b3b5ca2770c..9b5b955be0b 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_id.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element_id.hh
@@ -24,6 +24,9 @@
#include "tree_element.hh"
+struct AnimData;
+struct ID;
+
namespace blender::ed::outliner {
class TreeElementID : public AbstractTreeElement {
@@ -33,7 +36,7 @@ class TreeElementID : public AbstractTreeElement {
public:
TreeElementID(TreeElement &legacy_te, ID &id);
- static TreeElementID *createFromID(TreeElement &legacy_te, ID &id);
+ static std::unique_ptr<TreeElementID> createFromID(TreeElement &legacy_te, ID &id);
void postExpand(SpaceOutliner &) const override;
bool expandPoll(const SpaceOutliner &) const override;
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_library.cc b/source/blender/editors/space_outliner/tree/tree_element_id_library.cc
index 36f536c9845..b5fd67d4807 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_id_library.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_id_library.cc
@@ -18,9 +18,10 @@
* \ingroup spoutliner
*/
+#include "DNA_ID.h"
#include "DNA_listBase.h"
-#include "../outliner_intern.h"
+#include "../outliner_intern.hh"
#include "tree_element_id_library.hh"
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_library.hh b/source/blender/editors/space_outliner/tree/tree_element_id_library.hh
index 88660cd8aa9..ce128b1a5ff 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_id_library.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element_id_library.hh
@@ -22,6 +22,8 @@
#include "tree_element_id.hh"
+struct Library;
+
namespace blender::ed::outliner {
class TreeElementIDLibrary final : public TreeElementID {
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc b/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc
index ae81b44a1e4..c71d6786c6e 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc
@@ -19,9 +19,10 @@
*/
#include "DNA_listBase.h"
+#include "DNA_outliner_types.h"
+#include "DNA_scene_types.h"
-#include "../outliner_intern.h"
-#include "tree_display.h"
+#include "../outliner_intern.hh"
#include "tree_element_id_scene.hh"
diff --git a/source/blender/editors/space_outliner/tree/tree_element_nla.cc b/source/blender/editors/space_outliner/tree/tree_element_nla.cc
index 65832e8f981..89ebee49192 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_nla.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_nla.cc
@@ -22,11 +22,11 @@
#include "DNA_anim_types.h"
#include "DNA_listBase.h"
+#include "DNA_space_types.h"
#include "BLT_translation.h"
-#include "../outliner_intern.h"
-#include "tree_display.h"
+#include "../outliner_intern.hh"
#include "tree_element_nla.hh"
diff --git a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
index 731beb3956e..ba1471625b9 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
@@ -27,10 +27,11 @@
#include "BLT_translation.h"
+#include "DNA_space_types.h"
+
#include "RNA_access.h"
-#include "../outliner_intern.h"
-#include "tree_display.h"
+#include "../outliner_intern.hh"
#include "tree_element_overrides.hh"
diff --git a/source/blender/editors/space_outliner/tree/tree_element_rna.cc b/source/blender/editors/space_outliner/tree/tree_element_rna.cc
new file mode 100644
index 00000000000..7a9f1b6f0fa
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_rna.cc
@@ -0,0 +1,268 @@
+/*
+ * 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 spoutliner
+ */
+
+#include <climits>
+#include <iostream>
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_outliner_types.h"
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+
+#include "../outliner_intern.hh"
+
+#include "tree_element_rna.hh"
+
+namespace blender::ed::outliner {
+
+/* Don't display arrays larger, weak but index is stored as a short,
+ * also the outliner isn't intended for editing such large data-sets. */
+BLI_STATIC_ASSERT(sizeof(TreeElement::index) == 2, "Index is no longer short!")
+
+/* -------------------------------------------------------------------- */
+/* Common functionality (#TreeElementRNACommon Base Class) */
+
+TreeElementRNACommon::TreeElementRNACommon(TreeElement &legacy_te, PointerRNA &rna_ptr)
+ : AbstractTreeElement(legacy_te), rna_ptr_(rna_ptr)
+{
+ /* Create an empty tree-element. */
+ if (!isRNAValid()) {
+ legacy_te_.name = IFACE_("(empty)");
+ return;
+ }
+}
+
+bool TreeElementRNACommon::isExpandValid() const
+{
+ return true;
+}
+
+bool TreeElementRNACommon::isRNAValid() const
+{
+ return rna_ptr_.data != nullptr;
+}
+
+bool TreeElementRNACommon::expandPoll(const SpaceOutliner &) const
+{
+ return isRNAValid();
+}
+
+const PointerRNA &TreeElementRNACommon::getPointerRNA() const
+{
+ return rna_ptr_;
+}
+
+PropertyRNA *TreeElementRNACommon::getPropertyRNA() const
+{
+ return nullptr;
+}
+
+/* -------------------------------------------------------------------- */
+/* RNA Struct */
+
+TreeElementRNAStruct::TreeElementRNAStruct(TreeElement &legacy_te, PointerRNA &rna_ptr)
+ : TreeElementRNACommon(legacy_te, rna_ptr)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_RNA_STRUCT);
+
+ if (!isRNAValid()) {
+ return;
+ }
+
+ legacy_te_.name = RNA_struct_name_get_alloc(&rna_ptr, nullptr, 0, nullptr);
+ if (legacy_te_.name) {
+ legacy_te_.flag |= TE_FREE_NAME;
+ }
+ else {
+ legacy_te_.name = RNA_struct_ui_name(rna_ptr.type);
+ }
+}
+
+void TreeElementRNAStruct::expand(SpaceOutliner &space_outliner) const
+{
+ TreeStoreElem &tselem = *TREESTORE(&legacy_te_);
+ PointerRNA ptr = rna_ptr_;
+
+ /* If searching don't expand RNA entries */
+ if (SEARCHING_OUTLINER(&space_outliner) && BLI_strcasecmp("RNA", legacy_te_.name) == 0) {
+ tselem.flag &= ~TSE_CHILDSEARCH;
+ }
+
+ PropertyRNA *iterprop = RNA_struct_iterator_property(ptr.type);
+ int tot = RNA_property_collection_length(&ptr, iterprop);
+ CLAMP_MAX(tot, max_index);
+
+ TreeElementRNAProperty *parent_prop_te = legacy_te_.parent ?
+ tree_element_cast<TreeElementRNAProperty>(
+ legacy_te_.parent) :
+ nullptr;
+ /* auto open these cases */
+ if (!parent_prop_te || (RNA_property_type(parent_prop_te->getPropertyRNA()) == PROP_POINTER)) {
+ if (!tselem.used) {
+ tselem.flag &= ~TSE_CLOSED;
+ }
+ }
+
+ if (TSELEM_OPEN(&tselem, &space_outliner)) {
+ for (int index = 0; index < tot; index++) {
+ PointerRNA propptr;
+ RNA_property_collection_lookup_int(&ptr, iterprop, index, &propptr);
+ if (!(RNA_property_flag(reinterpret_cast<PropertyRNA *>(propptr.data)) & PROP_HIDDEN)) {
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, &ptr, &legacy_te_, TSE_RNA_PROPERTY, index);
+ }
+ }
+ }
+ else if (tot) {
+ legacy_te_.flag |= TE_LAZY_CLOSED;
+ }
+}
+
+/* -------------------------------------------------------------------- */
+/* RNA Property */
+
+TreeElementRNAProperty::TreeElementRNAProperty(TreeElement &legacy_te,
+ PointerRNA &rna_ptr,
+ const int index)
+ : TreeElementRNACommon(legacy_te, rna_ptr)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_RNA_PROPERTY);
+
+ if (!isRNAValid()) {
+ return;
+ }
+
+ PointerRNA propptr;
+ PropertyRNA *iterprop = RNA_struct_iterator_property(rna_ptr.type);
+ RNA_property_collection_lookup_int(&rna_ptr, iterprop, index, &propptr);
+
+ PropertyRNA *prop = reinterpret_cast<PropertyRNA *>(propptr.data);
+
+ legacy_te_.name = RNA_property_ui_name(prop);
+ rna_prop_ = prop;
+}
+
+void TreeElementRNAProperty::expand(SpaceOutliner &space_outliner) const
+{
+ TreeStoreElem &tselem = *TREESTORE(&legacy_te_);
+ PointerRNA rna_ptr = rna_ptr_;
+ PropertyType proptype = RNA_property_type(rna_prop_);
+
+ /* If searching don't expand RNA entries */
+ if (SEARCHING_OUTLINER(&space_outliner) && BLI_strcasecmp("RNA", legacy_te_.name) == 0) {
+ tselem.flag &= ~TSE_CHILDSEARCH;
+ }
+
+ if (proptype == PROP_POINTER) {
+ PointerRNA pptr = RNA_property_pointer_get(&rna_ptr, rna_prop_);
+
+ if (pptr.data) {
+ if (TSELEM_OPEN(&tselem, &space_outliner)) {
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, &pptr, &legacy_te_, TSE_RNA_STRUCT, -1);
+ }
+ else {
+ legacy_te_.flag |= TE_LAZY_CLOSED;
+ }
+ }
+ }
+ else if (proptype == PROP_COLLECTION) {
+ int tot = RNA_property_collection_length(&rna_ptr, rna_prop_);
+ CLAMP_MAX(tot, max_index);
+
+ if (TSELEM_OPEN(&tselem, &space_outliner)) {
+ for (int index = 0; index < tot; index++) {
+ PointerRNA pptr;
+ RNA_property_collection_lookup_int(&rna_ptr, rna_prop_, index, &pptr);
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, &pptr, &legacy_te_, TSE_RNA_STRUCT, index);
+ }
+ }
+ else if (tot) {
+ legacy_te_.flag |= TE_LAZY_CLOSED;
+ }
+ }
+ else if (ELEM(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
+ int tot = RNA_property_array_length(&rna_ptr, rna_prop_);
+ CLAMP_MAX(tot, max_index);
+
+ if (TSELEM_OPEN(&tselem, &space_outliner)) {
+ for (int index = 0; index < tot; index++) {
+ outliner_add_element(&space_outliner,
+ &legacy_te_.subtree,
+ &rna_ptr,
+ &legacy_te_,
+ TSE_RNA_ARRAY_ELEM,
+ index);
+ }
+ }
+ else if (tot) {
+ legacy_te_.flag |= TE_LAZY_CLOSED;
+ }
+ }
+}
+
+PropertyRNA *TreeElementRNAProperty::getPropertyRNA() const
+{
+ return rna_prop_;
+}
+
+/* -------------------------------------------------------------------- */
+/* RNA Array Element */
+
+TreeElementRNAArrayElement::TreeElementRNAArrayElement(TreeElement &legacy_te,
+ PointerRNA &rna_ptr,
+ const int index)
+ : TreeElementRNACommon(legacy_te, rna_ptr)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_RNA_ARRAY_ELEM);
+
+ BLI_assert(legacy_te.parent && (legacy_te.parent->store_elem->type == TSE_RNA_PROPERTY));
+ legacy_te_.index = index;
+
+ char c = RNA_property_array_item_char(TreeElementRNAArrayElement::getPropertyRNA(), index);
+
+ legacy_te_.name = reinterpret_cast<char *>(
+ MEM_callocN(sizeof(char[20]), "OutlinerRNAArrayName"));
+ if (c) {
+ sprintf((char *)legacy_te_.name, " %c", c);
+ }
+ else {
+ sprintf((char *)legacy_te_.name, " %d", index + 1);
+ }
+ legacy_te_.flag |= TE_FREE_NAME;
+}
+
+PropertyRNA *TreeElementRNAArrayElement::getPropertyRNA() const
+{
+ /* Forward query to the parent (which is expected to be a #TreeElementRNAProperty). */
+ const TreeElementRNAProperty *parent_prop_te = tree_element_cast<TreeElementRNAProperty>(
+ legacy_te_.parent);
+ return parent_prop_te ? parent_prop_te->getPropertyRNA() : nullptr;
+}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_rna.hh b/source/blender/editors/space_outliner/tree/tree_element_rna.hh
new file mode 100644
index 00000000000..1f107ddbf88
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_rna.hh
@@ -0,0 +1,86 @@
+/*
+ * 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 spoutliner
+ */
+
+#pragma once
+
+#include <limits>
+
+#include "RNA_types.h"
+
+#include "tree_element.hh"
+
+struct PointerRNA;
+
+namespace blender::ed::outliner {
+
+/**
+ * Base class for common behavior of RNA tree elements.
+ */
+class TreeElementRNACommon : public AbstractTreeElement {
+ protected:
+ constexpr static int max_index = std::numeric_limits<short>::max();
+ PointerRNA rna_ptr_;
+
+ public:
+ TreeElementRNACommon(TreeElement &legacy_te, PointerRNA &rna_ptr);
+ bool isExpandValid() const override;
+ bool expandPoll(const SpaceOutliner &) const override;
+
+ const PointerRNA &getPointerRNA() const;
+ /**
+ * If this element represents a property or is part of a property (array element), this returns
+ * the property. Otherwise nullptr.
+ */
+ virtual PropertyRNA *getPropertyRNA() const;
+
+ bool isRNAValid() const;
+};
+
+/* -------------------------------------------------------------------- */
+
+class TreeElementRNAStruct : public TreeElementRNACommon {
+ public:
+ TreeElementRNAStruct(TreeElement &legacy_te, PointerRNA &rna_ptr);
+ void expand(SpaceOutliner &space_outliner) const override;
+};
+
+/* -------------------------------------------------------------------- */
+
+class TreeElementRNAProperty : public TreeElementRNACommon {
+ private:
+ PropertyRNA *rna_prop_ = nullptr;
+
+ public:
+ TreeElementRNAProperty(TreeElement &legacy_te, PointerRNA &rna_ptr, int index);
+ void expand(SpaceOutliner &space_outliner) const override;
+
+ PropertyRNA *getPropertyRNA() const override;
+};
+
+/* -------------------------------------------------------------------- */
+
+class TreeElementRNAArrayElement : public TreeElementRNACommon {
+ public:
+ TreeElementRNAArrayElement(TreeElement &legacy_te, PointerRNA &rna_ptr, int index);
+
+ PropertyRNA *getPropertyRNA() const override;
+};
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc
index a46e8de1bdd..dad03d392fb 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc
@@ -24,8 +24,10 @@
#include "BLT_translation.h"
-#include "../outliner_intern.h"
-#include "tree_display.h"
+#include "DNA_outliner_types.h"
+
+#include "../outliner_intern.hh"
+#include "common.hh"
#include "tree_element_scene_objects.hh"
diff --git a/source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh
index a2aa29c4a33..7ce5a404f5c 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh
@@ -22,6 +22,8 @@
#include "tree_element.hh"
+struct Scene;
+
namespace blender::ed::outliner {
class TreeElementSceneObjectsBase final : public AbstractTreeElement {
diff --git a/source/blender/editors/space_outliner/tree/tree_element_seq.cc b/source/blender/editors/space_outliner/tree/tree_element_seq.cc
new file mode 100644
index 00000000000..8d0b4c140c7
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_seq.cc
@@ -0,0 +1,111 @@
+/*
+ * 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 spoutliner
+ */
+
+#include "DNA_outliner_types.h"
+#include "DNA_sequence_types.h"
+
+#include "BLI_listbase.h"
+
+#include "BLT_translation.h"
+
+#include "../outliner_intern.hh"
+#include "tree_element_seq.hh"
+
+namespace blender::ed::outliner {
+
+TreeElementSequence::TreeElementSequence(TreeElement &legacy_te, Sequence &sequence)
+ : AbstractTreeElement(legacy_te), sequence_(sequence)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_SEQUENCE);
+
+ /*
+ * The idcode is a little hack, but the outliner
+ * only check te->idcode if te->type is equal to zero,
+ * so this is "safe".
+ */
+ legacy_te.idcode = sequence_.type;
+ legacy_te.name = sequence_.name + 2;
+}
+
+bool TreeElementSequence::expandPoll(const SpaceOutliner & /*space_outliner*/) const
+{
+ return !(sequence_.type & SEQ_TYPE_EFFECT);
+}
+
+void TreeElementSequence::expand(SpaceOutliner &space_outliner) const
+{
+ /*
+ * This work like the sequence.
+ * If the sequence have a name (not default name)
+ * show it, in other case put the filename.
+ */
+
+ if (sequence_.type == SEQ_TYPE_META) {
+ LISTBASE_FOREACH (Sequence *, child, &sequence_.seqbase) {
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, child, &legacy_te_, TSE_SEQUENCE, 0);
+ }
+ }
+ else {
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, sequence_.strip, &legacy_te_, TSE_SEQ_STRIP, 0);
+ }
+}
+
+Sequence &TreeElementSequence::getSequence() const
+{
+ return sequence_;
+}
+
+/* -------------------------------------------------------------------- */
+/* Strip */
+
+TreeElementSequenceStrip::TreeElementSequenceStrip(TreeElement &legacy_te, Strip &strip)
+ : AbstractTreeElement(legacy_te)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_SEQ_STRIP);
+
+ if (strip.dir[0] != '\0') {
+ legacy_te_.name = strip.dir;
+ }
+ else {
+ legacy_te_.name = IFACE_("Strip None");
+ }
+}
+
+/* -------------------------------------------------------------------- */
+/* Strip Duplicate */
+
+TreeElementSequenceStripDuplicate::TreeElementSequenceStripDuplicate(TreeElement &legacy_te,
+ Sequence &sequence)
+ : AbstractTreeElement(legacy_te), sequence_(sequence)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_SEQUENCE_DUP);
+
+ legacy_te_.idcode = sequence.type;
+ legacy_te_.name = sequence.strip->stripdata->name;
+}
+
+Sequence &TreeElementSequenceStripDuplicate::getSequence() const
+{
+ return sequence_;
+}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_seq.hh b/source/blender/editors/space_outliner/tree/tree_element_seq.hh
new file mode 100644
index 00000000000..2b334b5b7fa
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_seq.hh
@@ -0,0 +1,60 @@
+/*
+ * 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 spoutliner
+ */
+
+#pragma once
+
+#include "tree_element.hh"
+
+struct Sequence;
+struct Strip;
+
+namespace blender::ed::outliner {
+
+class TreeElementSequence : public AbstractTreeElement {
+ Sequence &sequence_;
+
+ public:
+ TreeElementSequence(TreeElement &legacy_te, Sequence &sequence);
+
+ bool expandPoll(const SpaceOutliner &) const override;
+ void expand(SpaceOutliner &) const override;
+
+ Sequence &getSequence() const;
+};
+
+/* -------------------------------------------------------------------- */
+
+class TreeElementSequenceStrip : public AbstractTreeElement {
+ public:
+ TreeElementSequenceStrip(TreeElement &legacy_te, Strip &strip);
+};
+
+/* -------------------------------------------------------------------- */
+
+class TreeElementSequenceStripDuplicate : public AbstractTreeElement {
+ Sequence &sequence_;
+
+ public:
+ TreeElementSequenceStripDuplicate(TreeElement &legacy_te, Sequence &sequence);
+
+ Sequence &getSequence() const;
+};
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc
index 7bb9405147e..65786ac89ed 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc
@@ -19,13 +19,14 @@
*/
#include "DNA_layer_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
#include "BLI_listbase_wrapper.hh"
#include "BLT_translation.h"
-#include "../outliner_intern.h"
-#include "tree_display.h"
+#include "../outliner_intern.hh"
#include "tree_element_view_layer.hh"
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 616953e720a..72c39839739 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -59,6 +59,7 @@
#include "SEQ_add.h"
#include "SEQ_effects.h"
+#include "SEQ_iterator.h"
#include "SEQ_proxy.h"
#include "SEQ_relations.h"
#include "SEQ_render.h"
@@ -601,35 +602,48 @@ static IMB_Proxy_Size seq_get_proxy_size_flags(bContext *C)
return proxy_sizes;
}
-static void seq_build_proxy(bContext *C, Sequence *seq)
+static void seq_build_proxy(bContext *C, SeqCollection *movie_strips)
{
if (U.sequencer_proxy_setup != USER_SEQ_PROXY_SETUP_AUTOMATIC) {
return;
}
- /* Enable and set proxy size. */
- SEQ_proxy_set(seq, true);
- seq->strip->proxy->build_size_flags = seq_get_proxy_size_flags(C);
- seq->strip->proxy->build_flags |= SEQ_PROXY_SKIP_EXISTING;
-
- /* Build proxy. */
- GSet *file_list = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "file list");
wmJob *wm_job = ED_seq_proxy_wm_job_get(C);
ProxyJob *pj = ED_seq_proxy_job_get(C, wm_job);
- SEQ_proxy_rebuild_context(pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue);
- BLI_gset_free(file_list, MEM_freeN);
+
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, movie_strips) {
+ /* Enable and set proxy size. */
+ SEQ_proxy_set(seq, true);
+ seq->strip->proxy->build_size_flags = seq_get_proxy_size_flags(C);
+ seq->strip->proxy->build_flags |= SEQ_PROXY_SKIP_EXISTING;
+ SEQ_proxy_rebuild_context(pj->main, pj->depsgraph, pj->scene, seq, NULL, &pj->queue, true);
+ }
if (!WM_jobs_is_running(wm_job)) {
G.is_break = false;
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
-
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)
+ SeqLoadData *load_data,
+ SeqCollection *r_movie_strips)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
@@ -689,15 +703,19 @@ 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);
+ SEQ_collection_append_strip(seq_movie, r_movie_strips);
}
}
RNA_END;
}
-static bool sequencer_add_movie_single_strip(bContext *C, wmOperator *op, SeqLoadData *load_data)
+static bool sequencer_add_movie_single_strip(bContext *C,
+ wmOperator *op,
+ SeqLoadData *load_data,
+ SeqCollection *r_movie_strips)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
@@ -740,9 +758,10 @@ 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);
+ SEQ_collection_append_strip(seq_movie, r_movie_strips);
return true;
}
@@ -759,21 +778,25 @@ static int sequencer_add_movie_strip_exec(bContext *C, wmOperator *op)
ED_sequencer_deselect_all(scene);
}
+ SeqCollection *movie_strips = SEQ_collection_create(__func__);
const int tot_files = RNA_property_collection_length(op->ptr,
RNA_struct_find_property(op->ptr, "files"));
if (tot_files > 1) {
- sequencer_add_movie_multiple_strips(C, op, &load_data);
+ sequencer_add_movie_multiple_strips(C, op, &load_data, movie_strips);
}
else {
- if (!sequencer_add_movie_single_strip(C, op, &load_data)) {
- sequencer_add_cancel(C, op);
- return OPERATOR_CANCELLED;
- }
+ sequencer_add_movie_single_strip(C, op, &load_data, movie_strips);
+ }
+
+ if (SEQ_collection_len(movie_strips) == 0) {
+ SEQ_collection_free(movie_strips);
+ return OPERATOR_CANCELLED;
}
/* Free custom data. */
sequencer_add_cancel(C, op);
+ seq_build_proxy(C, movie_strips);
DEG_relations_tag_update(bmain);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index e814530d1e2..6dffc0bc2a4 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -2262,28 +2262,15 @@ void sequencer_draw_preview(const bContext *C,
seq_prefetch_wm_notify(C, scene);
}
-/* Draw backdrop in sequencer timeline. */
-static void draw_seq_backdrop(View2D *v2d)
+static void draw_seq_timeline_channels(View2D *v2d)
{
- int i;
-
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
-
- /* View backdrop. */
- immUniformThemeColor(TH_BACK);
- immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
-
- /* Darker overlay over the view backdrop. */
- immUniformThemeColorShade(TH_BACK, -10);
- immRectf(pos, v2d->cur.xmin, -1.0, v2d->cur.xmax, 1.0);
-
- /* Alternating horizontal stripes. */
- i = max_ii(1, ((int)v2d->cur.ymin) - 1);
-
GPU_blend(GPU_BLEND_ALPHA);
immUniformThemeColor(TH_ROW_ALTERNATE);
+ /* Alternating horizontal stripes. */
+ int i = max_ii(1, ((int)v2d->cur.ymin) - 1);
while (i < v2d->cur.ymax) {
if (i & 1) {
immRectf(pos, v2d->cur.xmin, i, v2d->cur.xmax, i + 1);
@@ -2295,6 +2282,14 @@ static void draw_seq_backdrop(View2D *v2d)
immUnbindProgram();
}
+static void draw_seq_timeline_channel_numbers(ARegion *region)
+{
+ View2D *v2d = &region->v2d;
+ rcti rect;
+ BLI_rcti_init(&rect, 0, 15 * UI_DPI_FAC, 15 * UI_DPI_FAC, region->winy - UI_TIME_SCRUB_MARGIN_Y);
+ UI_view2d_draw_scale_y__block(region, v2d, &rect, TH_SCROLL_TEXT);
+}
+
static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region)
{
Scene *scene = CTX_data_scene(C);
@@ -2718,7 +2713,7 @@ void draw_timeline_seq(const bContext *C, ARegion *region)
}
UI_view2d_view_ortho(v2d);
- draw_seq_backdrop(v2d);
+ draw_seq_timeline_channels(v2d);
if ((sseq->flag & SEQ_SHOW_OVERLAY) && (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_GRID)) {
U.v2d_min_gridsize *= 3;
UI_view2d_draw_lines_x__discrete_frames_or_seconds(
@@ -2776,13 +2771,7 @@ void draw_timeline_seq(const bContext *C, ARegion *region)
UI_view2d_view_restore(C);
ED_time_scrub_draw(region, scene, !(sseq->flag & SEQ_DRAWFRAMES), true);
- /* Draw channel numbers. */
- {
- rcti rect;
- BLI_rcti_init(
- &rect, 0, 15 * UI_DPI_FAC, 15 * UI_DPI_FAC, region->winy - UI_TIME_SCRUB_MARGIN_Y);
- UI_view2d_draw_scale_y__block(region, v2d, &rect, TH_SCROLL_TEXT);
- }
+ draw_seq_timeline_channel_numbers(region);
}
void draw_timeline_seq_display(const bContext *C, ARegion *region)
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index e9f37fa6838..3b5e16d84a9 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -39,6 +39,7 @@
#include "DNA_sound_types.h"
#include "BKE_context.h"
+#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
@@ -46,6 +47,7 @@
#include "BKE_sound.h"
#include "SEQ_add.h"
+#include "SEQ_animation.h"
#include "SEQ_clipboard.h"
#include "SEQ_edit.h"
#include "SEQ_effects.h"
@@ -66,6 +68,7 @@
#include "RNA_enum_types.h"
/* For menu, popup, icons, etc. */
+#include "ED_keyframing.h"
#include "ED_numinput.h"
#include "ED_outliner.h"
#include "ED_screen.h"
@@ -1558,7 +1561,7 @@ static int sequencer_split_invoke(bContext *C, wmOperator *op, const wmEvent *ev
}
RNA_int_set(op->ptr, "channel", mouseloc[1]);
RNA_enum_set(op->ptr, "side", split_side);
- /*RNA_enum_set(op->ptr, "type", split_hard); */
+ // RNA_enum_set(op->ptr, "type", split_hard);
return sequencer_split_exec(C, op);
}
@@ -1655,6 +1658,35 @@ void SEQUENCER_OT_split(struct wmOperatorType *ot)
/** \name Duplicate Strips Operator
* \{ */
+static void sequencer_backup_original_animation(Scene *scene, ListBase *list)
+{
+ if (scene->adt == NULL || scene->adt->action == NULL ||
+ BLI_listbase_is_empty(&scene->adt->action->curves)) {
+ return;
+ }
+
+ BLI_movelisttolist(list, &scene->adt->action->curves);
+}
+
+static void sequencer_restore_original_animation(Scene *scene, ListBase *list)
+{
+ if (scene->adt == NULL || scene->adt->action == NULL || BLI_listbase_is_empty(list)) {
+ return;
+ }
+
+ BLI_movelisttolist(&scene->adt->action->curves, list);
+}
+
+static void sequencer_duplicate_animation(Scene *scene, Sequence *seq, ListBase *curves_backup)
+{
+ GSet *fcurves = SEQ_fcurves_by_strip_get(seq, curves_backup);
+ GSET_FOREACH_BEGIN (FCurve *, fcu, fcurves) {
+ FCurve *fcu_cpy = BKE_fcurve_copy(fcu);
+ BLI_addtail(&scene->adt->action->curves, fcu_cpy);
+ }
+ GSET_FOREACH_END();
+}
+
static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
@@ -1665,32 +1697,44 @@ static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
}
Sequence *active_seq = SEQ_select_active_get(scene);
- ListBase duplicated = {NULL, NULL};
+ ListBase duplicated_strips = {NULL, NULL};
- SEQ_sequence_base_dupli_recursive(scene, scene, &duplicated, ed->seqbasep, 0, 0);
+ SEQ_sequence_base_dupli_recursive(scene, scene, &duplicated_strips, ed->seqbasep, 0, 0);
ED_sequencer_deselect_all(scene);
- if (duplicated.first) {
- Sequence *seq = duplicated.first;
- /* Rely on the nseqbase list being added at the end.
- * Their UUIDs has been re-generated by the SEQ_sequence_base_dupli_recursive(), */
- BLI_movelisttolist(ed->seqbasep, &duplicated);
-
- /* Handle duplicated strips: set active, select, ensure unique name and duplicate animation
- * data. */
- for (; seq; seq = seq->next) {
- if (active_seq != NULL && STREQ(seq->name, active_seq->name)) {
- SEQ_select_active_set(scene, seq);
- }
- seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL + SEQ_LOCK);
- SEQ_ensure_unique_name(seq, scene);
- }
+ if (duplicated_strips.first == NULL) {
+ return OPERATOR_CANCELLED;
+ }
- WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
- return OPERATOR_FINISHED;
+ /* Duplicate animation.
+ * First backup original curves from scene and duplicate strip curves from backup into scene.
+ * This way, when pasted strips are renamed, curves are renamed with them. Finally, restore
+ * original curves from backup.
+ */
+ ListBase fcurves_original_backup = {NULL, NULL};
+ sequencer_backup_original_animation(scene, &fcurves_original_backup);
+
+ Sequence *seq = duplicated_strips.first;
+
+ /* Rely on the nseqbase list being added at the end.
+ * Their UUIDs has been re-generated by the SEQ_sequence_base_dupli_recursive(), */
+ BLI_movelisttolist(ed->seqbasep, &duplicated_strips);
+
+ /* Handle duplicated strips: set active, select, ensure unique name and duplicate animation
+ * data. */
+ for (; seq; seq = seq->next) {
+ if (active_seq != NULL && STREQ(seq->name, active_seq->name)) {
+ SEQ_select_active_set(scene, seq);
+ }
+ seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL + SEQ_LOCK);
+ sequencer_duplicate_animation(scene, seq, &fcurves_original_backup);
+ SEQ_ensure_unique_name(seq, scene);
}
- return OPERATOR_CANCELLED;
+ sequencer_restore_original_animation(scene, &fcurves_original_backup);
+
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+ return OPERATOR_FINISHED;
}
void SEQUENCER_OT_duplicate(wmOperatorType *ot)
@@ -1905,7 +1949,7 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
}
seq_next = seq->next;
- SEQ_sequence_free(scene, seq, true);
+ SEQ_edit_flag_for_removal(scene, seqbase, seq);
seq = seq_next;
}
else {
@@ -1913,6 +1957,8 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
}
}
+ SEQ_edit_remove_flagged_sequences(scene, seqbase);
+
SEQ_sort(seqbase);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -1950,6 +1996,8 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
Editing *ed = SEQ_editing_get(scene);
Sequence *active_seq = SEQ_select_active_get(scene);
+ SEQ_prefetch_stop(scene);
+
if (active_seq && active_seq->type == SEQ_TYPE_META && active_seq->flag & SELECT) {
/* Enter meta-strip. */
SEQ_meta_stack_alloc(ed, active_seq);
@@ -2439,6 +2487,22 @@ static void seq_copy_del_sound(Scene *scene, Sequence *seq)
}
}
+static void sequencer_copy_animation(Scene *scene, Sequence *seq)
+{
+ if (scene->adt == NULL || scene->adt->action == NULL ||
+ BLI_listbase_is_empty(&scene->adt->action->curves)) {
+ return;
+ }
+
+ GSet *fcurves = SEQ_fcurves_by_strip_get(seq, &scene->adt->action->curves);
+
+ GSET_FOREACH_BEGIN (FCurve *, fcu, fcurves) {
+ BLI_addtail(&fcurves_clipboard, BKE_fcurve_copy(fcu));
+ }
+ GSET_FOREACH_END();
+ BLI_gset_free(fcurves, NULL);
+}
+
static int sequencer_copy_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -2465,8 +2529,10 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op)
seqbase_clipboard_frame = scene->r.cfra;
SEQ_clipboard_active_seq_name_store(scene);
- /* Remove anything that references the current scene. */
LISTBASE_FOREACH (Sequence *, seq, &seqbase_clipboard) {
+ /* Copy curves. */
+ sequencer_copy_animation(scene, seq);
+ /* Remove anything that references the current scene. */
seq_copy_del_sound(scene, seq);
}
@@ -2511,6 +2577,29 @@ void ED_sequencer_deselect_all(Scene *scene)
}
}
+static void sequencer_paste_animation(bContext *C)
+{
+ if (BLI_listbase_is_empty(&fcurves_clipboard)) {
+ return;
+ }
+
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ bAction *act;
+
+ if (scene->adt != NULL && scene->adt->action != NULL) {
+ act = scene->adt->action;
+ }
+ else {
+ /* get action to add F-Curve+keyframe to */
+ act = ED_id_action_ensure(bmain, &scene->id);
+ }
+
+ LISTBASE_FOREACH (FCurve *, fcu, &fcurves_clipboard) {
+ BLI_addtail(&act->curves, BKE_fcurve_copy(fcu));
+ }
+}
+
static int sequencer_paste_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -2540,6 +2629,17 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op)
ofs = scene->r.cfra - min_seq_startdisp;
}
+ /* Paste animation.
+ * Note: Only fcurves are copied. Drivers and NLA action strips are not copied.
+ * First backup original curves from scene and move curves from clipboard into scene. This way,
+ * when pasted strips are renamed, pasted fcurves are renamed with them. Finally restore original
+ * curves from backup.
+ */
+
+ ListBase fcurves_original_backup = {NULL, NULL};
+ sequencer_backup_original_animation(scene, &fcurves_original_backup);
+ sequencer_paste_animation(C);
+
/* Copy strips, temporarily restoring pointers to actual data-blocks. This
* must happen on the clipboard itself, so that copying does user counting
* on the actual data-blocks. */
@@ -2569,6 +2669,8 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op)
}
}
+ sequencer_restore_original_animation(scene, &fcurves_original_backup);
+
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h
index cb33c648b0a..7143a1fa1ca 100644
--- a/source/blender/editors/space_sequencer/sequencer_intern.h
+++ b/source/blender/editors/space_sequencer/sequencer_intern.h
@@ -33,13 +33,13 @@ struct ARegionType;
struct Depsgraph;
struct Main;
struct Scene;
-struct Sequence;
struct SeqCollection;
+struct Sequence;
struct SpaceSeq;
struct StripElem;
+struct View2D;
struct bContext;
struct rctf;
-struct View2D;
struct wmOperator;
#define OVERLAP_ALPHA 180
@@ -57,12 +57,12 @@ void sequencer_draw_preview(const struct bContext *C,
bool draw_backdrop);
void color3ubv_from_seq(const struct Scene *curscene,
const struct Sequence *seq,
- const bool show_strip_color_tag,
+ bool show_strip_color_tag,
uchar r_col[3]);
void sequencer_special_update_set(Sequence *seq);
/* Get handle width in 2d-View space. */
-float sequence_handle_size_get_clamped(struct Sequence *seq, const float pixelx);
+float sequence_handle_size_get_clamped(struct Sequence *seq, float pixelx);
/* UNUSED */
/* void seq_reset_imageofs(struct SpaceSeq *sseq); */
diff --git a/source/blender/editors/space_sequencer/sequencer_proxy.c b/source/blender/editors/space_sequencer/sequencer_proxy.c
index 0a8eb7cb88f..fb561025da2 100644
--- a/source/blender/editors/space_sequencer/sequencer_proxy.c
+++ b/source/blender/editors/space_sequencer/sequencer_proxy.c
@@ -85,7 +85,7 @@ static void seq_proxy_build_job(const bContext *C, ReportList *reports)
}
bool success = SEQ_proxy_rebuild_context(
- pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue);
+ pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue, false);
if (!success && (seq->strip->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) != 0) {
BKE_reportf(reports, RPT_WARNING, "Overwrite is not checked for %s, skipping", seq->name);
@@ -137,7 +137,7 @@ static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
short stop = 0, do_update;
float progress;
- SEQ_proxy_rebuild_context(bmain, depsgraph, scene, seq, file_list, &queue);
+ SEQ_proxy_rebuild_context(bmain, depsgraph, scene, seq, file_list, &queue, false);
for (link = queue.first; link; link = link->next) {
struct SeqIndexBuildContext *context = link->data;
diff --git a/source/blender/editors/space_sequencer/sequencer_thumbnails.c b/source/blender/editors/space_sequencer/sequencer_thumbnails.c
index c6fecdb1fc6..82ba17d4db1 100644
--- a/source/blender/editors/space_sequencer/sequencer_thumbnails.c
+++ b/source/blender/editors/space_sequencer/sequencer_thumbnails.c
@@ -66,7 +66,7 @@ typedef struct ThumbDataItem {
static void thumbnail_hash_data_free(void *val)
{
ThumbDataItem *item = val;
- SEQ_sequence_free(item->scene, item->seq_dupli, 0);
+ SEQ_sequence_free(item->scene, item->seq_dupli);
MEM_freeN(val);
}
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index b93f421ff5c..b294fdf4820 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -39,6 +39,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_remap.h"
#include "BKE_screen.h"
#include "BKE_sequencer_offscreen.h"
@@ -988,19 +989,12 @@ static void sequencer_buttons_region_listener(const wmRegionListenerParams *para
}
}
-static void sequencer_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void sequencer_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceSeq *sseq = (SpaceSeq *)slink;
-
- if (!ELEM(GS(old_id->name), ID_GD)) {
- return;
- }
-
- if ((ID *)sseq->gpd == old_id) {
- sseq->gpd = (bGPdata *)new_id;
- id_us_min(old_id);
- id_us_plus(new_id);
- }
+ BKE_id_remapper_apply(mappings, (ID **)&sseq->gpd, ID_REMAP_APPLY_DEFAULT);
}
/* ************************************* */
diff --git a/source/blender/editors/space_spreadsheet/CMakeLists.txt b/source/blender/editors/space_spreadsheet/CMakeLists.txt
index 27446fe1a94..f1db8dedf1a 100644
--- a/source/blender/editors/space_spreadsheet/CMakeLists.txt
+++ b/source/blender/editors/space_spreadsheet/CMakeLists.txt
@@ -49,7 +49,6 @@ set(SRC
spreadsheet_row_filter_ui.cc
spreadsheet_cache.hh
- spreadsheet_cell_value.hh
spreadsheet_column.hh
spreadsheet_column_values.hh
spreadsheet_context.hh
diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
index 0cb4a52eb2f..18f383d45fb 100644
--- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
+++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
@@ -18,6 +18,7 @@
#include "BLI_listbase.h"
+#include "BKE_lib_remap.h"
#include "BKE_screen.h"
#include "ED_screen.h"
@@ -60,15 +61,14 @@ using namespace blender::ed::spreadsheet;
static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
{
- SpaceSpreadsheet *spreadsheet_space = (SpaceSpreadsheet *)MEM_callocN(sizeof(SpaceSpreadsheet),
- "spreadsheet space");
+ SpaceSpreadsheet *spreadsheet_space = MEM_cnew<SpaceSpreadsheet>("spreadsheet space");
spreadsheet_space->spacetype = SPACE_SPREADSHEET;
spreadsheet_space->filter_flag = SPREADSHEET_FILTER_ENABLE;
{
/* Header. */
- ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet header");
+ ARegion *region = MEM_cnew<ARegion>("spreadsheet header");
BLI_addtail(&spreadsheet_space->regionbase, region);
region->regiontype = RGN_TYPE_HEADER;
region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
@@ -76,7 +76,7 @@ static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *U
{
/* Footer. */
- ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet footer region");
+ ARegion *region = MEM_cnew<ARegion>("spreadsheet footer region");
BLI_addtail(&spreadsheet_space->regionbase, region);
region->regiontype = RGN_TYPE_FOOTER;
region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_TOP : RGN_ALIGN_BOTTOM;
@@ -84,16 +84,15 @@ static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *U
{
/* Dataset Region */
- ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet dataset region");
+ ARegion *region = MEM_cnew<ARegion>("spreadsheet dataset region");
BLI_addtail(&spreadsheet_space->regionbase, region);
- region->regiontype = RGN_TYPE_CHANNELS;
+ region->regiontype = RGN_TYPE_TOOLS;
region->alignment = RGN_ALIGN_LEFT;
- region->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM);
}
{
/* Properties region. */
- ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet right region");
+ ARegion *region = MEM_cnew<ARegion>("spreadsheet right region");
BLI_addtail(&spreadsheet_space->regionbase, region);
region->regiontype = RGN_TYPE_UI;
region->alignment = RGN_ALIGN_RIGHT;
@@ -102,7 +101,7 @@ static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *U
{
/* Main window. */
- ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet main region");
+ ARegion *region = MEM_cnew<ARegion>("spreadsheet main region");
BLI_addtail(&spreadsheet_space->regionbase, region);
region->regiontype = RGN_TYPE_WINDOW;
}
@@ -114,7 +113,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 +130,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 +139,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);
@@ -172,21 +172,23 @@ static void spreadsheet_keymap(wmKeyConfig *keyconf)
WM_keymap_ensure(keyconf, "Spreadsheet Generic", SPACE_SPREADSHEET, 0);
}
-static void spreadsheet_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void spreadsheet_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const IDRemapper *mappings)
{
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)slink;
LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
- if (context->type == SPREADSHEET_CONTEXT_OBJECT) {
- SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context;
- if ((ID *)object_context->object == old_id) {
- if (new_id && GS(new_id->name) == ID_OB) {
- object_context->object = (Object *)new_id;
- }
- else {
- object_context->object = nullptr;
- }
- }
+ if (context->type != SPREADSHEET_CONTEXT_OBJECT) {
+ continue;
+ }
+ SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context;
+
+ if (object_context->object != nullptr && GS(object_context->object->id.name) != ID_OB) {
+ object_context->object = nullptr;
+ continue;
}
+
+ BKE_id_remapper_apply(mappings, ((ID **)&object_context->object), ID_REMAP_APPLY_DEFAULT);
}
}
@@ -323,6 +325,8 @@ static float get_default_column_width(const ColumnValues &values)
return 8.0f;
case SPREADSHEET_VALUE_TYPE_STRING:
return 5.0f;
+ case SPREADSHEET_VALUE_TYPE_UNKNOWN:
+ return 2.0f;
}
return float_width;
}
@@ -619,7 +623,7 @@ static void spreadsheet_right_region_listener(const wmRegionListenerParams *UNUS
void ED_spacetype_spreadsheet()
{
- SpaceType *st = (SpaceType *)MEM_callocN(sizeof(SpaceType), "spacetype spreadsheet");
+ SpaceType *st = MEM_cnew<SpaceType>("spacetype spreadsheet");
ARegionType *art;
st->spaceid = SPACE_SPREADSHEET;
@@ -634,7 +638,7 @@ void ED_spacetype_spreadsheet()
st->id_remap = spreadsheet_id_remap;
/* regions: main window */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet region");
+ art = MEM_cnew<ARegionType>("spacetype spreadsheet region");
art->regionid = RGN_TYPE_WINDOW;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
@@ -644,7 +648,7 @@ void ED_spacetype_spreadsheet()
BLI_addhead(&st->regiontypes, art);
/* regions: header */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet header region");
+ art = MEM_cnew<ARegionType>("spacetype spreadsheet header region");
art->regionid = RGN_TYPE_HEADER;
art->prefsizey = HEADERY;
art->keymapflag = 0;
@@ -657,7 +661,7 @@ void ED_spacetype_spreadsheet()
BLI_addhead(&st->regiontypes, art);
/* regions: footer */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet footer region");
+ art = MEM_cnew<ARegionType>("spacetype spreadsheet footer region");
art->regionid = RGN_TYPE_FOOTER;
art->prefsizey = HEADERY;
art->keymapflag = 0;
@@ -670,7 +674,7 @@ void ED_spacetype_spreadsheet()
BLI_addhead(&st->regiontypes, art);
/* regions: right panel buttons */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet right region");
+ art = MEM_cnew<ARegionType>("spacetype spreadsheet right region");
art->regionid = RGN_TYPE_UI;
art->prefsizex = UI_SIDEBAR_PANEL_WIDTH;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
@@ -685,10 +689,10 @@ void ED_spacetype_spreadsheet()
register_row_filter_panels(*art);
/* regions: channels */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spreadsheet dataset region");
- art->regionid = RGN_TYPE_CHANNELS;
+ art = MEM_cnew<ARegionType>("spreadsheet dataset region");
+ art->regionid = RGN_TYPE_TOOLS;
art->prefsizex = 150 + V2D_SCROLL_WIDTH;
- art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
+ art->keymapflag = ED_KEYMAP_UI;
art->init = ED_region_panels_init;
art->draw = spreadsheet_dataset_region_draw;
art->listener = spreadsheet_dataset_region_listener;
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh b/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh
deleted file mode 100644
index c11b4a2b23d..00000000000
--- a/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#pragma once
-
-#include <optional>
-
-#include "BLI_color.hh"
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
-
-struct Collection;
-struct Object;
-
-namespace blender::ed::spreadsheet {
-
-struct ObjectCellValue {
- const Object *object;
-};
-
-struct CollectionCellValue {
- const Collection *collection;
-};
-
-struct GeometrySetCellValue {
- const GeometrySet *geometry_set;
-};
-
-/**
- * This is a type that can hold the value of a cell in a spreadsheet. This type allows us to
- * decouple the drawing of individual cells from the code that generates the data to be displayed.
- */
-class CellValue {
- public:
- /* The implementation just uses a bunch of `std::option` for now. Unfortunately, we cannot use
- * `std::variant` yet, due to missing compiler support. This type can really be optimized more,
- * but it does not really matter too much currently. */
-
- std::optional<int> value_int;
- std::optional<float> value_float;
- std::optional<bool> value_bool;
- std::optional<float2> value_float2;
- std::optional<float3> value_float3;
- std::optional<ColorGeometry4f> value_color;
- std::optional<ObjectCellValue> value_object;
- std::optional<CollectionCellValue> value_collection;
- std::optional<GeometrySetCellValue> value_geometry_set;
- std::optional<std::string> value_string;
-};
-
-} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
index ee08c86b29f..ede8756a9da 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
@@ -18,18 +18,54 @@
#include "MEM_guardedalloc.h"
+#include "BLI_color.hh"
#include "BLI_hash.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_string.h"
#include "BLI_string_ref.hh"
+#include "BKE_geometry_set.hh"
+
+#include "FN_cpp_type.hh"
+
#include "spreadsheet_column.hh"
+#include "spreadsheet_column_values.hh"
namespace blender::ed::spreadsheet {
+eSpreadsheetColumnValueType cpp_type_to_column_type(const fn::CPPType &type)
+{
+ if (type.is<bool>()) {
+ return SPREADSHEET_VALUE_TYPE_BOOL;
+ }
+ if (type.is<int>()) {
+ return SPREADSHEET_VALUE_TYPE_INT32;
+ }
+ if (type.is<float>()) {
+ return SPREADSHEET_VALUE_TYPE_FLOAT;
+ }
+ if (type.is<float2>()) {
+ return SPREADSHEET_VALUE_TYPE_FLOAT2;
+ }
+ if (type.is<float3>()) {
+ return SPREADSHEET_VALUE_TYPE_FLOAT3;
+ }
+ if (type.is<ColorGeometry4f>()) {
+ return SPREADSHEET_VALUE_TYPE_COLOR;
+ }
+ if (type.is<std::string>()) {
+ return SPREADSHEET_VALUE_TYPE_STRING;
+ }
+ if (type.is<InstanceReference>()) {
+ return SPREADSHEET_VALUE_TYPE_INSTANCES;
+ }
+
+ return SPREADSHEET_VALUE_TYPE_UNKNOWN;
+}
+
SpreadsheetColumnID *spreadsheet_column_id_new()
{
- SpreadsheetColumnID *column_id = (SpreadsheetColumnID *)MEM_callocN(sizeof(SpreadsheetColumnID),
- __func__);
+ SpreadsheetColumnID *column_id = MEM_cnew<SpreadsheetColumnID>(__func__);
return column_id;
}
@@ -50,8 +86,7 @@ void spreadsheet_column_id_free(SpreadsheetColumnID *column_id)
SpreadsheetColumn *spreadsheet_column_new(SpreadsheetColumnID *column_id)
{
- SpreadsheetColumn *column = (SpreadsheetColumn *)MEM_callocN(sizeof(SpreadsheetColumn),
- __func__);
+ SpreadsheetColumn *column = MEM_cnew<SpreadsheetColumn>(__func__);
column->id = column_id;
return column;
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.hh b/source/blender/editors/space_spreadsheet/spreadsheet_column.hh
index 1a03278acad..7dad505c21b 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_column.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.hh
@@ -44,7 +44,7 @@ void spreadsheet_column_id_free(SpreadsheetColumnID *column_id);
SpreadsheetColumn *spreadsheet_column_new(SpreadsheetColumnID *column_id);
SpreadsheetColumn *spreadsheet_column_copy(const SpreadsheetColumn *src_column);
void spreadsheet_column_assign_runtime_data(SpreadsheetColumn *column,
- const eSpreadsheetColumnValueType data_type,
+ eSpreadsheetColumnValueType data_type,
const StringRefNull display_name);
void spreadsheet_column_free(SpreadsheetColumn *column);
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh b/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh
index 877651d6530..83e3217e5c8 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh
@@ -20,33 +20,36 @@
#include "BLI_string_ref.hh"
-#include "spreadsheet_cell_value.hh"
+#include "FN_generic_virtual_array.hh"
namespace blender::ed::spreadsheet {
+struct CellDrawParams;
+
+eSpreadsheetColumnValueType cpp_type_to_column_type(const fn::CPPType &type);
+
/**
* This represents a column in a spreadsheet. It has a name and provides a value for all the cells
* in the column.
*/
-class ColumnValues {
+class ColumnValues final {
protected:
- eSpreadsheetColumnValueType type_;
std::string name_;
- int size_;
+
+ fn::GVArray data_;
public:
- ColumnValues(const eSpreadsheetColumnValueType type, std::string name, const int size)
- : type_(type), name_(std::move(name)), size_(size)
+ ColumnValues(std::string name, fn::GVArray data) : name_(std::move(name)), data_(std::move(data))
{
+ /* The array should not be empty. */
+ BLI_assert(data_);
}
virtual ~ColumnValues() = default;
- virtual void get_value(int index, CellValue &r_cell_value) const = 0;
-
eSpreadsheetColumnValueType type() const
{
- return type_;
+ return cpp_type_to_column_type(data_.type());
}
StringRefNull name() const
@@ -56,45 +59,16 @@ class ColumnValues {
int size() const
{
- return size_;
+ return data_.size();
}
- /* The default width of newly created columns, in UI units. */
- float default_width = 0.0f;
-};
-
-/* Utility class for the function below. */
-template<typename GetValueF> class LambdaColumnValues : public ColumnValues {
- private:
- GetValueF get_value_;
-
- public:
- LambdaColumnValues(const eSpreadsheetColumnValueType type,
- std::string name,
- int size,
- GetValueF get_value)
- : ColumnValues(type, std::move(name), size), get_value_(std::move(get_value))
+ const fn::GVArray &data() const
{
+ return data_;
}
- void get_value(int index, CellValue &r_cell_value) const final
- {
- get_value_(index, r_cell_value);
- }
+ /* The default width of newly created columns, in UI units. */
+ float default_width = 0.0f;
};
-/* Utility function that simplifies creating a spreadsheet column from a lambda function. */
-template<typename GetValueF>
-std::unique_ptr<ColumnValues> column_values_from_function(const eSpreadsheetColumnValueType type,
- std::string name,
- const int size,
- GetValueF get_value,
- const float default_width = 0.0f)
-{
- std::unique_ptr<ColumnValues> column_values = std::make_unique<LambdaColumnValues<GetValueF>>(
- type, std::move(name), size, std::move(get_value));
- column_values->default_width = default_width;
- return column_values;
-}
-
} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_context.cc b/source/blender/editors/space_spreadsheet/spreadsheet_context.cc
index e55a7cae6a6..5cec016b727 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_context.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_context.cc
@@ -50,8 +50,7 @@ namespace blender::ed::spreadsheet {
static SpreadsheetContextObject *spreadsheet_context_object_new()
{
- SpreadsheetContextObject *context = (SpreadsheetContextObject *)MEM_callocN(
- sizeof(SpreadsheetContextObject), __func__);
+ SpreadsheetContextObject *context = MEM_cnew<SpreadsheetContextObject>(__func__);
context->base.type = SPREADSHEET_CONTEXT_OBJECT;
return context;
}
@@ -77,8 +76,7 @@ static void spreadsheet_context_object_free(SpreadsheetContextObject *context)
static SpreadsheetContextModifier *spreadsheet_context_modifier_new()
{
- SpreadsheetContextModifier *context = (SpreadsheetContextModifier *)MEM_callocN(
- sizeof(SpreadsheetContextModifier), __func__);
+ SpreadsheetContextModifier *context = MEM_cnew<SpreadsheetContextModifier>(__func__);
context->base.type = SPREADSHEET_CONTEXT_MODIFIER;
return context;
}
@@ -111,8 +109,7 @@ static void spreadsheet_context_modifier_free(SpreadsheetContextModifier *contex
static SpreadsheetContextNode *spreadsheet_context_node_new()
{
- SpreadsheetContextNode *context = (SpreadsheetContextNode *)MEM_callocN(
- sizeof(SpreadsheetContextNode), __func__);
+ SpreadsheetContextNode *context = MEM_cnew<SpreadsheetContextNode>(__func__);
context->base.type = SPREADSHEET_CONTEXT_NODE;
return context;
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
index 173ef43bfb6..b9b03732a40 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
@@ -14,8 +14,11 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include "BLI_virtual_array.hh"
+
#include "BKE_context.h"
#include "BKE_editmesh.h"
+#include "BKE_global.h"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
#include "BKE_mesh_wrapper.h"
@@ -51,30 +54,6 @@ using blender::fn::GField;
namespace blender::ed::spreadsheet {
-static std::optional<eSpreadsheetColumnValueType> cpp_type_to_column_value_type(
- const fn::CPPType &type)
-{
- if (type.is<bool>()) {
- return SPREADSHEET_VALUE_TYPE_BOOL;
- }
- if (type.is<int>()) {
- return SPREADSHEET_VALUE_TYPE_INT32;
- }
- if (type.is<float>()) {
- return SPREADSHEET_VALUE_TYPE_FLOAT;
- }
- if (type.is<float2>()) {
- return SPREADSHEET_VALUE_TYPE_FLOAT2;
- }
- if (type.is<float3>()) {
- return SPREADSHEET_VALUE_TYPE_FLOAT3;
- }
- if (type.is<ColorGeometry4f>()) {
- return SPREADSHEET_VALUE_TYPE_COLOR;
- }
- return std::nullopt;
-}
-
void ExtraColumns::foreach_default_column_ids(
FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
{
@@ -92,39 +71,7 @@ std::unique_ptr<ColumnValues> ExtraColumns::get_column_values(
if (values == nullptr) {
return {};
}
- eSpreadsheetColumnValueType column_type = *cpp_type_to_column_value_type(values->type());
- return column_values_from_function(column_type,
- column_id.name,
- values->size(),
- [column_type, values](int index, CellValue &r_cell_value) {
- const void *value = (*values)[index];
- switch (column_type) {
- case SPREADSHEET_VALUE_TYPE_BOOL:
- r_cell_value.value_bool = *(const bool *)value;
- break;
- case SPREADSHEET_VALUE_TYPE_INT32:
- r_cell_value.value_int = *(const int *)value;
- break;
- case SPREADSHEET_VALUE_TYPE_FLOAT:
- r_cell_value.value_float = *(const float *)value;
- break;
- case SPREADSHEET_VALUE_TYPE_FLOAT2:
- r_cell_value.value_float2 = *(const float2 *)value;
- break;
- case SPREADSHEET_VALUE_TYPE_FLOAT3:
- r_cell_value.value_float3 = *(const float3 *)value;
- break;
- case SPREADSHEET_VALUE_TYPE_COLOR:
- r_cell_value.value_color = *(
- const ColorGeometry4f *)value;
- break;
- case SPREADSHEET_VALUE_TYPE_STRING:
- r_cell_value.value_string = *(const std::string *)value;
- break;
- case SPREADSHEET_VALUE_TYPE_INSTANCES:
- break;
- }
- });
+ return std::make_unique<ColumnValues>(column_id.name, fn::GVArray::ForSpan(*values));
}
void GeometryDataSource::foreach_default_column_ids(
@@ -157,6 +104,20 @@ void GeometryDataSource::foreach_default_column_ids(
fn({(char *)"Rotation"}, false);
fn({(char *)"Scale"}, false);
}
+ else if (G.debug_value == 4001 && component_->type() == GEO_COMPONENT_TYPE_MESH) {
+ if (domain_ == ATTR_DOMAIN_EDGE) {
+ fn({(char *)"Vertex 1"}, false);
+ fn({(char *)"Vertex 2"}, false);
+ }
+ else if (domain_ == ATTR_DOMAIN_FACE) {
+ fn({(char *)"Corner Start"}, false);
+ fn({(char *)"Corner Size"}, false);
+ }
+ else if (domain_ == ATTR_DOMAIN_CORNER) {
+ fn({(char *)"Vertex"}, false);
+ fn({(char *)"Edge"}, false);
+ }
+ }
}
std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
@@ -179,52 +140,72 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
if (STREQ(column_id.name, "Name")) {
Span<int> reference_handles = instances.instance_reference_handles();
Span<InstanceReference> references = instances.references();
- std::unique_ptr<ColumnValues> values = column_values_from_function(
- SPREADSHEET_VALUE_TYPE_INSTANCES,
- "Name",
- domain_size,
- [reference_handles, references](int index, CellValue &r_cell_value) {
- const InstanceReference &reference = references[reference_handles[index]];
- switch (reference.type()) {
- case InstanceReference::Type::Object: {
- Object &object = reference.object();
- r_cell_value.value_object = ObjectCellValue{&object};
- break;
- }
- case InstanceReference::Type::Collection: {
- Collection &collection = reference.collection();
- r_cell_value.value_collection = CollectionCellValue{&collection};
- break;
- }
- case InstanceReference::Type::GeometrySet: {
- const GeometrySet &geometry_set = reference.geometry_set();
- r_cell_value.value_geometry_set = GeometrySetCellValue{&geometry_set};
- break;
- }
- case InstanceReference::Type::None: {
- break;
- }
- }
- });
- return values;
+ return std::make_unique<ColumnValues>(
+ column_id.name,
+ VArray<InstanceReference>::ForFunc(domain_size,
+ [reference_handles, references](int64_t index) {
+ return references[reference_handles[index]];
+ }));
}
Span<float4x4> transforms = instances.instance_transforms();
if (STREQ(column_id.name, "Rotation")) {
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_FLOAT3,
- column_id.name,
- domain_size,
- [transforms](int index, CellValue &r_cell_value) {
- r_cell_value.value_float3 = transforms[index].to_euler();
- });
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<float3>::ForFunc(domain_size, [transforms](int64_t index) {
+ return transforms[index].to_euler();
+ }));
}
if (STREQ(column_id.name, "Scale")) {
- return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT3,
- column_id.name,
- domain_size,
- [transforms](int index, CellValue &r_cell_value) {
- r_cell_value.value_float3 = transforms[index].scale();
- });
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<float3>::ForFunc(domain_size, [transforms](int64_t index) {
+ return transforms[index].scale();
+ }));
+ }
+ }
+ else if (G.debug_value == 4001 && component_->type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &component = static_cast<const MeshComponent &>(*component_);
+ if (const Mesh *mesh = component.get_for_read()) {
+ if (domain_ == ATTR_DOMAIN_EDGE) {
+ if (STREQ(column_id.name, "Vertex 1")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<int>::ForFunc(mesh->totedge, [mesh](int64_t index) {
+ return mesh->medge[index].v1;
+ }));
+ }
+ if (STREQ(column_id.name, "Vertex 2")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<int>::ForFunc(mesh->totedge, [mesh](int64_t index) {
+ return mesh->medge[index].v2;
+ }));
+ }
+ }
+ else if (domain_ == ATTR_DOMAIN_FACE) {
+ if (STREQ(column_id.name, "Corner Start")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<int>::ForFunc(mesh->totpoly, [mesh](int64_t index) {
+ return mesh->mpoly[index].loopstart;
+ }));
+ }
+ if (STREQ(column_id.name, "Corner Size")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<int>::ForFunc(mesh->totpoly, [mesh](int64_t index) {
+ return mesh->mpoly[index].totloop;
+ }));
+ }
+ }
+ else if (domain_ == ATTR_DOMAIN_CORNER) {
+ if (STREQ(column_id.name, "Vertex")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<int>::ForFunc(mesh->totloop, [mesh](int64_t index) {
+ return mesh->mloop[index].v;
+ }));
+ }
+ if (STREQ(column_id.name, "Edge")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<int>::ForFunc(mesh->totloop, [mesh](int64_t index) {
+ return mesh->mloop[index].e;
+ }));
+ }
+ }
}
}
@@ -237,71 +218,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
return {};
}
- const CustomDataType type = bke::cpp_type_to_custom_data_type(varray.type());
- switch (type) {
- case CD_PROP_FLOAT:
- return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- float value;
- varray.get(index, &value);
- r_cell_value.value_float = value;
- });
- case CD_PROP_INT32:
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_INT32,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- int value;
- varray.get(index, &value);
- r_cell_value.value_int = value;
- },
- STREQ(column_id.name, "id") ? 5.5f : 0.0f);
- case CD_PROP_BOOL:
- return column_values_from_function(SPREADSHEET_VALUE_TYPE_BOOL,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- bool value;
- varray.get(index, &value);
- r_cell_value.value_bool = value;
- });
- case CD_PROP_FLOAT2: {
- return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT2,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- float2 value;
- varray.get(index, &value);
- r_cell_value.value_float2 = value;
- });
- }
- case CD_PROP_FLOAT3: {
- return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT3,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- float3 value;
- varray.get(index, &value);
- r_cell_value.value_float3 = value;
- });
- }
- case CD_PROP_COLOR: {
- return column_values_from_function(SPREADSHEET_VALUE_TYPE_COLOR,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- ColorGeometry4f value;
- varray.get(index, &value);
- r_cell_value.value_color = value;
- });
- }
- default:
- break;
- }
- return {};
+ return std::make_unique<ColumnValues>(column_id.name, std::move(varray));
}
int GeometryDataSource::tot_rows() const
@@ -309,90 +226,9 @@ int GeometryDataSource::tot_rows() const
return component_->attribute_domain_size(domain_);
}
-using IsVertexSelectedFn = FunctionRef<bool(int vertex_index)>;
-
-static void get_selected_vertex_indices(const Mesh &mesh,
- const IsVertexSelectedFn is_vertex_selected_fn,
- MutableSpan<bool> selection)
-{
- for (const int i : IndexRange(mesh.totvert)) {
- if (!selection[i]) {
- continue;
- }
- if (!is_vertex_selected_fn(i)) {
- selection[i] = false;
- }
- }
-}
-
-static void get_selected_corner_indices(const Mesh &mesh,
- const IsVertexSelectedFn is_vertex_selected_fn,
- MutableSpan<bool> selection)
-{
- for (const int i : IndexRange(mesh.totloop)) {
- const MLoop &loop = mesh.mloop[i];
- if (!selection[i]) {
- continue;
- }
- if (!is_vertex_selected_fn(loop.v)) {
- selection[i] = false;
- }
- }
-}
-
-static void get_selected_face_indices(const Mesh &mesh,
- const IsVertexSelectedFn is_vertex_selected_fn,
- MutableSpan<bool> selection)
-{
- for (const int poly_index : IndexRange(mesh.totpoly)) {
- if (!selection[poly_index]) {
- continue;
- }
- const MPoly &poly = mesh.mpoly[poly_index];
- for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- const MLoop &loop = mesh.mloop[loop_index];
- if (!is_vertex_selected_fn(loop.v)) {
- selection[poly_index] = false;
- break;
- }
- }
- }
-}
-
-static void get_selected_edge_indices(const Mesh &mesh,
- const IsVertexSelectedFn is_vertex_selected_fn,
- MutableSpan<bool> selection)
-{
- for (const int i : IndexRange(mesh.totedge)) {
- if (!selection[i]) {
- continue;
- }
- const MEdge &edge = mesh.medge[i];
- if (!is_vertex_selected_fn(edge.v1) || !is_vertex_selected_fn(edge.v2)) {
- selection[i] = false;
- }
- }
-}
-
-static void get_selected_indices_on_domain(const Mesh &mesh,
- const AttributeDomain domain,
- const IsVertexSelectedFn is_vertex_selected_fn,
- MutableSpan<bool> selection)
-{
- switch (domain) {
- case ATTR_DOMAIN_POINT:
- return get_selected_vertex_indices(mesh, is_vertex_selected_fn, selection);
- case ATTR_DOMAIN_FACE:
- return get_selected_face_indices(mesh, is_vertex_selected_fn, selection);
- case ATTR_DOMAIN_CORNER:
- return get_selected_corner_indices(mesh, is_vertex_selected_fn, selection);
- case ATTR_DOMAIN_EDGE:
- return get_selected_edge_indices(mesh, is_vertex_selected_fn, selection);
- default:
- return;
- }
-}
-
+/**
+ * Only data sets corresponding to mesh objects in edit mode currently support selection filtering.
+ */
bool GeometryDataSource::has_selection_filter() const
{
Object *object_orig = DEG_get_original_object(object_eval_);
@@ -409,7 +245,18 @@ bool GeometryDataSource::has_selection_filter() const
return true;
}
-void GeometryDataSource::apply_selection_filter(MutableSpan<bool> rows_included) const
+static IndexMask index_mask_from_bool_array(const VArray<bool> &selection,
+ Vector<int64_t> &indices)
+{
+ for (const int i : selection.index_range()) {
+ if (selection[i]) {
+ indices.append(i);
+ }
+ }
+ return IndexMask(indices);
+}
+
+IndexMask GeometryDataSource::apply_selection_filter(Vector<int64_t> &indices) const
{
std::lock_guard lock{mutex_};
@@ -425,27 +272,38 @@ void GeometryDataSource::apply_selection_filter(MutableSpan<bool> rows_included)
int *orig_indices = (int *)CustomData_get_layer(&mesh_eval->vdata, CD_ORIGINDEX);
if (orig_indices != nullptr) {
/* Use CD_ORIGINDEX layer if it exists. */
- auto is_vertex_selected = [&](int vertex_index) -> bool {
- const int i_orig = orig_indices[vertex_index];
- if (i_orig < 0) {
- return false;
- }
- if (i_orig >= bm->totvert) {
- return false;
- }
- BMVert *vert = bm->vtable[i_orig];
- return BM_elem_flag_test(vert, BM_ELEM_SELECT);
- };
- get_selected_indices_on_domain(*mesh_eval, domain_, is_vertex_selected, rows_included);
- }
- else if (mesh_eval->totvert == bm->totvert) {
+ VArray<bool> selection = mesh_component->attribute_try_adapt_domain<bool>(
+ VArray<bool>::ForFunc(mesh_eval->totvert,
+ [bm, orig_indices](int vertex_index) -> bool {
+ const int i_orig = orig_indices[vertex_index];
+ if (i_orig < 0) {
+ return false;
+ }
+ if (i_orig >= bm->totvert) {
+ return false;
+ }
+ BMVert *vert = bm->vtable[i_orig];
+ return BM_elem_flag_test(vert, BM_ELEM_SELECT);
+ }),
+ ATTR_DOMAIN_POINT,
+ domain_);
+ return index_mask_from_bool_array(selection, indices);
+ }
+
+ if (mesh_eval->totvert == bm->totvert) {
/* Use a simple heuristic to match original vertices to evaluated ones. */
- auto is_vertex_selected = [&](int vertex_index) -> bool {
- BMVert *vert = bm->vtable[vertex_index];
- return BM_elem_flag_test(vert, BM_ELEM_SELECT);
- };
- get_selected_indices_on_domain(*mesh_eval, domain_, is_vertex_selected, rows_included);
- }
+ VArray<bool> selection = mesh_component->attribute_try_adapt_domain<bool>(
+ VArray<bool>::ForFunc(mesh_eval->totvert,
+ [bm](int vertex_index) -> bool {
+ BMVert *vert = bm->vtable[vertex_index];
+ return BM_elem_flag_test(vert, BM_ELEM_SELECT);
+ }),
+ ATTR_DOMAIN_POINT,
+ domain_);
+ return index_mask_from_bool_array(selection, indices);
+ }
+
+ return IndexMask(mesh_eval->totvert);
}
void VolumeDataSource::foreach_default_column_ids(
@@ -472,50 +330,36 @@ std::unique_ptr<ColumnValues> VolumeDataSource::get_column_values(
#ifdef WITH_OPENVDB
const int size = this->tot_rows();
if (STREQ(column_id.name, "Grid Name")) {
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_STRING,
- IFACE_("Grid Name"),
- size,
- [volume](int index, CellValue &r_cell_value) {
+ return std::make_unique<ColumnValues>(
+ IFACE_("Grid Name"), VArray<std::string>::ForFunc(size, [volume](int64_t index) {
const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, index);
- r_cell_value.value_string = BKE_volume_grid_name(volume_grid);
- },
- 6.0f);
+ return BKE_volume_grid_name(volume_grid);
+ }));
}
if (STREQ(column_id.name, "Data Type")) {
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_STRING,
- IFACE_("Type"),
- size,
- [volume](int index, CellValue &r_cell_value) {
+ return std::make_unique<ColumnValues>(
+ IFACE_("Data Type"), VArray<std::string>::ForFunc(size, [volume](int64_t index) {
const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, index);
const VolumeGridType type = BKE_volume_grid_type(volume_grid);
const char *name = nullptr;
RNA_enum_name_from_value(rna_enum_volume_grid_data_type_items, type, &name);
- r_cell_value.value_string = IFACE_(name);
- },
- 5.0f);
+ return IFACE_(name);
+ }));
}
if (STREQ(column_id.name, "Class")) {
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_STRING,
- IFACE_("Class"),
- size,
- [volume](int index, CellValue &r_cell_value) {
+ return std::make_unique<ColumnValues>(
+ IFACE_("Class"), VArray<std::string>::ForFunc(size, [volume](int64_t index) {
const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, index);
openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
openvdb::GridClass grid_class = grid->getGridClass();
if (grid_class == openvdb::GridClass::GRID_FOG_VOLUME) {
- r_cell_value.value_string = IFACE_("Fog Volume");
- }
- else if (grid_class == openvdb::GridClass::GRID_LEVEL_SET) {
- r_cell_value.value_string = IFACE_("Level Set");
+ return IFACE_("Fog Volume");
}
- else {
- r_cell_value.value_string = IFACE_("Unknown");
+ if (grid_class == openvdb::GridClass::GRID_LEVEL_SET) {
+ return IFACE_("Level Set");
}
- },
- 5.0f);
+ return IFACE_("Unknown");
+ }));
}
#else
UNUSED_VARS(column_id);
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
index 23207734d2b..b5105050d2b 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
@@ -87,7 +87,7 @@ class GeometryDataSource : public DataSource {
* filtering.
*/
bool has_selection_filter() const override;
- void apply_selection_filter(MutableSpan<bool> rows_included) const;
+ IndexMask apply_selection_filter(Vector<int64_t> &indices) const;
void foreach_default_column_ids(
FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const override;
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh
index e62835d5792..df23a27aa22 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh
@@ -36,10 +36,10 @@ struct SpaceSpreadsheet_Runtime {
}
};
-struct bContext;
struct ARegionType;
+struct bContext;
-void spreadsheet_operatortypes(void);
+void spreadsheet_operatortypes();
void spreadsheet_update_context_path(const bContext *C);
Object *spreadsheet_get_object_eval(const SpaceSpreadsheet *sspreadsheet,
const Depsgraph *depsgraph);
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
index 202523c0e64..f4b5ff819ed 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
@@ -17,8 +17,15 @@
#include <iomanip>
#include <sstream>
+#include "BLI_math_vec_types.hh"
+
+#include "BKE_geometry_set.hh"
+
+#include "spreadsheet_column_values.hh"
#include "spreadsheet_layout.hh"
+#include "DNA_collection_types.h"
+#include "DNA_object_types.h"
#include "DNA_userdef_types.h"
#include "UI_interface.h"
@@ -92,13 +99,14 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
{
const int real_index = spreadsheet_layout_.row_indices[row_index];
const ColumnValues &column = *spreadsheet_layout_.columns[column_index].values;
- CellValue cell_value;
- if (real_index < column.size()) {
- column.get_value(real_index, cell_value);
+ if (real_index > column.size()) {
+ return;
}
- if (cell_value.value_int.has_value()) {
- const int value = *cell_value.value_int;
+ const fn::GVArray &data = column.data();
+
+ if (data.type().is<int>()) {
+ const int value = data.get<int>(real_index);
const std::string value_str = std::to_string(value);
uiBut *but = uiDefIconTextBut(params.block,
UI_BTYPE_LABEL,
@@ -119,8 +127,8 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT);
UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT);
}
- else if (cell_value.value_float.has_value()) {
- const float value = *cell_value.value_float;
+ else if (data.type().is<float>()) {
+ const float value = data.get<float>(real_index);
std::stringstream ss;
ss << std::fixed << std::setprecision(3) << value;
const std::string value_str = ss.str();
@@ -143,8 +151,8 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT);
UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT);
}
- else if (cell_value.value_bool.has_value()) {
- const bool value = *cell_value.value_bool;
+ else if (data.type().is<bool>()) {
+ const bool value = data.get<bool>(real_index);
const int icon = value ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
uiBut *but = uiDefIconTextBut(params.block,
UI_BTYPE_LABEL,
@@ -163,87 +171,81 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
nullptr);
UI_but_drawflag_disable(but, UI_BUT_ICON_LEFT);
}
- else if (cell_value.value_float2.has_value()) {
- const float2 value = *cell_value.value_float2;
+ else if (data.type().is<float2>()) {
+ const float2 value = data.get<float2>(real_index);
this->draw_float_vector(params, Span(&value.x, 2));
}
- else if (cell_value.value_float3.has_value()) {
- const float3 value = *cell_value.value_float3;
+ else if (data.type().is<float3>()) {
+ const float3 value = data.get<float3>(real_index);
this->draw_float_vector(params, Span(&value.x, 3));
}
- else if (cell_value.value_color.has_value()) {
- const ColorGeometry4f value = *cell_value.value_color;
+ else if (data.type().is<ColorGeometry4f>()) {
+ const ColorGeometry4f value = data.get<ColorGeometry4f>(real_index);
this->draw_float_vector(params, Span(&value.r, 4));
}
- else if (cell_value.value_object.has_value()) {
- const ObjectCellValue value = *cell_value.value_object;
- uiDefIconTextBut(params.block,
- UI_BTYPE_LABEL,
- 0,
- ICON_OBJECT_DATA,
- reinterpret_cast<const ID *const>(value.object)->name + 2,
- params.xmin,
- params.ymin,
- params.width,
- params.height,
- nullptr,
- 0,
- 0,
- 0,
- 0,
- nullptr);
- }
- else if (cell_value.value_collection.has_value()) {
- const CollectionCellValue value = *cell_value.value_collection;
- uiDefIconTextBut(params.block,
- UI_BTYPE_LABEL,
- 0,
- ICON_OUTLINER_COLLECTION,
- reinterpret_cast<const ID *const>(value.collection)->name + 2,
- params.xmin,
- params.ymin,
- params.width,
- params.height,
- nullptr,
- 0,
- 0,
- 0,
- 0,
- nullptr);
- }
- else if (cell_value.value_geometry_set.has_value()) {
- uiDefIconTextBut(params.block,
- UI_BTYPE_LABEL,
- 0,
- ICON_MESH_DATA,
- "Geometry",
- params.xmin,
- params.ymin,
- params.width,
- params.height,
- nullptr,
- 0,
- 0,
- 0,
- 0,
- nullptr);
- }
- else if (cell_value.value_string.has_value()) {
- uiDefIconTextBut(params.block,
- UI_BTYPE_LABEL,
- 0,
- ICON_NONE,
- cell_value.value_string->c_str(),
- params.xmin,
- params.ymin,
- params.width,
- params.height,
- nullptr,
- 0,
- 0,
- 0,
- 0,
- nullptr);
+ else if (data.type().is<InstanceReference>()) {
+ const InstanceReference value = data.get<InstanceReference>(real_index);
+ switch (value.type()) {
+ case InstanceReference::Type::Object: {
+ const Object &object = value.object();
+ uiDefIconTextBut(params.block,
+ UI_BTYPE_LABEL,
+ 0,
+ ICON_OBJECT_DATA,
+ object.id.name + 2,
+ params.xmin,
+ params.ymin,
+ params.width,
+ params.height,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+ break;
+ }
+ case InstanceReference::Type::Collection: {
+ Collection &collection = value.collection();
+ uiDefIconTextBut(params.block,
+ UI_BTYPE_LABEL,
+ 0,
+ ICON_OUTLINER_COLLECTION,
+ collection.id.name + 2,
+ params.xmin,
+ params.ymin,
+ params.width,
+ params.height,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+ break;
+ }
+ case InstanceReference::Type::GeometrySet: {
+ uiDefIconTextBut(params.block,
+ UI_BTYPE_LABEL,
+ 0,
+ ICON_MESH_DATA,
+ "Geometry",
+ params.xmin,
+ params.ymin,
+ params.width,
+ params.height,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+ break;
+ }
+ case InstanceReference::Type::None: {
+ break;
+ }
+ }
}
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh b/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh
index 1768af6ae09..f996cd99dad 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh
@@ -32,7 +32,7 @@ struct ColumnLayout {
/* Layout information for the entire spreadsheet. */
struct SpreadsheetLayout {
Vector<ColumnLayout> columns;
- Span<int64_t> row_indices;
+ IndexMask row_indices;
int index_column_width = 100;
};
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc b/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc
index 854c3d4aba6..db8265a33ce 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc
@@ -25,7 +25,7 @@ namespace blender::ed::spreadsheet {
void spreadsheet_data_set_region_panels_register(ARegionType &region_type)
{
- PanelType *panel_type = (PanelType *)MEM_callocN(sizeof(PanelType), __func__);
+ PanelType *panel_type = MEM_cnew<PanelType>(__func__);
strcpy(panel_type->idname, "SPREADSHEET_PT_data_set");
strcpy(panel_type->label, N_("Data Set"));
strcpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
index 1e46fef8d71..556c0b0d5ca 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
@@ -18,7 +18,6 @@
#include "BLI_listbase.h"
-#include "DNA_collection_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
@@ -38,238 +37,193 @@
namespace blender::ed::spreadsheet {
-template<typename OperationFn>
-static void apply_filter_operation(const ColumnValues &values,
+template<typename T, typename OperationFn>
+static void apply_filter_operation(const VArray<T> &data,
OperationFn check_fn,
- MutableSpan<bool> rows_included)
+ const IndexMask mask,
+ Vector<int64_t> &new_indices)
{
- for (const int i : rows_included.index_range()) {
- if (!rows_included[i]) {
- continue;
- }
- CellValue cell_value;
- values.get_value(i, cell_value);
- if (!check_fn(cell_value)) {
- rows_included[i] = false;
+ for (const int64_t i : mask) {
+ if (check_fn(data[i])) {
+ new_indices.append(i);
}
}
}
-static void apply_row_filter(const SpreadsheetLayout &spreadsheet_layout,
- const SpreadsheetRowFilter &row_filter,
- MutableSpan<bool> rows_included)
+static void apply_row_filter(const SpreadsheetRowFilter &row_filter,
+ const Map<StringRef, const ColumnValues *> &columns,
+ const IndexMask prev_mask,
+ Vector<int64_t> &new_indices)
{
- for (const ColumnLayout &column : spreadsheet_layout.columns) {
- const ColumnValues &values = *column.values;
- if (values.name() != row_filter.column_name) {
- continue;
+ const ColumnValues &column = *columns.lookup(row_filter.column_name);
+ const fn::GVArray &column_data = column.data();
+ if (column_data.type().is<float>()) {
+ const float value = row_filter.value_float;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ const float threshold = row_filter.threshold;
+ apply_filter_operation(
+ column_data.typed<float>(),
+ [&](const float cell) { return std::abs(cell - value) < threshold; },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_GREATER: {
+ apply_filter_operation(
+ column_data.typed<float>(),
+ [&](const float cell) { return cell > value; },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_LESS: {
+ apply_filter_operation(
+ column_data.typed<float>(),
+ [&](const float cell) { return cell < value; },
+ prev_mask,
+ new_indices);
+ break;
+ }
}
-
- switch (values.type()) {
- case SPREADSHEET_VALUE_TYPE_INT32: {
- const int value = row_filter.value_int;
- switch (row_filter.operation) {
- case SPREADSHEET_ROW_FILTER_EQUAL: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return *cell_value.value_int == value;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_GREATER: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return *cell_value.value_int > value;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_LESS: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return *cell_value.value_int < value;
- },
- rows_included);
- break;
- }
- }
+ }
+ else if (column_data.type().is<int>()) {
+ const int value = row_filter.value_int;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ apply_filter_operation(
+ column_data.typed<int>(),
+ [&](const int cell) { return cell == value; },
+ prev_mask,
+ new_indices);
break;
}
- case SPREADSHEET_VALUE_TYPE_FLOAT: {
- const float value = row_filter.value_float;
- switch (row_filter.operation) {
- case SPREADSHEET_ROW_FILTER_EQUAL: {
- const float threshold = row_filter.threshold;
- apply_filter_operation(
- values,
- [value, threshold](const CellValue &cell_value) -> bool {
- return std::abs(*cell_value.value_float - value) < threshold;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_GREATER: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return *cell_value.value_float > value;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_LESS: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return *cell_value.value_float < value;
- },
- rows_included);
- break;
- }
- }
+ case SPREADSHEET_ROW_FILTER_GREATER: {
+ apply_filter_operation(
+ column_data.typed<int>(),
+ [value](const int cell) { return cell > value; },
+ prev_mask,
+ new_indices);
break;
}
- case SPREADSHEET_VALUE_TYPE_FLOAT2: {
- const float2 value = row_filter.value_float2;
- switch (row_filter.operation) {
- case SPREADSHEET_ROW_FILTER_EQUAL: {
- const float threshold_squared = row_filter.threshold * row_filter.threshold;
- apply_filter_operation(
- values,
- [value, threshold_squared](const CellValue &cell_value) -> bool {
- return float2::distance_squared(*cell_value.value_float2, value) <
- threshold_squared;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_GREATER: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return cell_value.value_float2->x > value.x &&
- cell_value.value_float2->y > value.y;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_LESS: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return cell_value.value_float2->x < value.x &&
- cell_value.value_float2->y < value.y;
- },
- rows_included);
- break;
- }
- }
+ case SPREADSHEET_ROW_FILTER_LESS: {
+ apply_filter_operation(
+ column_data.typed<int>(),
+ [&](const int cell) { return cell < value; },
+ prev_mask,
+ new_indices);
break;
}
- case SPREADSHEET_VALUE_TYPE_FLOAT3: {
- const float3 value = row_filter.value_float3;
- switch (row_filter.operation) {
- case SPREADSHEET_ROW_FILTER_EQUAL: {
- const float threshold_squared = row_filter.threshold * row_filter.threshold;
- apply_filter_operation(
- values,
- [value, threshold_squared](const CellValue &cell_value) -> bool {
- return float3::distance_squared(*cell_value.value_float3, value) <
- threshold_squared;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_GREATER: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return cell_value.value_float3->x > value.x &&
- cell_value.value_float3->y > value.y &&
- cell_value.value_float3->z > value.z;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_LESS: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return cell_value.value_float3->x < value.x &&
- cell_value.value_float3->y < value.y &&
- cell_value.value_float3->z < value.z;
- },
- rows_included);
- break;
- }
- }
+ }
+ }
+ else if (column_data.type().is<float2>()) {
+ const float2 value = row_filter.value_float2;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ const float threshold_sq = row_filter.threshold;
+ apply_filter_operation(
+ column_data.typed<float2>(),
+ [&](const float2 cell) { return math::distance_squared(cell, value) > threshold_sq; },
+ prev_mask,
+ new_indices);
break;
}
- case SPREADSHEET_VALUE_TYPE_COLOR: {
- const ColorGeometry4f value = row_filter.value_color;
- switch (row_filter.operation) {
- case SPREADSHEET_ROW_FILTER_EQUAL: {
- const float threshold_squared = row_filter.threshold * row_filter.threshold;
- apply_filter_operation(
- values,
- [value, threshold_squared](const CellValue &cell_value) -> bool {
- return len_squared_v4v4(value, *cell_value.value_color) < threshold_squared;
- },
- rows_included);
- break;
- }
- }
+ case SPREADSHEET_ROW_FILTER_GREATER: {
+ apply_filter_operation(
+ column_data.typed<float2>(),
+ [&](const float2 cell) { return cell.x > value.x && cell.y > value.y; },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_LESS: {
+ apply_filter_operation(
+ column_data.typed<float2>(),
+ [&](const float2 cell) { return cell.x < value.x && cell.y < value.y; },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ }
+ }
+ else if (column_data.type().is<float3>()) {
+ const float3 value = row_filter.value_float3;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ const float threshold_sq = row_filter.threshold;
+ apply_filter_operation(
+ column_data.typed<float3>(),
+ [&](const float3 cell) { return math::distance_squared(cell, value) > threshold_sq; },
+ prev_mask,
+ new_indices);
break;
}
- case SPREADSHEET_VALUE_TYPE_BOOL: {
- const bool value = (row_filter.flag & SPREADSHEET_ROW_FILTER_BOOL_VALUE) != 0;
+ case SPREADSHEET_ROW_FILTER_GREATER: {
apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return *cell_value.value_bool == value;
+ column_data.typed<float3>(),
+ [&](const float3 cell) {
+ return cell.x > value.x && cell.y > value.y && cell.z > value.z;
},
- rows_included);
+ prev_mask,
+ new_indices);
break;
}
- case SPREADSHEET_VALUE_TYPE_INSTANCES: {
- const StringRef value = row_filter.value_string;
+ case SPREADSHEET_ROW_FILTER_LESS: {
apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- const ID *id = nullptr;
- if (cell_value.value_object) {
- id = &cell_value.value_object->object->id;
- }
- else if (cell_value.value_collection) {
- id = &cell_value.value_collection->collection->id;
- }
- if (id == nullptr) {
- return false;
- }
-
- return value == id->name + 2;
+ column_data.typed<float3>(),
+ [&](const float3 cell) {
+ return cell.x < value.x && cell.y < value.y && cell.z < value.z;
},
- rows_included);
+ prev_mask,
+ new_indices);
break;
}
- default:
+ }
+ }
+ else if (column_data.type().is<ColorGeometry4f>()) {
+ const ColorGeometry4f value = row_filter.value_color;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ const float threshold_sq = row_filter.threshold;
+ apply_filter_operation(
+ column_data.typed<ColorGeometry4f>(),
+ [&](const ColorGeometry4f cell) {
+ return len_squared_v4v4(cell, value) > threshold_sq;
+ },
+ prev_mask,
+ new_indices);
break;
+ }
}
-
- /* Only one column should have this name. */
- break;
}
-}
-
-static void index_vector_from_bools(Span<bool> selection, Vector<int64_t> &indices)
-{
- for (const int i : selection.index_range()) {
- if (selection[i]) {
- indices.append(i);
+ else if (column_data.type().is<InstanceReference>()) {
+ const StringRef value = row_filter.value_string;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ apply_filter_operation(
+ column_data.typed<InstanceReference>(),
+ [&](const InstanceReference cell) {
+ switch (cell.type()) {
+ case InstanceReference::Type::Object: {
+ return value == (reinterpret_cast<ID &>(cell.object()).name + 2);
+ }
+ case InstanceReference::Type::Collection: {
+ return value == (reinterpret_cast<ID &>(cell.collection()).name + 2);
+ }
+ case InstanceReference::Type::GeometrySet: {
+ return false;
+ }
+ case InstanceReference::Type::None: {
+ return false;
+ }
+ }
+ BLI_assert_unreachable();
+ return false;
+ },
+ prev_mask,
+ new_indices);
+ break;
+ }
}
}
}
@@ -297,10 +251,10 @@ static bool use_selection_filter(const SpaceSpreadsheet &sspreadsheet,
return true;
}
-Span<int64_t> spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet,
- const SpreadsheetLayout &spreadsheet_layout,
- const DataSource &data_source,
- ResourceScope &scope)
+IndexMask spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet,
+ const SpreadsheetLayout &spreadsheet_layout,
+ const DataSource &data_source,
+ ResourceScope &scope)
{
const int tot_rows = data_source.tot_rows();
@@ -309,35 +263,51 @@ Span<int64_t> spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet,
/* Avoid allocating an array if no row filtering is necessary. */
if (!(use_filters || use_selection)) {
- return IndexRange(tot_rows).as_span();
+ return IndexMask(tot_rows);
}
- Array<bool> rows_included(tot_rows, true);
+ IndexMask mask(tot_rows);
+
+ Vector<int64_t> mask_indices;
+ mask_indices.reserve(tot_rows);
+
+ if (use_selection) {
+ const GeometryDataSource *geometry_data_source = dynamic_cast<const GeometryDataSource *>(
+ &data_source);
+ mask = geometry_data_source->apply_selection_filter(mask_indices);
+ }
if (use_filters) {
+ Map<StringRef, const ColumnValues *> columns;
+ for (const ColumnLayout &column : spreadsheet_layout.columns) {
+ columns.add(column.values->name(), column.values);
+ }
+
LISTBASE_FOREACH (const SpreadsheetRowFilter *, row_filter, &sspreadsheet.row_filters) {
if (row_filter->flag & SPREADSHEET_ROW_FILTER_ENABLED) {
- apply_row_filter(spreadsheet_layout, *row_filter, rows_included);
+ if (!columns.contains(row_filter->column_name)) {
+ continue;
+ }
+ Vector<int64_t> new_indices;
+ new_indices.reserve(mask_indices.size());
+ apply_row_filter(*row_filter, columns, mask, new_indices);
+ std::swap(new_indices, mask_indices);
+ mask = IndexMask(mask_indices);
}
}
}
- if (use_selection) {
- const GeometryDataSource *geometry_data_source = dynamic_cast<const GeometryDataSource *>(
- &data_source);
- geometry_data_source->apply_selection_filter(rows_included);
+ if (mask_indices.is_empty()) {
+ BLI_assert(mask.is_empty() || mask.is_range());
+ return mask;
}
- Vector<int64_t> &indices = scope.construct<Vector<int64_t>>();
- index_vector_from_bools(rows_included, indices);
-
- return indices;
+ return IndexMask(scope.add_value(std::move(mask_indices)));
}
SpreadsheetRowFilter *spreadsheet_row_filter_new()
{
- SpreadsheetRowFilter *row_filter = (SpreadsheetRowFilter *)MEM_callocN(
- sizeof(SpreadsheetRowFilter), __func__);
+ SpreadsheetRowFilter *row_filter = MEM_cnew<SpreadsheetRowFilter>(__func__);
row_filter->flag = (SPREADSHEET_ROW_FILTER_UI_EXPAND | SPREADSHEET_ROW_FILTER_ENABLED);
row_filter->operation = SPREADSHEET_ROW_FILTER_LESS;
row_filter->threshold = 0.01f;
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh
index 0a5783e318d..3788baaa993 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh
@@ -23,10 +23,10 @@
namespace blender::ed::spreadsheet {
-Span<int64_t> spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet,
- const SpreadsheetLayout &spreadsheet_layout,
- const DataSource &data_source,
- ResourceScope &scope);
+IndexMask spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet,
+ const SpreadsheetLayout &spreadsheet_layout,
+ const DataSource &data_source,
+ ResourceScope &scope);
SpreadsheetRowFilter *spreadsheet_row_filter_new();
SpreadsheetRowFilter *spreadsheet_row_filter_copy(const SpreadsheetRowFilter *src_row_filter);
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
index a07abac4474..56722104b4f 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
@@ -114,6 +114,8 @@ static std::string value_string(const SpreadsheetRowFilter &row_filter,
}
case SPREADSHEET_VALUE_TYPE_STRING:
return row_filter.value_string;
+ case SPREADSHEET_VALUE_TYPE_UNKNOWN:
+ return "";
}
BLI_assert_unreachable();
return "";
@@ -238,6 +240,10 @@ static void spreadsheet_filter_panel_draw(const bContext *C, Panel *panel)
uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE);
break;
case SPREADSHEET_VALUE_TYPE_STRING:
+ uiItemR(layout, filter_ptr, "value_string", 0, IFACE_("Value"), ICON_NONE);
+ break;
+ case SPREADSHEET_VALUE_TYPE_UNKNOWN:
+ uiItemL(layout, IFACE_("Unkown column type"), ICON_ERROR);
break;
}
}
@@ -325,7 +331,7 @@ static void set_filter_expand_flag(const bContext *UNUSED(C), Panel *panel, shor
void register_row_filter_panels(ARegionType &region_type)
{
{
- PanelType *panel_type = (PanelType *)MEM_callocN(sizeof(PanelType), __func__);
+ PanelType *panel_type = MEM_cnew<PanelType>(__func__);
strcpy(panel_type->idname, "SPREADSHEET_PT_row_filters");
strcpy(panel_type->label, N_("Filters"));
strcpy(panel_type->category, "Filters");
@@ -336,7 +342,7 @@ void register_row_filter_panels(ARegionType &region_type)
}
{
- PanelType *panel_type = (PanelType *)MEM_callocN(sizeof(PanelType), __func__);
+ PanelType *panel_type = MEM_cnew<PanelType>(__func__);
strcpy(panel_type->idname, "SPREADSHEET_PT_filter");
strcpy(panel_type->label, "");
strcpy(panel_type->category, "Filters");
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index f449ce50ae3..7339d8248c8 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -32,6 +32,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_remap.h"
#include "BKE_screen.h"
#include "ED_screen.h"
@@ -401,18 +402,12 @@ static void text_properties_region_draw(const bContext *C, ARegion *region)
}
}
-static void text_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void text_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceText *stext = (SpaceText *)slink;
-
- if (!ELEM(GS(old_id->name), ID_TXT)) {
- return;
- }
-
- if ((ID *)stext->text == old_id) {
- stext->text = (Text *)new_id;
- id_us_ensure_real(new_id);
- }
+ BKE_id_remapper_apply(mappings, (ID **)&stext->text, ID_REMAP_APPLY_ENSURE_REAL);
}
/********************* registration ********************/
diff --git a/source/blender/editors/space_text/text_format.h b/source/blender/editors/space_text/text_format.h
index 01c40b4ed22..ebccaa54342 100644
--- a/source/blender/editors/space_text/text_format.h
+++ b/source/blender/editors/space_text/text_format.h
@@ -66,12 +66,12 @@ int text_check_format_len(TextLine *line, unsigned int len);
*
* \param len: length in bytes of \a fmt_p to fill.
*/
-void text_format_fill(const char **str_p, char **fmt_p, const char type, const int len);
+void text_format_fill(const char **str_p, char **fmt_p, char type, int len);
/**
* ASCII version of #text_format_fill,
* use when we no the text being stepped over is ascii (as is the case for most keywords)
*/
-void text_format_fill_ascii(const char **str_p, char **fmt_p, const char type, const int len);
+void text_format_fill_ascii(const char **str_p, char **fmt_p, char type, int len);
/* *** Generalize Formatting *** */
typedef struct TextFormatType {
@@ -88,7 +88,7 @@ typedef struct TextFormatType {
*
* See: FMT_TYPE_ enums below
*/
- void (*format_line)(SpaceText *st, TextLine *line, const bool do_next);
+ void (*format_line)(SpaceText *st, TextLine *line, bool do_next);
const char **ext; /* NULL terminated extensions */
} TextFormatType;
diff --git a/source/blender/editors/space_text/text_intern.h b/source/blender/editors/space_text/text_intern.h
index 3cae4188932..0b81cd74a42 100644
--- a/source/blender/editors/space_text/text_intern.h
+++ b/source/blender/editors/space_text/text_intern.h
@@ -42,7 +42,7 @@ void text_update_character_width(struct SpaceText *st);
/**
* Takes an area instead of a region, use for listeners.
*/
-void text_scroll_to_cursor__area(struct SpaceText *st, struct ScrArea *area, const bool center);
+void text_scroll_to_cursor__area(struct SpaceText *st, struct ScrArea *area, bool center);
void text_update_cursor_moved(struct bContext *C);
/* Padding around line numbers in character widths. */
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index 3c0ffa29bbd..430ffe6d56f 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -796,7 +796,7 @@ static int text_run_script(bContext *C, ReportList *reports)
/* Don't report error messages while live editing */
if (!is_live) {
- /* text may have freed its self */
+ /* text may have freed itself */
if (CTX_data_edit_text(C) == text) {
if (text->curl != curl_prev || curc_prev != text->curc) {
text_update_cursor_moved(C);
diff --git a/source/blender/editors/space_topbar/space_topbar.c b/source/blender/editors/space_topbar/space_topbar.c
index 41eddd32854..82a0de9b845 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,64 @@ 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;
+ int undo_step_count_all = 0;
+ for (UndoStep *us = wm->undo_stack->steps.last; us; us = us->prev) {
+ undo_step_count_all += 1;
+ 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);
+
+ undo_step_count = 0;
+
+ /* Reverse the order so the most recent state is first in the menu. */
+ int i = undo_step_count_all - 1;
+ for (UndoStep *us = wm->undo_stack->steps.last; us; us = us->prev, 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 +337,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_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c
index 1711188fca7..b1ee6da1a33 100644
--- a/source/blender/editors/space_userpref/space_userpref.c
+++ b/source/blender/editors/space_userpref/space_userpref.c
@@ -113,9 +113,9 @@ static SpaceLink *userpref_duplicate(SpaceLink *sl)
/* add handlers, stuff you only do once or on area/region changes */
static void userpref_main_region_init(wmWindowManager *wm, ARegion *region)
{
- /* do not use here, the properties changed in userprefs do a system-wide refresh,
+ /* do not use here, the properties changed in user-preferences do a system-wide refresh,
* then scroller jumps back */
- /* region->v2d.flag &= ~V2D_IS_INIT; */
+ // region->v2d.flag &= ~V2D_IS_INIT;
region->v2d.scroll = V2D_SCROLL_RIGHT | V2D_SCROLL_VERTICAL_HIDE;
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 8822ea6af3b..0a5bebac8a8 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -48,6 +48,7 @@
#include "BKE_idprop.h"
#include "BKE_lattice.h"
#include "BKE_layer.h"
+#include "BKE_lib_remap.h"
#include "BKE_main.h"
#include "BKE_mball.h"
#include "BKE_mesh.h"
@@ -1813,50 +1814,54 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes
return CTX_RESULT_MEMBER_NOT_FOUND;
}
-static void view3d_id_remap(ScrArea *area, SpaceLink *slink, ID *old_id, ID *new_id)
+static void view3d_id_remap_v3d_ob_centers(View3D *v3d, const struct IDRemapper *mappings)
{
- View3D *v3d;
- ARegion *region;
- bool is_local = false;
-
- if (!ELEM(GS(old_id->name), ID_OB, ID_MA, ID_IM, ID_MC)) {
- return;
+ if (BKE_id_remapper_apply(mappings, (ID **)&v3d->ob_center, ID_REMAP_APPLY_DEFAULT) ==
+ ID_REMAP_RESULT_SOURCE_UNASSIGNED) {
+ /* Otherwise, bonename may remain valid...
+ * We could be smart and check this, too? */
+ v3d->ob_center_bone[0] = '\0';
}
+}
- for (v3d = (View3D *)slink; v3d; v3d = v3d->localvd, is_local = true) {
- if ((ID *)v3d->camera == old_id) {
- v3d->camera = (Object *)new_id;
- if (!new_id) {
- /* 3D view might be inactive, in that case needs to use slink->regionbase */
- ListBase *regionbase = (slink == area->spacedata.first) ? &area->regionbase :
- &slink->regionbase;
- for (region = regionbase->first; region; region = region->next) {
- if (region->regiontype == RGN_TYPE_WINDOW) {
- RegionView3D *rv3d = is_local ? ((RegionView3D *)region->regiondata)->localvd :
- region->regiondata;
- if (rv3d && (rv3d->persp == RV3D_CAMOB)) {
- rv3d->persp = RV3D_PERSP;
- }
- }
+static void view3d_id_remap_v3d(ScrArea *area,
+ SpaceLink *slink,
+ View3D *v3d,
+ const struct IDRemapper *mappings,
+ const bool is_local)
+{
+ ARegion *region;
+ if (BKE_id_remapper_apply(mappings, (ID **)&v3d->camera, ID_REMAP_APPLY_DEFAULT) ==
+ ID_REMAP_RESULT_SOURCE_UNASSIGNED) {
+ /* 3D view might be inactive, in that case needs to use slink->regionbase */
+ ListBase *regionbase = (slink == area->spacedata.first) ? &area->regionbase :
+ &slink->regionbase;
+ for (region = regionbase->first; region; region = region->next) {
+ if (region->regiontype == RGN_TYPE_WINDOW) {
+ RegionView3D *rv3d = is_local ? ((RegionView3D *)region->regiondata)->localvd :
+ region->regiondata;
+ if (rv3d && (rv3d->persp == RV3D_CAMOB)) {
+ rv3d->persp = RV3D_PERSP;
}
}
}
+ }
+}
- /* Values in local-view aren't used, see: T52663 */
- if (is_local == false) {
- if ((ID *)v3d->ob_center == old_id) {
- v3d->ob_center = (Object *)new_id;
- /* Otherwise, bonename may remain valid...
- * We could be smart and check this, too? */
- if (new_id == NULL) {
- v3d->ob_center_bone[0] = '\0';
- }
- }
- }
+static void view3d_id_remap(ScrArea *area, SpaceLink *slink, const struct IDRemapper *mappings)
+{
- if (is_local) {
- break;
- }
+ if (!BKE_id_remapper_has_mapping_for(
+ mappings, FILTER_ID_OB | FILTER_ID_MA | FILTER_ID_IM | FILTER_ID_MC)) {
+ return;
+ }
+
+ View3D *view3d = (View3D *)slink;
+ view3d_id_remap_v3d(area, slink, view3d, mappings, false);
+ view3d_id_remap_v3d_ob_centers(view3d, mappings);
+ if (view3d->localvd != NULL) {
+ /* Object centers in local-view aren't used, see: T52663 */
+ view3d_id_remap_v3d(area, slink, view3d->localvd, mappings, true);
}
}
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index b79303551a1..243d4033cbc 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -87,7 +87,7 @@ typedef struct {
} TransformMedian_Generic;
typedef struct {
- float location[3], bv_weight, be_weight, skin[2], crease;
+ float location[3], bv_weight, v_crease, be_weight, skin[2], e_crease;
} TransformMedian_Mesh;
typedef struct {
@@ -319,6 +319,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
BMIter iter;
const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
+ const int cd_vert_crease_offset = CustomData_get_offset(&bm->vdata, CD_CREASE);
const int cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
@@ -335,6 +336,10 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
median->bv_weight += BM_ELEM_CD_GET_FLOAT(eve, cd_vert_bweight_offset);
}
+ if (cd_vert_crease_offset != -1) {
+ median->v_crease += BM_ELEM_CD_GET_FLOAT(eve, cd_vert_crease_offset);
+ }
+
if (has_skinradius) {
MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset);
add_v2_v2(median->skin, vs->radius); /* Third val not used currently. */
@@ -352,7 +357,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
}
if (cd_edge_crease_offset != -1) {
- median->crease += BM_ELEM_CD_GET_FLOAT(eed, cd_edge_crease_offset);
+ median->e_crease += BM_ELEM_CD_GET_FLOAT(eed, cd_edge_crease_offset);
}
totedgedata++;
@@ -489,11 +494,12 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
if (has_meshdata) {
TransformMedian_Mesh *median = &median_basis.mesh;
if (totedgedata) {
- median->crease /= (float)totedgedata;
+ median->e_crease /= (float)totedgedata;
median->be_weight /= (float)totedgedata;
}
if (tot) {
median->bv_weight /= (float)tot;
+ median->v_crease /= (float)tot;
if (has_skinradius) {
median->skin[0] /= (float)tot;
median->skin[1] /= (float)tot;
@@ -683,6 +689,23 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
TIP_("Vertex weight used by Bevel modifier"));
UI_but_number_step_size_set(but, 1);
UI_but_number_precision_set(but, 2);
+ /* customdata layer added on demand */
+ but = uiDefButF(block,
+ UI_BTYPE_NUM,
+ B_TRANSFORM_PANEL_MEDIAN,
+ tot == 1 ? IFACE_("Vertex Crease:") : IFACE_("Mean Vertex Crease:"),
+ 0,
+ yi -= buth + but_margin,
+ butw,
+ buth,
+ &ve_median->v_crease,
+ 0.0,
+ 1.0,
+ 0,
+ 0,
+ TIP_("Weight used by the Subdivision Surface modifier"));
+ UI_but_number_step_size_set(but, 1);
+ UI_but_number_precision_set(but, 2);
}
if (has_skinradius) {
UI_block_align_begin(block);
@@ -761,7 +784,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
yi -= buth + but_margin,
butw,
buth,
- &ve_median->crease,
+ &ve_median->e_crease,
0.0,
1.0,
0,
@@ -958,8 +981,9 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
const bool apply_vcos = (tot == 1) || (len_squared_v3(median_basis.generic.location) != 0.0f);
if ((ob->type == OB_MESH) &&
- (apply_vcos || median_basis.mesh.bv_weight || median_basis.mesh.skin[0] ||
- median_basis.mesh.skin[1] || median_basis.mesh.be_weight || median_basis.mesh.crease)) {
+ (apply_vcos || median_basis.mesh.bv_weight || median_basis.mesh.v_crease ||
+ median_basis.mesh.skin[0] || median_basis.mesh.skin[1] || median_basis.mesh.be_weight ||
+ median_basis.mesh.e_crease)) {
const TransformMedian_Mesh *median = &median_basis.mesh, *ve_median = &ve_median_basis.mesh;
Mesh *me = ob->data;
BMEditMesh *em = me->edit_mesh;
@@ -969,18 +993,21 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
BMEdge *eed;
int cd_vert_bweight_offset = -1;
+ int cd_vert_crease_offset = -1;
int cd_vert_skin_offset = -1;
int cd_edge_bweight_offset = -1;
int cd_edge_crease_offset = -1;
float scale_bv_weight = 1.0f;
+ float scale_v_crease = 1.0f;
float scale_skin[2] = {1.0f, 1.0f};
float scale_be_weight = 1.0f;
- float scale_crease = 1.0f;
+ float scale_e_crease = 1.0f;
/* Vertices */
- if (apply_vcos || median->bv_weight || median->skin[0] || median->skin[1]) {
+ if (apply_vcos || median->bv_weight || median->v_crease || median->skin[0] ||
+ median->skin[1]) {
if (median->bv_weight) {
BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_BWEIGHT);
cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
@@ -989,6 +1016,14 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
scale_bv_weight = compute_scale_factor(ve_median->bv_weight, median->bv_weight);
}
+ if (median->v_crease) {
+ BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_CREASE);
+ cd_vert_crease_offset = CustomData_get_offset(&bm->vdata, CD_CREASE);
+ BLI_assert(cd_vert_crease_offset != -1);
+
+ scale_v_crease = compute_scale_factor(ve_median->v_crease, median->v_crease);
+ }
+
for (int i = 0; i < 2; i++) {
if (median->skin[i]) {
cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
@@ -1011,6 +1046,11 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
apply_scale_factor_clamp(b_weight, tot, ve_median->bv_weight, scale_bv_weight);
}
+ if (cd_vert_crease_offset != -1) {
+ float *crease = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_crease_offset);
+ apply_scale_factor_clamp(crease, tot, ve_median->v_crease, scale_v_crease);
+ }
+
if (cd_vert_skin_offset != -1) {
MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset);
@@ -1033,7 +1073,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
/* Edges */
- if (median->be_weight || median->crease) {
+ if (median->be_weight || median->e_crease) {
if (median->be_weight) {
BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_BWEIGHT);
cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
@@ -1042,12 +1082,12 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
scale_be_weight = compute_scale_factor(ve_median->be_weight, median->be_weight);
}
- if (median->crease) {
+ if (median->e_crease) {
BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_CREASE);
cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
BLI_assert(cd_edge_crease_offset != -1);
- scale_crease = compute_scale_factor(ve_median->crease, median->crease);
+ scale_e_crease = compute_scale_factor(ve_median->e_crease, median->e_crease);
}
BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
@@ -1057,9 +1097,9 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
apply_scale_factor_clamp(b_weight, tot, ve_median->be_weight, scale_be_weight);
}
- if (median->crease != 0.0f) {
+ if (median->e_crease != 0.0f) {
float *crease = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_crease_offset);
- apply_scale_factor_clamp(crease, tot, ve_median->crease, scale_crease);
+ apply_scale_factor_clamp(crease, tot, ve_median->e_crease, scale_e_crease);
}
}
}
@@ -1552,7 +1592,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_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index a7d170982ed..b1f19581543 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -1581,6 +1581,7 @@ void view3d_main_region_draw(const bContext *C, ARegion *region)
view3d_draw_view(C, region);
+ DRW_cache_free_old_subdiv();
DRW_cache_free_old_batches(bmain);
BKE_image_free_old_gputextures(bmain);
GPU_pass_cache_garbage_collect();
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/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index 7388004125c..6a1a09df316 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -115,8 +115,8 @@ struct wmNDOFMotionData;
void view3d_ndof_fly(const struct wmNDOFMotionData *ndof,
struct View3D *v3d,
struct RegionView3D *rv3d,
- const bool use_precision,
- const short protectflag,
+ bool use_precision,
+ short protectflag,
bool *r_has_translate,
bool *r_has_rotate);
#endif /* WITH_INPUT_NDOF */
@@ -203,13 +203,13 @@ void ED_view3d_smooth_view_ex(const struct Depsgraph *depsgraph,
struct ScrArea *area,
struct View3D *v3d,
struct ARegion *region,
- const int smooth_viewtx,
+ int smooth_viewtx,
const V3D_SmoothParams *sview);
void ED_view3d_smooth_view(struct bContext *C,
struct View3D *v3d,
struct ARegion *region,
- const int smooth_viewtx,
+ int smooth_viewtx,
const V3D_SmoothParams *sview);
/**
@@ -274,17 +274,17 @@ struct View3DCameraControl *ED_view3d_cameracontrol_acquire(struct Depsgraph *de
* Updates cameras from the `rv3d` values, optionally auto-keyframing.
*/
void ED_view3d_cameracontrol_update(struct View3DCameraControl *vctrl,
- const bool use_autokey,
+ bool use_autokey,
struct bContext *C,
- const bool do_rotate,
- const bool do_translate);
+ bool do_rotate,
+ bool do_translate);
/**
* Release view control.
*
* \param restore: Sets the view state to the values that were set
* before #ED_view3d_control_acquire was called.
*/
-void ED_view3d_cameracontrol_release(struct View3DCameraControl *vctrl, const bool restore);
+void ED_view3d_cameracontrol_release(struct View3DCameraControl *vctrl, bool restore);
/**
* Returns the object which is being manipulated or NULL.
*/
diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c
index 16d9b9182cf..990b4fc85b1 100644
--- a/source/blender/editors/space_view3d/view3d_iterators.c
+++ b/source/blender/editors/space_view3d/view3d_iterators.c
@@ -272,8 +272,7 @@ typedef struct foreachScreenFace_userData {
static void meshobject_foreachScreenVert__mapFunc(void *userData,
int index,
const float co[3],
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
foreachScreenObjectVert_userData *data = userData;
struct MVert *mv = &((Mesh *)(data->vc.obact->data))->mvert[index];
@@ -322,8 +321,7 @@ void meshobject_foreachScreenVert(
static void mesh_foreachScreenVert__mapFunc(void *userData,
int index,
const float co[3],
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
foreachScreenVert_userData *data = userData;
BMVert *eve = BM_vert_at_index(data->vc.em->bm, index);
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index cc8aac21a6e..45899880b41 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -4040,7 +4040,9 @@ static bool lattice_circle_select(ViewContext *vc,
return data.is_changed;
}
-/* NOTE: pose-bone case is copied from editbone case... */
+/**
+ * \note logic is shared with the edit-bone case, see #armature_circle_doSelectJoint.
+ */
static bool pchan_circle_doSelectJoint(void *userData,
bPoseChannel *pchan,
const float screen_co[2])
@@ -4137,6 +4139,9 @@ static bool pose_circle_select(ViewContext *vc,
return data.is_changed;
}
+/**
+ * \note logic is shared with the pose-bone case, see #pchan_circle_doSelectJoint.
+ */
static bool armature_circle_doSelectJoint(void *userData,
EditBone *ebone,
const float screen_co[2],
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 3035d11d0e3..642de550812 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -712,9 +712,9 @@ int transformEnd(struct bContext *C, TransInfo *t);
void setTransformViewMatrices(TransInfo *t);
void setTransformViewAspect(TransInfo *t, float r_aspect[3]);
void convertViewVec(TransInfo *t, float r_vec[3], double dx, double dy);
-void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DProjTest flag);
+void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], eV3DProjTest flag);
void projectIntView(TransInfo *t, const float vec[3], int adr[2]);
-void projectFloatViewEx(TransInfo *t, const float vec[3], float adr[2], const eV3DProjTest flag);
+void projectFloatViewEx(TransInfo *t, const float vec[3], float adr[2], eV3DProjTest flag);
void projectFloatView(TransInfo *t, const float vec[3], float adr[2]);
void applyAspectRatio(TransInfo *t, float vec[2]);
@@ -770,7 +770,7 @@ typedef enum {
} MouseInputMode;
void initMouseInput(
- TransInfo *t, MouseInput *mi, const float center[2], const int mval[2], const bool precision);
+ TransInfo *t, MouseInput *mi, const float center[2], const int mval[2], bool precision);
void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode);
void applyMouseInput(struct TransInfo *t,
struct MouseInput *mi,
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..c40f3c28a79 100644
--- a/source/blender/editors/transform/transform_convert.h
+++ b/source/blender/editors/transform/transform_convert.h
@@ -48,9 +48,9 @@ int special_transform_moving(TransInfo *t);
void special_aftertrans_update(struct bContext *C, TransInfo *t);
void sort_trans_data_dist(TransInfo *t);
void createTransData(struct bContext *C, TransInfo *t);
-bool clipUVTransform(TransInfo *t, float vec[2], const bool resize);
+bool clipUVTransform(TransInfo *t, float vec[2], bool resize);
void clipUVData(TransInfo *t);
-void transform_convert_flush_handle2D(TransData *td, TransData2D *td2d, const float y_fac);
+void transform_convert_flush_handle2D(TransData *td, TransData2D *td2d, float y_fac);
/**
* Called for updating while transform acts, once per redraw.
*/
@@ -83,7 +83,7 @@ void transform_around_single_fallback(TransInfo *t);
* but may want to use a different one at times (if caller does not operate on
* selection).
*/
-void posttrans_fcurve_clean(struct FCurve *fcu, const int sel_flag, const bool use_handle);
+void posttrans_fcurve_clean(struct FCurve *fcu, int sel_flag, bool use_handle);
/**
* Little helper function for ObjectToTransData used to give certain
* constraints (ChildOf, FollowPath, and others that may be added)
@@ -125,8 +125,8 @@ void special_aftertrans_update__actedit(bContext *C, TransInfo *t);
* Returns total number of bones with #BONE_TRANSFORM.
*/
int transform_convert_pose_transflags_update(Object *ob,
- const int mode,
- const short around,
+ int mode,
+ short around,
bool has_translate_rotate[2]);
/**
* When objects array is NULL, use 't->data_container' as is.
@@ -208,9 +208,9 @@ struct TransMeshDataCrazySpace {
};
void transform_convert_mesh_islands_calc(struct BMEditMesh *em,
- const bool calc_single_islands,
- const bool calc_island_center,
- const bool calc_island_axismtx,
+ bool calc_single_islands,
+ bool calc_island_center,
+ bool calc_island_axismtx,
struct TransIslandData *r_island_data);
void transform_convert_mesh_islanddata_free(struct TransIslandData *island_data);
/**
@@ -223,8 +223,8 @@ void transform_convert_mesh_connectivity_distance(struct BMesh *bm,
float *dists,
int *index);
void transform_convert_mesh_mirrordata_calc(struct BMEditMesh *em,
- const bool use_select,
- const bool use_topology,
+ bool use_select,
+ bool use_topology,
const bool mirror_axis[3],
struct TransMirrorData *r_mirror_data);
void transform_convert_mesh_mirrordata_free(struct TransMirrorData *mirror_data);
@@ -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_curve.c b/source/blender/editors/transform/transform_convert_curve.c
index 255af3feca2..924e51a2b41 100644
--- a/source/blender/editors/transform/transform_convert_curve.c
+++ b/source/blender/editors/transform/transform_convert_curve.c
@@ -357,26 +357,6 @@ void createTransCurveVerts(TransInfo *t)
for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
if (bp->hide == 0) {
if (is_prop_edit || (bp->f1 & SELECT)) {
- float axismtx[3][3];
-
- if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
- if (nu->pntsv == 1) {
- float normal[3], plane[3];
-
- BKE_nurb_bpoint_calc_normal(nu, bp, normal);
- BKE_nurb_bpoint_calc_plane(nu, bp, plane);
-
- if (createSpaceNormalTangent(axismtx, normal, plane)) {
- /* pass */
- }
- else {
- normalize_v3(normal);
- axis_dominant_v3_to_m3(axismtx, normal);
- invert_m3(axismtx);
- }
- }
- }
-
copy_v3_v3(td->iloc, bp->vec);
td->loc = bp->vec;
copy_v3_v3(td->center, td->loc);
@@ -400,9 +380,22 @@ void createTransCurveVerts(TransInfo *t)
copy_m3_m3(td->smtx, smtx);
copy_m3_m3(td->mtx, mtx);
+
if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
if (nu->pntsv == 1) {
- copy_m3_m3(td->axismtx, axismtx);
+ float normal[3], plane[3];
+
+ BKE_nurb_bpoint_calc_normal(nu, bp, normal);
+ BKE_nurb_bpoint_calc_plane(nu, bp, plane);
+
+ if (createSpaceNormalTangent(td->axismtx, normal, plane)) {
+ /* pass */
+ }
+ else {
+ normalize_v3(normal);
+ axis_dominant_v3_to_m3(td->axismtx, normal);
+ invert_m3(td->axismtx);
+ }
}
}
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_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
index c3d95e1ad98..e00522f0f88 100644
--- a/source/blender/editors/transform/transform_convert_mesh.c
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -1465,7 +1465,7 @@ static void VertsToTransData(TransInfo *t,
td->ext = NULL;
td->val = NULL;
td->extra = eve;
- if (t->mode == TFM_BWEIGHT) {
+ if (t->mode == TFM_BWEIGHT || t->mode == TFM_VERT_CREASE) {
td->val = bweight;
td->ival = *bweight;
}
@@ -1606,10 +1606,15 @@ void createTransEditVerts(TransInfo *t)
}
int cd_vert_bweight_offset = -1;
+ int cd_vert_crease_offset = -1;
if (t->mode == TFM_BWEIGHT) {
BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_BWEIGHT);
cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
}
+ else if (t->mode == TFM_VERT_CREASE) {
+ BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_CREASE);
+ cd_vert_crease_offset = CustomData_get_offset(&bm->vdata, CD_CREASE);
+ }
TransData *tob = tc->data;
TransDataMirror *td_mirror = tc->data_mirror;
@@ -1645,6 +1650,8 @@ void createTransEditVerts(TransInfo *t)
else if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
float *bweight = (cd_vert_bweight_offset != -1) ?
BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) :
+ (cd_vert_crease_offset != -1) ?
+ BM_ELEM_CD_GET_VOID_P(eve, cd_vert_crease_offset) :
NULL;
/* Do not use the island center in case we are using islands
diff --git a/source/blender/editors/transform/transform_convert_mesh_edge.c b/source/blender/editors/transform/transform_convert_mesh_edge.c
index 2db3e259153..2243f66cc7f 100644
--- a/source/blender/editors/transform/transform_convert_mesh_edge.c
+++ b/source/blender/editors/transform/transform_convert_mesh_edge.c
@@ -86,8 +86,8 @@ void createTransEdge(TransInfo *t)
BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_BWEIGHT);
cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_BWEIGHT);
}
- else { /* if (t->mode == TFM_CREASE) { */
- BLI_assert(t->mode == TFM_CREASE);
+ else { /* if (t->mode == TFM_EDGE_CREASE) { */
+ BLI_assert(t->mode == TFM_EDGE_CREASE);
BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_CREASE);
cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_CREASE);
}
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.c b/source/blender/editors/transform/transform_convert_sequencer.c
index 88c01321785..01eae36e846 100644
--- a/source/blender/editors/transform/transform_convert_sequencer.c
+++ b/source/blender/editors/transform/transform_convert_sequencer.c
@@ -34,6 +34,7 @@
#include "ED_markers.h"
+#include "SEQ_animation.h"
#include "SEQ_edit.h"
#include "SEQ_effects.h"
#include "SEQ_iterator.h"
@@ -302,7 +303,7 @@ static SeqCollection *extract_standalone_strips(SeqCollection *transformed_strip
return collection;
}
-/* Query strips positioned after left edge of transformed strips boundbox. */
+/* Query strips positioned after left edge of transformed strips bound-box. */
static SeqCollection *query_right_side_strips(ListBase *seqbase, SeqCollection *transformed_strips)
{
int minframe = MAXFRAME;
@@ -351,7 +352,7 @@ static ListBase *seqbase_active_get(const TransInfo *t)
return SEQ_active_seqbase_get(ed);
}
-/* Offset all strips positioned after left edge of transformed strips boundbox by amount equal
+/* Offset all strips positioned after left edge of transformed strips bound-box by amount equal
* to overlap of transformed strips. */
static void seq_transform_handle_expand_to_fit(TransInfo *t, SeqCollection *transformed_strips)
{
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_data.h b/source/blender/editors/transform/transform_data.h
index 6cfceedb389..a78c2491a1a 100644
--- a/source/blender/editors/transform/transform_data.h
+++ b/source/blender/editors/transform/transform_data.h
@@ -27,8 +27,8 @@ struct Object;
struct bConstraint;
#define TRANSDATABASIC \
- /** Extra data (mirrored element pointer, in editmode mesh to BMVert) \
- * (editbone for roll fixing) (...). */ \
+ /** Extra data (mirrored element pointer, in edit-mode mesh to #BMVert) \
+ * (edit-bone for roll fixing) (...). */ \
void *extra; \
/** Location of the data to transform. */ \
float *loc; \
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index c2ff095904d..d1cbab9ff8a 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -214,7 +214,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->flag = 0;
- if (obact && ELEM(object_mode, OB_MODE_EDIT, OB_MODE_EDIT_GPENCIL)) {
+ if (obact && !(t->options & (CTX_CURSOR | CTX_TEXTURE_SPACE)) &&
+ ELEM(object_mode, OB_MODE_EDIT, OB_MODE_EDIT_GPENCIL)) {
t->obedit_type = obact->type;
}
else {
@@ -259,7 +260,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
/* Crease needs edge flag */
- if (ELEM(t->mode, TFM_CREASE, TFM_BWEIGHT)) {
+ if (ELEM(t->mode, TFM_EDGE_CREASE, TFM_BWEIGHT)) {
t->options |= CTX_EDGE_DATA;
}
diff --git a/source/blender/editors/transform/transform_gizmo_extrude_3d.c b/source/blender/editors/transform/transform_gizmo_extrude_3d.c
index 6e89c3de197..dee6e7281ef 100644
--- a/source/blender/editors/transform/transform_gizmo_extrude_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_extrude_3d.c
@@ -82,6 +82,7 @@ typedef struct GizmoExtrudeGroup {
float orient_matrix[3][3];
bool constraint_axis[3];
float value[4];
+ int orient_type;
} redo_xform;
/* Depends on object type. */
@@ -310,6 +311,7 @@ static void gizmo_mesh_extrude_refresh(const bContext *C, wmGizmoGroup *gzgroup)
RNA_float_get_array(op_xform->ptr, "orient_matrix", &ggd->redo_xform.orient_matrix[0][0]);
RNA_boolean_get_array(op_xform->ptr, "constraint_axis", ggd->redo_xform.constraint_axis);
RNA_float_get_array(op_xform->ptr, "value", ggd->redo_xform.value);
+ ggd->redo_xform.orient_type = RNA_enum_get(op_xform->ptr, "orient_type");
/* Set properties for redo. */
for (int i = 0; i < 3; i++) {
@@ -435,7 +437,8 @@ static void gizmo_mesh_extrude_invoke_prepare(const bContext *UNUSED(C),
if (gz == ggd->adjust[0]) {
RNA_boolean_set_array(&macroptr, "constraint_axis", ggd->redo_xform.constraint_axis);
RNA_float_set_array(&macroptr, "orient_matrix", &ggd->redo_xform.orient_matrix[0][0]);
- RNA_enum_set(&macroptr, "orient_type", V3D_ORIENT_NORMAL);
+ RNA_enum_set(&macroptr, "orient_matrix_type", ggd->redo_xform.orient_type);
+ RNA_enum_set(&macroptr, "orient_type", ggd->redo_xform.orient_type);
}
RNA_float_set_array(&macroptr, "value", ggd->redo_xform.value);
}
diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c
index d2e7f9f83df..e1fea62ae54 100644
--- a/source/blender/editors/transform/transform_mode.c
+++ b/source/blender/editors/transform/transform_mode.c
@@ -1042,7 +1042,7 @@ void ElementResize(const TransInfo *t,
applyNumInput(&num_evil, values_final_evil);
float ratio = values_final_evil[0];
- *td->val = td->ival * ratio * gps->runtime.multi_frame_falloff;
+ *td->val = td->ival * fabs(ratio) * gps->runtime.multi_frame_falloff;
CLAMP_MIN(*td->val, 0.001f);
}
}
@@ -1135,8 +1135,11 @@ void transform_mode_init(TransInfo *t, wmOperator *op, const int mode)
case TFM_PUSHPULL:
initPushPull(t);
break;
- case TFM_CREASE:
- initCrease(t);
+ case TFM_EDGE_CREASE:
+ initEgdeCrease(t);
+ break;
+ case TFM_VERT_CREASE:
+ initVertCrease(t);
break;
case TFM_BONESIZE:
initBoneSize(t);
diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h
index ec3d5b8d0fe..16b26724c67 100644
--- a/source/blender/editors/transform/transform_mode.h
+++ b/source/blender/editors/transform/transform_mode.h
@@ -45,7 +45,7 @@ bool transdata_check_local_center(const TransInfo *t, short around);
/**
* Informs if the mode can be switched during modal.
*/
-bool transform_mode_is_changeable(const int mode);
+bool transform_mode_is_changeable(int mode);
void protectedTransBits(short protectflag, float vec[3]);
void protectedSizeBits(short protectflag, float size[3]);
void constraintTransLim(const TransInfo *t, TransData *td);
@@ -69,13 +69,13 @@ void ElementRotation(const TransInfo *t,
const TransDataContainer *tc,
TransData *td,
const float mat[3][3],
- const short around);
+ short around);
void headerResize(TransInfo *t, const float vec[3], char *str, int str_size);
void ElementResize(const TransInfo *t,
const TransDataContainer *tc,
TransData *td,
const float mat[3][3]);
-void transform_mode_init(TransInfo *t, struct wmOperator *op, const int mode);
+void transform_mode_init(TransInfo *t, struct wmOperator *op, int mode);
/**
* When in modal and not set, initializes a default orientation for the mode.
*/
@@ -106,7 +106,8 @@ void initCurveShrinkFatten(TransInfo *t);
void initBevelWeight(TransInfo *t);
/* transform_mode_edge_crease.c */
-void initCrease(TransInfo *t);
+void initEgdeCrease(TransInfo *t);
+void initVertCrease(TransInfo *t);
/* transform_mode_edge_rotate_normal.c */
void initNormalRotation(TransInfo *t);
diff --git a/source/blender/editors/transform/transform_mode_edge_crease.c b/source/blender/editors/transform/transform_mode_edge_crease.c
index debc2a1be3e..60b95a1d2da 100644
--- a/source/blender/editors/transform/transform_mode_edge_crease.c
+++ b/source/blender/editors/transform/transform_mode_edge_crease.c
@@ -157,9 +157,9 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
ED_area_status_text(t->area, str);
}
-void initCrease(TransInfo *t)
+static void initCrease_ex(TransInfo *t, int mode)
{
- t->mode = TFM_CREASE;
+ t->mode = mode;
t->transform = applyCrease;
initMouseInputMode(t, &t->mouse, INPUT_SPRING_DELTA);
@@ -176,4 +176,13 @@ void initCrease(TransInfo *t)
t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
}
+void initEgdeCrease(TransInfo *t)
+{
+ initCrease_ex(t, TFM_EDGE_CREASE);
+}
+
+void initVertCrease(TransInfo *t)
+{
+ initCrease_ex(t, TFM_VERT_CREASE);
+}
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_edge_slide.c b/source/blender/editors/transform/transform_mode_edge_slide.c
index 7a0f2743a98..223f2511c72 100644
--- a/source/blender/editors/transform/transform_mode_edge_slide.c
+++ b/source/blender/editors/transform/transform_mode_edge_slide.c
@@ -195,7 +195,7 @@ static bool bm_loop_calc_opposite_co(BMLoop *l_tmp, const float plane_no[3], flo
/* allow some overlap to avoid missing the intersection because of float precision */
if ((fac > -FLT_EPSILON) && (fac < 1.0f + FLT_EPSILON)) {
/* likelihood of multiple intersections per ngon is quite low,
- * it would have to loop back on its self, but better support it
+ * it would have to loop back on itself, but better support it
* so check for the closest opposite edge */
const float tdist = len_v3v3(l_tmp->v->co, tvec);
if (tdist < dist) {
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_ops.c b/source/blender/editors/transform/transform_ops.c
index 5ed340abf97..80feb934f1a 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -78,6 +78,7 @@ static const char OP_BONE_SIZE[] = "TRANSFORM_OT_bbone_resize";
static const char OP_EDGE_SLIDE[] = "TRANSFORM_OT_edge_slide";
static const char OP_VERT_SLIDE[] = "TRANSFORM_OT_vert_slide";
static const char OP_EDGE_CREASE[] = "TRANSFORM_OT_edge_crease";
+static const char OP_VERT_CREASE[] = "TRANSFORM_OT_vert_crease";
static const char OP_EDGE_BWEIGHT[] = "TRANSFORM_OT_edge_bevelweight";
static const char OP_SEQ_SLIDE[] = "TRANSFORM_OT_seq_slide";
static const char OP_NORMAL_ROTATION[] = "TRANSFORM_OT_rotate_normal";
@@ -98,6 +99,7 @@ static void TRANSFORM_OT_bbone_resize(struct wmOperatorType *ot);
static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot);
static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot);
static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot);
+static void TRANSFORM_OT_vert_crease(struct wmOperatorType *ot);
static void TRANSFORM_OT_edge_bevelweight(struct wmOperatorType *ot);
static void TRANSFORM_OT_seq_slide(struct wmOperatorType *ot);
static void TRANSFORM_OT_rotate_normal(struct wmOperatorType *ot);
@@ -118,7 +120,8 @@ static TransformModeItem transform_modes[] = {
{OP_BONE_SIZE, TFM_BONESIZE, TRANSFORM_OT_bbone_resize},
{OP_EDGE_SLIDE, TFM_EDGE_SLIDE, TRANSFORM_OT_edge_slide},
{OP_VERT_SLIDE, TFM_VERT_SLIDE, TRANSFORM_OT_vert_slide},
- {OP_EDGE_CREASE, TFM_CREASE, TRANSFORM_OT_edge_crease},
+ {OP_EDGE_CREASE, TFM_EDGE_CREASE, TRANSFORM_OT_edge_crease},
+ {OP_VERT_CREASE, TFM_VERT_CREASE, TRANSFORM_OT_vert_crease},
{OP_EDGE_BWEIGHT, TFM_BWEIGHT, TRANSFORM_OT_edge_bevelweight},
{OP_SEQ_SLIDE, TFM_SEQ_SLIDE, TRANSFORM_OT_seq_slide},
{OP_NORMAL_ROTATION, TFM_NORMAL_ROTATION, TRANSFORM_OT_rotate_normal},
@@ -139,7 +142,8 @@ const EnumPropertyItem rna_enum_transform_mode_types[] = {
{TFM_TILT, "TILT", 0, "Tilt", ""},
{TFM_TRACKBALL, "TRACKBALL", 0, "Trackball", ""},
{TFM_PUSHPULL, "PUSHPULL", 0, "Push/Pull", ""},
- {TFM_CREASE, "CREASE", 0, "Crease", ""},
+ {TFM_EDGE_CREASE, "CREASE", 0, "Crease", ""},
+ {TFM_VERT_CREASE, "VERTEX_CREASE", 0, "Vertex Crease", ""},
{TFM_MIRROR, "MIRROR", 0, "Mirror", ""},
{TFM_BONESIZE, "BONE_SIZE", 0, "Bone Size", ""},
{TFM_BONE_ENVELOPE, "BONE_ENVELOPE", 0, "Bone Envelope", ""},
@@ -1196,6 +1200,29 @@ static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot)
Transform_Properties(ot, P_SNAP);
}
+static void TRANSFORM_OT_vert_crease(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Crease";
+ ot->description = "Change the crease of vertices";
+ ot->idname = OP_VERT_CREASE;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* api callbacks */
+ ot->invoke = transform_invoke;
+ ot->exec = transform_exec;
+ ot->modal = transform_modal;
+ ot->cancel = transform_cancel;
+ ot->poll = ED_operator_editmesh;
+ ot->poll_property = transform_poll_property;
+
+ RNA_def_float_factor(ot->srna, "value", 0, -1.0f, 1.0f, "Factor", "", -1.0f, 1.0f);
+
+ WM_operatortype_props_advanced_begin(ot);
+
+ Transform_Properties(ot, P_SNAP);
+}
+
static void TRANSFORM_OT_edge_bevelweight(struct wmOperatorType *ot)
{
/* identifiers */
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/transform/transform_orientations.h b/source/blender/editors/transform/transform_orientations.h
index 6e0e3d9f8c7..dd2d5bc86c5 100644
--- a/source/blender/editors/transform/transform_orientations.h
+++ b/source/blender/editors/transform/transform_orientations.h
@@ -34,8 +34,8 @@ short transform_orientation_matrix_get(struct bContext *C,
short orient_index,
const float custom[3][3],
float r_spacemtx[3][3]);
-const char *transform_orientations_spacename_get(struct TransInfo *t, const short orient_type);
-void transform_orientations_current_set(struct TransInfo *t, const short orient_index);
+const char *transform_orientations_spacename_get(struct TransInfo *t, short orient_type);
+void transform_orientations_current_set(struct TransInfo *t, short orient_index);
/**
* Those two fill in mat and return non-zero on success.
@@ -55,7 +55,7 @@ bool createSpaceNormalTangent(float mat[3][3], const float normal[3], const floa
struct TransformOrientation *addMatrixSpace(struct bContext *C,
float mat[3][3],
const char *name,
- const bool overwrite);
+ bool overwrite);
void applyTransformOrientation(const struct TransformOrientation *ts,
float r_mat[3][3],
char r_name[64]);
@@ -75,5 +75,5 @@ int getTransformOrientation_ex(ViewLayer *view_layer,
struct Object *obedit,
float normal[3],
float plane[3],
- const short around);
+ short around);
int getTransformOrientation(const struct bContext *C, float normal[3], float plane[3]);
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index a09078a8222..40be8e6e641 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -499,13 +499,15 @@ void applySnapping(TransInfo *t, float *vec)
/* Time base quirky code to go around find-nearest slowness. */
/* TODO: add exception for object mode, no need to slow it down then. */
if (current - t->tsnap.last >= 0.01) {
- t->tsnap.calcSnap(t, vec);
+ if (t->tsnap.calcSnap) {
+ t->tsnap.calcSnap(t, vec);
+ }
if (t->tsnap.targetSnap) {
t->tsnap.targetSnap(t);
}
- }
- t->tsnap.last = current;
+ t->tsnap.last = current;
+ }
if (validSnap(t)) {
t->tsnap.applySnap(t, vec);
@@ -691,6 +693,15 @@ static void initSnappingMode(TransInfo *t)
bm_face_is_snap_target,
POINTER_FROM_UINT((BM_ELEM_SELECT | BM_ELEM_HIDDEN)));
}
+ else {
+ /* Ignore hidden geometry in the general case. */
+ ED_transform_snap_object_context_set_editmesh_callbacks(
+ t->tsnap.object_context,
+ (bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled,
+ (bool (*)(BMEdge *, void *))BM_elem_cb_check_hflag_disabled,
+ (bool (*)(BMFace *, void *))BM_elem_cb_check_hflag_disabled,
+ POINTER_FROM_UINT(BM_ELEM_HIDDEN));
+ }
}
}
else if (t->spacetype == SPACE_SEQ) {
@@ -783,8 +794,15 @@ static void setSnappingCallback(TransInfo *t)
if (t->spacetype == SPACE_VIEW3D) {
t->tsnap.calcSnap = snap_calc_view3d_fn;
}
- else if (t->spacetype == SPACE_IMAGE && t->obedit_type == OB_MESH) {
- t->tsnap.calcSnap = snap_calc_uv_fn;
+ else if (t->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = t->area->spacedata.first;
+ Object *obact = t->view_layer->basact ? t->view_layer->basact->object : NULL;
+
+ const bool is_uv_editor = sima->mode == SI_MODE_UV;
+ const bool has_edit_object = obact && BKE_object_is_in_editmode(obact);
+ if (is_uv_editor && has_edit_object) {
+ t->tsnap.calcSnap = snap_calc_uv_fn;
+ }
}
else if (t->spacetype == SPACE_NODE) {
t->tsnap.calcSnap = snap_calc_node_fn;
@@ -959,7 +977,7 @@ static void snap_calc_view3d_fn(TransInfo *t, float *UNUSED(vec))
static void snap_calc_uv_fn(TransInfo *t, float *UNUSED(vec))
{
- BLI_assert(t->spacetype == SPACE_IMAGE && t->obedit_type == OB_MESH);
+ BLI_assert(t->spacetype == SPACE_IMAGE);
if (t->tsnap.mode & SCE_SNAP_MODE_VERTEX) {
float co[2];
diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h
index bc89c7a8cda..389c1441db1 100644
--- a/source/blender/editors/transform/transform_snap.h
+++ b/source/blender/editors/transform/transform_snap.h
@@ -27,7 +27,7 @@
bool peelObjectsTransform(struct TransInfo *t,
const float mval[2],
- const bool use_peel_object,
+ bool use_peel_object,
/* return args */
float r_loc[3],
float r_no[3],
@@ -92,9 +92,9 @@ void transform_snap_sequencer_apply_translate(TransInfo *t, float *vec);
*/
short getAnimEdit_SnapMode(TransInfo *t);
void snapFrameTransform(TransInfo *t,
- const eAnimEdit_AutoSnap autosnap,
- const float val_initial,
- const float val_final,
+ eAnimEdit_AutoSnap autosnap,
+ float val_initial,
+ float val_final,
float *r_val_final);
/**
* This function is used by Animation Editor specific transform functions to do
@@ -102,5 +102,5 @@ void snapFrameTransform(TransInfo *t,
*/
void transform_snap_anim_flush_data(TransInfo *t,
TransData *td,
- const eAnimEdit_AutoSnap autosnap,
+ eAnimEdit_AutoSnap autosnap,
float *r_val_final);
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 350d3a2676c..9dc8b6cf69d 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -146,26 +146,28 @@ struct SnapObjectContext {
* If NULL the BMesh should be used. */
static Mesh *mesh_for_snap(Object *ob_eval, eSnapEditType edit_mode_type, bool *r_use_hide)
{
- Mesh *me_eval = ob_eval->data;
+ Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval);
bool use_hide = false;
if (BKE_object_is_in_editmode(ob_eval)) {
if (edit_mode_type == SNAP_GEOM_EDIT) {
return NULL;
}
- BMEditMesh *em_eval = BKE_editmesh_from_object(ob_eval);
- if ((edit_mode_type == SNAP_GEOM_FINAL) && em_eval->mesh_eval_final) {
- if (em_eval->mesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
+ Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob_eval);
+ Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob_eval);
+
+ if ((edit_mode_type == SNAP_GEOM_FINAL) && editmesh_eval_final) {
+ if (editmesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
return NULL;
}
- me_eval = em_eval->mesh_eval_final;
+ me_eval = editmesh_eval_final;
use_hide = true;
}
- else if ((edit_mode_type == SNAP_GEOM_CAGE) && em_eval->mesh_eval_cage) {
- if (em_eval->mesh_eval_cage->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
+ else if ((edit_mode_type == SNAP_GEOM_CAGE) && editmesh_eval_cage) {
+ if (editmesh_eval_cage->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
return NULL;
}
- me_eval = em_eval->mesh_eval_cage;
+ me_eval = editmesh_eval_cage;
use_hide = true;
}
}
@@ -318,12 +320,14 @@ static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx,
if (sod->treedata_mesh.tree == NULL) {
sod->treedata_mesh.vert = me_eval->mvert;
+ sod->treedata_mesh.vert_normals = BKE_mesh_vertex_normals_ensure(me_eval);
sod->treedata_mesh.loop = me_eval->mloop;
sod->treedata_mesh.looptri = BKE_mesh_runtime_looptri_ensure(me_eval);
BLI_assert(sod->has_looptris == false);
}
else {
BLI_assert(sod->treedata_mesh.vert != NULL);
+ BLI_assert(sod->treedata_mesh.vert_normals != NULL);
BLI_assert(sod->treedata_mesh.loop != NULL);
BLI_assert(sod->treedata_mesh.looptri != NULL);
sod->has_looptris = true;
@@ -343,12 +347,14 @@ static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx,
static struct Mesh_Runtime *snap_object_data_editmesh_runtime_get(Object *ob_eval)
{
- BMEditMesh *em_eval = BKE_editmesh_from_object(ob_eval);
- if (em_eval->mesh_eval_final) {
- return &em_eval->mesh_eval_final->runtime;
+ Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob_eval);
+ if (editmesh_eval_final) {
+ return &editmesh_eval_final->runtime;
}
- if (em_eval->mesh_eval_cage) {
- return &em_eval->mesh_eval_cage->runtime;
+
+ Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob_eval);
+ if (editmesh_eval_cage) {
+ return &editmesh_eval_cage->runtime;
}
return &((Mesh *)ob_eval->data)->runtime;
@@ -1195,56 +1201,96 @@ static bool snap_bound_box_check_dist(const float min[3],
return true;
}
-static void cb_mvert_co_get(const int index, const void *user_data, const float **r_co)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks
+ * \{ */
+
+struct Nearest2dUserData;
+
+typedef void (*Nearest2DGetVertCoCallback)(const int index,
+ const struct Nearest2dUserData *data,
+ const float **r_co);
+typedef void (*Nearest2DGetEdgeVertsCallback)(const int index,
+ const struct Nearest2dUserData *data,
+ int r_v_index[2]);
+typedef void (*Nearest2DGetTriVertsCallback)(const int index,
+ const struct Nearest2dUserData *data,
+ int r_v_index[3]);
+/* Equal the previous one */
+typedef void (*Nearest2DGetTriEdgesCallback)(const int index,
+ const struct Nearest2dUserData *data,
+ int r_e_index[3]);
+typedef void (*Nearest2DCopyVertNoCallback)(const int index,
+ const struct Nearest2dUserData *data,
+ float r_no[3]);
+
+typedef struct Nearest2dUserData {
+ Nearest2DGetVertCoCallback get_vert_co;
+ Nearest2DGetEdgeVertsCallback get_edge_verts_index;
+ Nearest2DGetTriVertsCallback get_tri_verts_index;
+ Nearest2DGetTriEdgesCallback get_tri_edges_index;
+ Nearest2DCopyVertNoCallback copy_vert_no;
+
+ union {
+ struct {
+ struct BMesh *bm;
+ };
+ struct {
+ const struct MVert *vert;
+ const float (*vert_normals)[3];
+ const struct MEdge *edge; /* only used for #BVHTreeFromMeshEdges */
+ const struct MLoop *loop;
+ const struct MLoopTri *looptri;
+ };
+ };
+
+ bool is_persp;
+ bool use_backface_culling;
+} Nearest2dUserData;
+
+static void cb_mvert_co_get(const int index, const Nearest2dUserData *data, const float **r_co)
{
- const BVHTreeFromMesh *data = user_data;
*r_co = data->vert[index].co;
}
-static void cb_bvert_co_get(const int index, const void *user_data, const float **r_co)
+static void cb_bvert_co_get(const int index, const Nearest2dUserData *data, const float **r_co)
{
- const BMEditMesh *data = user_data;
BMVert *eve = BM_vert_at_index(data->bm, index);
*r_co = eve->co;
}
-static void cb_mvert_no_copy(const int index, const void *user_data, float r_no[3])
+static void cb_mvert_no_copy(const int index, const Nearest2dUserData *data, float r_no[3])
{
- const BVHTreeFromMesh *data = user_data;
- const MVert *vert = data->vert + index;
-
- normal_short_to_float_v3(r_no, vert->no);
+ copy_v3_v3(r_no, data->vert_normals[index]);
}
-static void cb_bvert_no_copy(const int index, const void *user_data, float r_no[3])
+static void cb_bvert_no_copy(const int index, const Nearest2dUserData *data, float r_no[3])
{
- const BMEditMesh *data = user_data;
BMVert *eve = BM_vert_at_index(data->bm, index);
copy_v3_v3(r_no, eve->no);
}
-static void cb_medge_verts_get(const int index, const void *user_data, int r_v_index[2])
+static void cb_medge_verts_get(const int index, const Nearest2dUserData *data, int r_v_index[2])
{
- const BVHTreeFromMesh *data = user_data;
const MEdge *edge = &data->edge[index];
r_v_index[0] = edge->v1;
r_v_index[1] = edge->v2;
}
-static void cb_bedge_verts_get(const int index, const void *user_data, int r_v_index[2])
+static void cb_bedge_verts_get(const int index, const Nearest2dUserData *data, int r_v_index[2])
{
- const BMEditMesh *data = user_data;
BMEdge *eed = BM_edge_at_index(data->bm, index);
r_v_index[0] = BM_elem_index_get(eed->v1);
r_v_index[1] = BM_elem_index_get(eed->v2);
}
-static void cb_mlooptri_edges_get(const int index, const void *user_data, int r_v_index[3])
+static void cb_mlooptri_edges_get(const int index, const Nearest2dUserData *data, int r_v_index[3])
{
- const BVHTreeFromMesh *data = user_data;
const MEdge *medge = data->edge;
const MLoop *mloop = data->loop;
const MLoopTri *lt = &data->looptri[index];
@@ -1261,9 +1307,8 @@ static void cb_mlooptri_edges_get(const int index, const void *user_data, int r_
}
}
-static void cb_mlooptri_verts_get(const int index, const void *user_data, int r_v_index[3])
+static void cb_mlooptri_verts_get(const int index, const Nearest2dUserData *data, int r_v_index[3])
{
- const BVHTreeFromMesh *data = user_data;
const MLoop *loop = data->loop;
const MLoopTri *looptri = &data->looptri[index];
@@ -1332,66 +1377,6 @@ static bool test_projected_edge_dist(const struct DistProjectedAABBPrecalc *prec
precalc, clip_plane, clip_plane_len, is_persp, near_co, dist_px_sq, r_co);
}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Walk DFS
- * \{ */
-
-typedef void (*Nearest2DGetVertCoCallback)(const int index,
- const void *user_data,
- const float **r_co);
-typedef void (*Nearest2DGetEdgeVertsCallback)(const int index,
- const void *user_data,
- int r_v_index[2]);
-typedef void (*Nearest2DGetTriVertsCallback)(const int index,
- const void *user_data,
- int r_v_index[3]);
-/* Equal the previous one */
-typedef void (*Nearest2DGetTriEdgesCallback)(const int index,
- const void *user_data,
- int r_e_index[3]);
-typedef void (*Nearest2DCopyVertNoCallback)(const int index, const void *user_data, float r_no[3]);
-
-typedef struct Nearest2dUserData {
- void *userdata;
- Nearest2DGetVertCoCallback get_vert_co;
- Nearest2DGetEdgeVertsCallback get_edge_verts_index;
- Nearest2DGetTriVertsCallback get_tri_verts_index;
- Nearest2DGetTriEdgesCallback get_tri_edges_index;
- Nearest2DCopyVertNoCallback copy_vert_no;
-
- bool is_persp;
- bool use_backface_culling;
-} Nearest2dUserData;
-
-static void nearest2d_data_init(SnapObjectData *sod,
- bool is_persp,
- bool use_backface_culling,
- Nearest2dUserData *r_nearest2d)
-{
- if (sod->type == SNAP_MESH) {
- r_nearest2d->userdata = &sod->treedata_mesh;
- r_nearest2d->get_vert_co = cb_mvert_co_get;
- r_nearest2d->get_edge_verts_index = cb_medge_verts_get;
- r_nearest2d->copy_vert_no = cb_mvert_no_copy;
- r_nearest2d->get_tri_verts_index = cb_mlooptri_verts_get;
- r_nearest2d->get_tri_edges_index = cb_mlooptri_edges_get;
- }
- else {
- BLI_assert(sod->type == SNAP_EDIT_MESH);
- r_nearest2d->userdata = sod->treedata_editmesh.em;
- r_nearest2d->get_vert_co = cb_bvert_co_get;
- r_nearest2d->get_edge_verts_index = cb_bedge_verts_get;
- r_nearest2d->copy_vert_no = cb_bvert_no_copy;
- r_nearest2d->get_tri_verts_index = NULL;
- r_nearest2d->get_tri_edges_index = NULL;
- }
-
- r_nearest2d->is_persp = is_persp;
- r_nearest2d->use_backface_culling = use_backface_culling;
-}
-
static void cb_snap_vert(void *userdata,
int index,
const struct DistProjectedAABBPrecalc *precalc,
@@ -1399,10 +1384,10 @@ static void cb_snap_vert(void *userdata,
const int clip_plane_len,
BVHTreeNearest *nearest)
{
- struct Nearest2dUserData *data = userdata;
+ Nearest2dUserData *data = userdata;
const float *co;
- data->get_vert_co(index, data->userdata, &co);
+ data->get_vert_co(index, data, &co);
if (test_projected_vert_dist(precalc,
clip_plane,
@@ -1411,7 +1396,7 @@ static void cb_snap_vert(void *userdata,
co,
&nearest->dist_sq,
nearest->co)) {
- data->copy_vert_no(index, data->userdata, nearest->no);
+ data->copy_vert_no(index, data, nearest->no);
nearest->index = index;
}
}
@@ -1426,11 +1411,11 @@ static void cb_snap_edge(void *userdata,
struct Nearest2dUserData *data = userdata;
int vindex[2];
- data->get_edge_verts_index(index, data->userdata, vindex);
+ data->get_edge_verts_index(index, data, vindex);
const float *v_pair[2];
- data->get_vert_co(vindex[0], data->userdata, &v_pair[0]);
- data->get_vert_co(vindex[1], data->userdata, &v_pair[1]);
+ data->get_vert_co(vindex[0], data, &v_pair[0]);
+ data->get_vert_co(vindex[1], data, &v_pair[1]);
if (test_projected_edge_dist(precalc,
clip_plane,
@@ -1455,7 +1440,7 @@ static void cb_snap_edge_verts(void *userdata,
struct Nearest2dUserData *data = userdata;
int vindex[2];
- data->get_edge_verts_index(index, data->userdata, vindex);
+ data->get_edge_verts_index(index, data, vindex);
for (int i = 2; i--;) {
if (vindex[i] == nearest->index) {
@@ -1472,16 +1457,16 @@ static void cb_snap_tri_edges(void *userdata,
const int clip_plane_len,
BVHTreeNearest *nearest)
{
- struct Nearest2dUserData *data = userdata;
+ Nearest2dUserData *data = userdata;
if (data->use_backface_culling) {
int vindex[3];
- data->get_tri_verts_index(index, data->userdata, vindex);
+ data->get_tri_verts_index(index, data, vindex);
const float *t0, *t1, *t2;
- data->get_vert_co(vindex[0], data->userdata, &t0);
- data->get_vert_co(vindex[1], data->userdata, &t1);
- data->get_vert_co(vindex[2], data->userdata, &t2);
+ data->get_vert_co(vindex[0], data, &t0);
+ data->get_vert_co(vindex[1], data, &t1);
+ data->get_vert_co(vindex[2], data, &t2);
float dummy[3];
if (raycast_tri_backface_culling_test(precalc->ray_direction, t0, t1, t2, dummy)) {
return;
@@ -1489,7 +1474,7 @@ static void cb_snap_tri_edges(void *userdata,
}
int eindex[3];
- data->get_tri_edges_index(index, data->userdata, eindex);
+ data->get_tri_edges_index(index, data, eindex);
for (int i = 3; i--;) {
if (eindex[i] != -1) {
if (eindex[i] == nearest->index) {
@@ -1510,13 +1495,13 @@ static void cb_snap_tri_verts(void *userdata,
struct Nearest2dUserData *data = userdata;
int vindex[3];
- data->get_tri_verts_index(index, data->userdata, vindex);
+ data->get_tri_verts_index(index, data, vindex);
if (data->use_backface_culling) {
const float *t0, *t1, *t2;
- data->get_vert_co(vindex[0], data->userdata, &t0);
- data->get_vert_co(vindex[1], data->userdata, &t1);
- data->get_vert_co(vindex[2], data->userdata, &t2);
+ data->get_vert_co(vindex[0], data, &t0);
+ data->get_vert_co(vindex[1], data, &t1);
+ data->get_vert_co(vindex[2], data, &t2);
float dummy[3];
if (raycast_tri_backface_culling_test(precalc->ray_direction, t0, t1, t2, dummy)) {
return;
@@ -1531,6 +1516,39 @@ static void cb_snap_tri_verts(void *userdata,
}
}
+static void nearest2d_data_init(SnapObjectData *sod,
+ bool is_persp,
+ bool use_backface_culling,
+ Nearest2dUserData *r_nearest2d)
+{
+ if (sod->type == SNAP_MESH) {
+ r_nearest2d->get_vert_co = cb_mvert_co_get;
+ r_nearest2d->get_edge_verts_index = cb_medge_verts_get;
+ r_nearest2d->copy_vert_no = cb_mvert_no_copy;
+ r_nearest2d->get_tri_verts_index = cb_mlooptri_verts_get;
+ r_nearest2d->get_tri_edges_index = cb_mlooptri_edges_get;
+
+ r_nearest2d->vert = sod->treedata_mesh.vert;
+ r_nearest2d->vert_normals = sod->treedata_mesh.vert_normals;
+ r_nearest2d->edge = sod->treedata_mesh.edge;
+ r_nearest2d->loop = sod->treedata_mesh.loop;
+ r_nearest2d->looptri = sod->treedata_mesh.looptri;
+ }
+ else {
+ BLI_assert(sod->type == SNAP_EDIT_MESH);
+ r_nearest2d->get_vert_co = cb_bvert_co_get;
+ r_nearest2d->get_edge_verts_index = cb_bedge_verts_get;
+ r_nearest2d->copy_vert_no = cb_bvert_no_copy;
+ r_nearest2d->get_tri_verts_index = NULL;
+ r_nearest2d->get_tri_edges_index = NULL;
+
+ r_nearest2d->bm = sod->treedata_editmesh.em->bm;
+ }
+
+ r_nearest2d->is_persp = is_persp;
+ r_nearest2d->use_backface_culling = use_backface_culling;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1689,11 +1707,11 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
sod, sctx->runtime.view_proj == VIEW_PROJ_PERSP, params->use_backface_culling, &nearest2d);
int vindex[2];
- nearest2d.get_edge_verts_index(*r_index, nearest2d.userdata, vindex);
+ nearest2d.get_edge_verts_index(*r_index, &nearest2d, vindex);
const float *v_pair[2];
- nearest2d.get_vert_co(vindex[0], nearest2d.userdata, &v_pair[0]);
- nearest2d.get_vert_co(vindex[1], nearest2d.userdata, &v_pair[1]);
+ nearest2d.get_vert_co(vindex[0], &nearest2d, &v_pair[0]);
+ nearest2d.get_vert_co(vindex[1], &nearest2d, &v_pair[1]);
struct DistProjectedAABBPrecalc neasrest_precalc;
{
@@ -1740,7 +1758,7 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
if (r_no) {
float imat[4][4];
invert_m4_m4(imat, obmat);
- nearest2d.copy_vert_no(vindex[v_id], nearest2d.userdata, r_no);
+ nearest2d.copy_vert_no(vindex[v_id], &nearest2d, r_no);
mul_transposed_mat3_m4_v3(imat, r_no);
normalize_v3(r_no);
}
diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c
index ca8b86d525d..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"
@@ -374,6 +375,9 @@ static int ed_undo_step_by_index(bContext *C, const int undo_index, ReportList *
wmWindowManager *wm = CTX_wm_manager(C);
const int active_step_index = BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active);
+ if (undo_index == active_step_index) {
+ return OPERATOR_CANCELLED;
+ }
const enum eUndoStepDir undo_dir = (undo_index < active_step_index) ? STEP_UNDO : STEP_REDO;
CLOG_INFO(&LOG,
@@ -494,17 +498,28 @@ UndoStack *ED_undo_stack_get(void)
/** \name Undo, Undo Push & Redo Operators
* \{ */
+/**
+ * Refresh to run after user activated undo/redo actions.
+ */
+static void ed_undo_refresh_for_op(bContext *C)
+{
+ /* The "last operator" should disappear, later we can tie this with undo stack nicer. */
+ WM_operator_stack_clear(CTX_wm_manager(C));
+
+ /* Keep button under the cursor active. */
+ WM_event_add_mousemove(CTX_wm_window(C));
+
+ ED_outliner_select_sync_from_all_tag(C);
+}
+
static int ed_undo_exec(bContext *C, wmOperator *op)
{
/* "last operator" should disappear, later we can tie this with undo stack nicer */
WM_operator_stack_clear(CTX_wm_manager(C));
int ret = ed_undo_step_direction(C, STEP_UNDO, op->reports);
if (ret & OPERATOR_FINISHED) {
- /* Keep button under the cursor active. */
- WM_event_add_mousemove(CTX_wm_window(C));
+ ed_undo_refresh_for_op(C);
}
-
- ED_outliner_select_sync_from_all_tag(C);
return ret;
}
@@ -529,11 +544,8 @@ static int ed_redo_exec(bContext *C, wmOperator *op)
{
int ret = ed_undo_step_direction(C, STEP_REDO, op->reports);
if (ret & OPERATOR_FINISHED) {
- /* Keep button under the cursor active. */
- WM_event_add_mousemove(CTX_wm_window(C));
+ ed_undo_refresh_for_op(C);
}
-
- ED_outliner_select_sync_from_all_tag(C);
return ret;
}
@@ -748,97 +760,36 @@ 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))
+/* NOTE: also check #ed_undo_step() in top if you change notifiers. */
+static int undo_history_exec(bContext *C, wmOperator *op)
{
- 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);
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "item");
+ if (RNA_property_is_set(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);
- UI_popup_menu_end(C, pup);
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+ return OPERATOR_FINISHED;
}
}
return OPERATOR_CANCELLED;
}
-/* NOTE: also check #ed_undo_step() in top if you change notifiers. */
-static int undo_history_exec(bContext *C, wmOperator *op)
+static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
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);
- WM_operator_stack_clear(CTX_wm_manager(C));
- ed_undo_step_by_index(C, item, op->reports);
- WM_event_add_notifier(C, NC_WINDOW, NULL);
- return OPERATOR_FINISHED;
+ return undo_history_exec(C, op);
}
- return OPERATOR_CANCELLED;
-}
-static bool undo_history_poll(bContext *C)
-{
- if (!ed_undo_is_init_and_screenactive_poll(C)) {
- return false;
- }
- 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)
@@ -851,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/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt
index b339bfbdc47..90a09c87cc6 100644
--- a/source/blender/editors/util/CMakeLists.txt
+++ b/source/blender/editors/util/CMakeLists.txt
@@ -55,6 +55,7 @@ set(SRC
../include/ED_clip.h
../include/ED_curve.h
../include/ED_datafiles.h
+ ../include/ED_file_indexer.h
../include/ED_fileselect.h
../include/ED_geometry.h
../include/ED_gizmo_library.h
diff --git a/source/blender/editors/util/ed_draw.c b/source/blender/editors/util/ed_draw.c
index ccbde07f5b1..3e85862a847 100644
--- a/source/blender/editors/util/ed_draw.c
+++ b/source/blender/editors/util/ed_draw.c
@@ -599,9 +599,9 @@ static void metadata_custom_draw_fields(const char *field, const char *value, vo
}
MetadataCustomDrawContext *ctx = (MetadataCustomDrawContext *)ctx_v;
char temp_str[MAX_METADATA_STR];
- BLI_snprintf(temp_str, MAX_METADATA_STR, "%s: %s", field, value);
+ SNPRINTF(temp_str, "%s: %s", field, value);
BLF_position(ctx->fontid, ctx->xmin, ctx->ymin + ctx->current_y, 0.0f);
- BLF_draw(ctx->fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw(ctx->fontid, temp_str, sizeof(temp_str));
ctx->current_y += ctx->vertical_offset;
}
@@ -625,18 +625,18 @@ static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const
/* first line */
if (i == 0) {
bool do_newline = false;
- int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[0]);
+ int len = SNPRINTF_RLEN(temp_str, "%s: ", meta_data_list[0]);
if (metadata_is_valid(ibuf, temp_str, 0, len)) {
BLF_position(fontid, xmin, ymax - vertical_offset, 0.0f);
- BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw(fontid, temp_str, sizeof(temp_str));
do_newline = true;
}
- len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[1]);
+ len = SNPRINTF_RLEN(temp_str, "%s: ", meta_data_list[1]);
if (metadata_is_valid(ibuf, temp_str, 1, len)) {
- int line_width = BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ int line_width = BLF_width(fontid, temp_str, sizeof(temp_str));
BLF_position(fontid, xmax - line_width, ymax - vertical_offset, 0.0f);
- BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw(fontid, temp_str, sizeof(temp_str));
do_newline = true;
}
@@ -645,32 +645,32 @@ static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const
}
} /* Strip */
else if (ELEM(i, 1, 2)) {
- int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]);
+ int len = SNPRINTF_RLEN(temp_str, "%s: ", meta_data_list[i + 1]);
if (metadata_is_valid(ibuf, temp_str, i + 1, len)) {
BLF_position(fontid, xmin, ymax - vertical_offset - ofs_y, 0.0f);
- BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw(fontid, temp_str, sizeof(temp_str));
ofs_y += vertical_offset;
}
} /* Note (wrapped) */
else if (i == 3) {
- int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]);
+ int len = SNPRINTF_RLEN(temp_str, "%s: ", meta_data_list[i + 1]);
if (metadata_is_valid(ibuf, temp_str, i + 1, len)) {
struct ResultBLF info;
BLF_enable(fontid, BLF_WORD_WRAP);
BLF_wordwrap(fontid, ibuf->x - (margin * 2));
BLF_position(fontid, xmin, ymax - vertical_offset - ofs_y, 0.0f);
- BLF_draw_ex(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX, &info);
+ BLF_draw_ex(fontid, temp_str, sizeof(temp_str), &info);
BLF_wordwrap(fontid, 0);
BLF_disable(fontid, BLF_WORD_WRAP);
ofs_y += vertical_offset * info.lines;
}
}
else {
- int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]);
+ int len = SNPRINTF_RLEN(temp_str, "%s: ", meta_data_list[i + 1]);
if (metadata_is_valid(ibuf, temp_str, i + 1, len)) {
- int line_width = BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ int line_width = BLF_width(fontid, temp_str, sizeof(temp_str));
BLF_position(fontid, xmax - line_width, ymax - vertical_offset - ofs_y, 0.0f);
- BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw(fontid, temp_str, sizeof(temp_str));
ofs_y += vertical_offset;
}
}
@@ -687,12 +687,12 @@ static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const
int ofs_x = 0;
ofs_y = ctx.current_y;
for (int i = 5; i < 10; i++) {
- int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i]);
+ int len = SNPRINTF_RLEN(temp_str, "%s: ", meta_data_list[i]);
if (metadata_is_valid(ibuf, temp_str, i, len)) {
BLF_position(fontid, xmin + ofs_x, ymin + ofs_y, 0.0f);
- BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw(fontid, temp_str, sizeof(temp_str));
- ofs_x += BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX) + UI_UNIT_X;
+ ofs_x += BLF_width(fontid, temp_str, sizeof(temp_str)) + UI_UNIT_X;
}
}
}
diff --git a/source/blender/editors/util/ed_transverts.c b/source/blender/editors/util/ed_transverts.c
index b4a93eb996c..b8efbad1ad9 100644
--- a/source/blender/editors/util/ed_transverts.c
+++ b/source/blender/editors/util/ed_transverts.c
@@ -41,6 +41,7 @@
#include "BKE_editmesh.h"
#include "BKE_lattice.h"
#include "BKE_mesh_iterators.h"
+#include "BKE_object.h"
#include "DEG_depsgraph.h"
@@ -168,11 +169,7 @@ void ED_transverts_update_obedit(TransVertStore *tvs, Object *obedit)
}
}
-static void set_mapped_co(void *vuserdata,
- int index,
- const float co[3],
- const float UNUSED(no[3]),
- const short UNUSED(no_s[3]))
+static void set_mapped_co(void *vuserdata, int index, const float co[3], const float UNUSED(no[3]))
{
void **userdata = vuserdata;
BMEditMesh *em = userdata[0];
@@ -315,9 +312,10 @@ void ED_transverts_create_from_obedit(TransVertStore *tvs, Object *obedit, const
userdata[1] = tvs->transverts;
}
- if (tvs->transverts && em->mesh_eval_cage) {
+ struct Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(obedit);
+ if (tvs->transverts && editmesh_eval_cage) {
BM_mesh_elem_table_ensure(bm, BM_VERT);
- BKE_mesh_foreach_mapped_vert(em->mesh_eval_cage, set_mapped_co, userdata, MESH_FOREACH_NOP);
+ BKE_mesh_foreach_mapped_vert(editmesh_eval_cage, set_mapped_co, userdata, MESH_FOREACH_NOP);
}
}
else if (obedit->type == OB_ARMATURE) {
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 8e94dc23085..0320a2a9a1a 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -35,6 +35,7 @@
#include "BKE_collection.h"
#include "BKE_global.h"
+#include "BKE_lib_remap.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_multires.h"
@@ -352,6 +353,7 @@ void unpack_menu(bContext *C,
uiLayout *layout;
char line[FILE_MAX + 100];
wmOperatorType *ot = WM_operatortype_find(opname, 1);
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
pup = UI_popup_menu_begin(C, IFACE_("Unpack File"), ICON_NONE);
layout = UI_popup_menu_layout(pup);
@@ -361,13 +363,13 @@ void unpack_menu(bContext *C,
RNA_enum_set(&props_ptr, "method", PF_REMOVE);
RNA_string_set(&props_ptr, "id", id_name);
- if (G.relbase_valid) {
+ if (blendfile_path[0] != '\0') {
char local_name[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX];
BLI_split_file_part(abs_name, fi, sizeof(fi));
BLI_snprintf(local_name, sizeof(local_name), "//%s/%s", folder, fi);
if (!STREQ(abs_name, local_name)) {
- switch (BKE_packedfile_compare_to_file(BKE_main_blendfile_path(bmain), local_name, pf)) {
+ switch (BKE_packedfile_compare_to_file(blendfile_path, local_name, pf)) {
case PF_CMP_NOFILE:
BLI_snprintf(line, sizeof(line), TIP_("Create %s"), local_name);
uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr);
@@ -400,7 +402,7 @@ void unpack_menu(bContext *C,
}
}
- switch (BKE_packedfile_compare_to_file(BKE_main_blendfile_path(bmain), abs_name, pf)) {
+ switch (BKE_packedfile_compare_to_file(blendfile_path, abs_name, pf)) {
case PF_CMP_NOFILE:
BLI_snprintf(line, sizeof(line), TIP_("Create %s"), abs_name);
// uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_WRITE_ORIGINAL);
@@ -433,11 +435,27 @@ void unpack_menu(bContext *C,
UI_popup_menu_end(C, pup);
}
-void ED_spacedata_id_remap(struct ScrArea *area, struct SpaceLink *sl, ID *old_id, ID *new_id)
+void ED_spacedata_id_remap(struct ScrArea *area,
+ struct SpaceLink *sl,
+ const struct IDRemapper *mappings)
+{
+ SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
+ if (st && st->id_remap) {
+ st->id_remap(area, sl, mappings);
+ }
+}
+
+void ED_spacedata_id_remap_single(struct ScrArea *area,
+ struct SpaceLink *sl,
+ ID *old_id,
+ ID *new_id)
{
SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
if (st && st->id_remap) {
- st->id_remap(area, sl, old_id, new_id);
+ struct IDRemapper *mappings = BKE_id_remapper_create();
+ BKE_id_remapper_add(mappings, old_id, new_id);
+ st->id_remap(area, sl, mappings);
+ BKE_id_remapper_free(mappings);
}
}
diff --git a/source/blender/editors/util/ed_util_imbuf.c b/source/blender/editors/util/ed_util_imbuf.c
index 38ae98c678f..2e983eeff39 100644
--- a/source/blender/editors/util/ed_util_imbuf.c
+++ b/source/blender/editors/util/ed_util_imbuf.c
@@ -278,13 +278,13 @@ static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event
/* XXX node curve integration. */
#if 0
{
- ScrArea *sa, *cur = curarea;
+ ScrArea *area, *cur = curarea;
node_curvemap_sample(fp); /* sends global to node editor */
- for (sa = G.curscreen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_NODE) {
- areawinset(sa->win);
- scrarea_do_windraw(sa);
+ for (area = G.curscreen->areabase.first; area; area = area->next) {
+ if (area->spacetype == SPACE_NODE) {
+ areawinset(area->win);
+ scrarea_do_windraw(area);
}
}
node_curvemap_sample(NULL); /* clears global in node editor */
@@ -385,12 +385,12 @@ static void sequencer_sample_apply(bContext *C, wmOperator *op, const wmEvent *e
static void ed_imbuf_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa == NULL) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area == NULL) {
return;
}
- switch (sa->spacetype) {
+ switch (area->spacetype) {
case SPACE_IMAGE: {
image_sample_apply(C, op, event);
break;
@@ -432,9 +432,9 @@ void ED_imbuf_sample_draw(const bContext *C, ARegion *region, void *arg_info)
info->zfp);
if (info->sample_size > 1) {
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_IMAGE) {
+ if (area && area->spacetype == SPACE_IMAGE) {
const wmWindow *win = CTX_wm_window(C);
const wmEvent *event = win->eventstate;
@@ -482,11 +482,11 @@ void ED_imbuf_sample_exit(bContext *C, wmOperator *op)
int ED_imbuf_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *region = CTX_wm_region(C);
- ScrArea *sa = CTX_wm_area(C);
- if (sa) {
- switch (sa->spacetype) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area) {
+ switch (area->spacetype) {
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
if (region->regiontype == RGN_TYPE_WINDOW) {
if (ED_space_image_show_cache_and_mval_over(sima, region, event->mval)) {
return OPERATOR_PASS_THROUGH;
diff --git a/source/blender/editors/util/ed_util_ops.cc b/source/blender/editors/util/ed_util_ops.cc
index a1b17d799bc..ae37dab7bb4 100644
--- a/source/blender/editors/util/ed_util_ops.cc
+++ b/source/blender/editors/util/ed_util_ops.cc
@@ -121,6 +121,22 @@ static void ED_OT_lib_id_load_custom_preview(wmOperatorType *ot)
FILE_SORT_DEFAULT);
}
+static bool lib_id_generate_preview_poll(bContext *C)
+{
+ if (!lib_id_preview_editing_poll(C)) {
+ return false;
+ }
+
+ const PointerRNA idptr = CTX_data_pointer_get(C, "id");
+ const ID *id = (ID *)idptr.data;
+ if (GS(id->name) == ID_NT) {
+ CTX_wm_operator_poll_msg_set(C, TIP_("Can't generate automatic preview for node group"));
+ return false;
+ }
+
+ return true;
+}
+
static int lib_id_generate_preview_exec(bContext *C, wmOperator *UNUSED(op))
{
PointerRNA idptr = CTX_data_pointer_get(C, "id");
@@ -148,13 +164,57 @@ static void ED_OT_lib_id_generate_preview(wmOperatorType *ot)
ot->idname = "ED_OT_lib_id_generate_preview";
/* api callbacks */
- ot->poll = lib_id_preview_editing_poll;
+ ot->poll = lib_id_generate_preview_poll;
ot->exec = lib_id_generate_preview_exec;
/* flags */
ot->flag = OPTYPE_INTERNAL | OPTYPE_REGISTER | OPTYPE_UNDO;
}
+static bool lib_id_generate_preview_from_object_poll(bContext *C)
+{
+ if (!lib_id_preview_editing_poll(C)) {
+ return false;
+ }
+ if (CTX_data_active_object(C) == nullptr) {
+ return false;
+ }
+ return true;
+}
+
+static int lib_id_generate_preview_from_object_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ PointerRNA idptr = CTX_data_pointer_get(C, "id");
+ ID *id = (ID *)idptr.data;
+
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
+
+ Object *object_to_render = CTX_data_active_object(C);
+
+ BKE_previewimg_id_free(id);
+ PreviewImage *preview_image = BKE_previewimg_id_ensure(id);
+ UI_icon_render_id_ex(C, nullptr, &object_to_render->id, ICON_SIZE_PREVIEW, true, preview_image);
+
+ WM_event_add_notifier(C, NC_ASSET | NA_EDITED, nullptr);
+ ED_assetlist_storage_tag_main_data_dirty();
+
+ return OPERATOR_FINISHED;
+}
+
+static void ED_OT_lib_id_generate_preview_from_object(wmOperatorType *ot)
+{
+ ot->name = "Generate Preview from Object";
+ ot->description = "Create a preview for this asset by rendering the active object";
+ ot->idname = "ED_OT_lib_id_generate_preview_from_object";
+
+ /* api callbacks */
+ ot->poll = lib_id_generate_preview_from_object_poll;
+ ot->exec = lib_id_generate_preview_from_object_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_INTERNAL | OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -280,6 +340,7 @@ void ED_operatortypes_edutils()
{
WM_operatortype_append(ED_OT_lib_id_load_custom_preview);
WM_operatortype_append(ED_OT_lib_id_generate_preview);
+ WM_operatortype_append(ED_OT_lib_id_generate_preview_from_object);
WM_operatortype_append(ED_OT_lib_id_fake_user_toggle);
WM_operatortype_append(ED_OT_lib_id_unlink);
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index 1fa96a932ed..9646444c103 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -74,13 +74,13 @@ typedef struct UvNearestHit {
bool uv_find_nearest_vert(struct Scene *scene,
struct Object *obedit,
const float co[2],
- const float penalty_dist,
+ float penalty_dist,
struct UvNearestHit *hit);
bool uv_find_nearest_vert_multi(struct Scene *scene,
struct Object **objects,
- const uint objects_len,
+ uint objects_len,
const float co[2],
- const float penalty_dist,
+ float penalty_dist,
struct UvNearestHit *hit);
bool uv_find_nearest_edge(struct Scene *scene,
@@ -89,7 +89,7 @@ bool uv_find_nearest_edge(struct Scene *scene,
struct UvNearestHit *hit);
bool uv_find_nearest_edge_multi(struct Scene *scene,
struct Object **objects,
- const uint objects_len,
+ uint objects_len,
const float co[2],
struct UvNearestHit *hit);
@@ -106,20 +106,20 @@ bool uv_find_nearest_face_ex(struct Scene *scene,
struct Object *obedit,
const float co[2],
struct UvNearestHit *hit,
- const bool only_in_face);
+ bool only_in_face);
bool uv_find_nearest_face(struct Scene *scene,
struct Object *obedit,
const float co[2],
struct UvNearestHit *hit);
bool uv_find_nearest_face_multi_ex(struct Scene *scene,
struct Object **objects,
- const uint objects_len,
+ uint objects_len,
const float co[2],
struct UvNearestHit *hit,
- const bool only_in_face);
+ bool only_in_face);
bool uv_find_nearest_face_multi(struct Scene *scene,
struct Object **objects,
- const uint objects_len,
+ uint objects_len,
const float co[2],
struct UvNearestHit *hit);
@@ -162,14 +162,14 @@ void UV_OT_shortest_path_select(struct wmOperatorType *ot);
bool uvedit_select_is_any_selected(struct Scene *scene, struct Object *obedit);
bool uvedit_select_is_any_selected_multi(struct Scene *scene,
struct Object **objects,
- const uint objects_len);
+ uint objects_len);
/**
* \warning This returns first selected UV,
* not ideal in many cases since there could be multiple.
*/
const float *uvedit_first_selected_uv_from_vertex(struct Scene *scene,
struct BMVert *eve,
- const int cd_loop_uv_offset);
+ int cd_loop_uv_offset);
void UV_OT_select_all(struct wmOperatorType *ot);
void UV_OT_select(struct wmOperatorType *ot);
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);
}
}