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:
authorJacques Lucke <jacques@blender.org>2021-09-17 11:56:46 +0300
committerJacques Lucke <jacques@blender.org>2021-09-17 11:56:46 +0300
commitdcf72a30e174cf2a4a7eeb7c482690b31cdef172 (patch)
treefd220ebf2b45802f82b2328e735d3ac1dfcd97ac
parent0bec1f5dadc0a52dcfe895b8fe04a431d52930ab (diff)
parent9dee0a10c81d9f4ce8d4fc85ed8722d899f34dde (diff)
Merge branch 'master' into temp-field-visualization
-rw-r--r--release/datafiles/userdef/userdef_default.c2
-rw-r--r--release/scripts/modules/bl_keymap_utils/io.py15
-rw-r--r--release/scripts/modules/rna_keymap_ui.py10
-rw-r--r--release/scripts/startup/bl_ui/properties_mask_common.py1
-rw-r--r--release/scripts/startup/bl_ui/space_clip.py1
-rw-r--r--release/scripts/startup/bl_ui/space_dopesheet.py1
-rw-r--r--release/scripts/startup/bl_ui/space_graph.py1
-rw-r--r--release/scripts/startup/bl_ui/space_node.py1
-rw-r--r--release/scripts/startup/bl_ui/space_topbar.py15
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py1
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py15
-rw-r--r--release/scripts/startup/nodeitems_builtins.py2
-rw-r--r--source/blender/blenkernel/BKE_attribute_access.hh7
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh1
-rw-r--r--source/blender/blenkernel/BKE_global.h5
-rw-r--r--source/blender/blenkernel/BKE_idtype.h13
-rw-r--r--source/blender/blenkernel/BKE_lib_id.h4
-rw-r--r--source/blender/blenkernel/BKE_mesh.h2
-rw-r--r--source/blender/blenkernel/BKE_node.h2
-rw-r--r--source/blender/blenkernel/BKE_spline.hh11
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc14
-rw-r--r--source/blender/blenkernel/intern/brush.c8
-rw-r--r--source/blender/blenkernel/intern/displist.cc2
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c2
-rw-r--r--source/blender/blenkernel/intern/fluid.c2
-rw-r--r--source/blender/blenkernel/intern/fmodifier.c8
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curve.cc31
-rw-r--r--source/blender/blenkernel/intern/geometry_component_mesh.cc238
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c3
-rw-r--r--source/blender/blenkernel/intern/idtype.c24
-rw-r--r--source/blender/blenkernel/intern/ipo.c3
-rw-r--r--source/blender/blenkernel/intern/key.c2
-rw-r--r--source/blender/blenkernel/intern/lib_id.c71
-rw-r--r--source/blender/blenkernel/intern/library.c3
-rw-r--r--source/blender/blenkernel/intern/mesh.c6
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.cc (renamed from source/blender/blenkernel/intern/mesh_convert.c)282
-rw-r--r--source/blender/blenkernel/intern/node.cc5
-rw-r--r--source/blender/blenkernel/intern/screen.c2
-rw-r--r--source/blender/blenkernel/intern/spline_base.cc29
-rw-r--r--source/blender/blenkernel/intern/spline_bezier.cc11
-rw-r--r--source/blender/blenkernel/intern/spline_nurbs.cc5
-rw-r--r--source/blender/blenkernel/intern/spline_poly.cc4
-rw-r--r--source/blender/blenkernel/intern/subdiv_mesh.c2
-rw-r--r--source/blender/blenkernel/intern/workspace.c2
-rw-r--r--source/blender/blenlib/BLI_span.hh10
-rw-r--r--source/blender/blenlib/tests/BLI_span_test.cc23
-rw-r--r--source/blender/blenloader/intern/versioning_300.c27
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c2
-rw-r--r--source/blender/editors/armature/armature_add.c4
-rw-r--r--source/blender/editors/curve/editcurve.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c2
-rw-r--r--source/blender/editors/interface/interface_handlers.c19
-rw-r--r--source/blender/editors/interface/interface_layout.c8
-rw-r--r--source/blender/editors/interface/interface_template_search_menu.c3
-rw-r--r--source/blender/editors/interface/interface_templates.c6
-rw-r--r--source/blender/editors/mask/mask_select.c2
-rw-r--r--source/blender/editors/mesh/editmesh_bisect.c2
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c4
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c2
-rw-r--r--source/blender/editors/mesh/editmesh_rip_edge.c2
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c2
-rw-r--r--source/blender/editors/object/object_intern.h1
-rw-r--r--source/blender/editors/object/object_modifier.c51
-rw-r--r--source/blender/editors/object/object_ops.c1
-rw-r--r--source/blender/editors/screen/area.c10
-rw-r--r--source/blender/editors/screen/screen_geometry.c4
-rw-r--r--source/blender/editors/screen/screen_intern.h1
-rw-r--r--source/blender/editors/screen/screen_ops.c1
-rw-r--r--source/blender/editors/screen/screendump.c60
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c8
-rw-r--r--source/blender/editors/space_action/action_select.c2
-rw-r--r--source/blender/editors/space_clip/tracking_select.c2
-rw-r--r--source/blender/editors/space_file/filesel.c3
-rw-r--r--source/blender/editors/space_graph/graph_select.c2
-rw-r--r--source/blender/editors/space_node/node_add.cc2
-rw-r--r--source/blender/editors/space_node/node_relationships.cc4
-rw-r--r--source/blender/editors/space_node/node_select.cc2
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c9
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c2
-rw-r--r--source/blender/editors/transform/transform_ops.c7
-rw-r--r--source/blender/editors/uvedit/uvedit_rip.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_select.c2
-rw-r--r--source/blender/makesdna/DNA_space_types.h7
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h5
-rw-r--r--source/blender/makesrna/intern/rna_ID.c5
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c48
-rw-r--r--source/blender/makesrna/intern/rna_wm.c50
-rw-r--r--source/blender/makesrna/intern/rna_wm_api.c124
-rw-r--r--source/blender/modifiers/intern/MOD_array.c2
-rw-r--r--source/blender/modifiers/intern/MOD_bevel.c2
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.cc6
-rw-r--r--source/blender/modifiers/intern/MOD_build.c2
-rw-r--r--source/blender/modifiers/intern/MOD_decimate.c2
-rw-r--r--source/blender/modifiers/intern/MOD_edgesplit.c2
-rw-r--r--source/blender/modifiers/intern/MOD_mask.cc3
-rw-r--r--source/blender/modifiers/intern/MOD_mirror.c2
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc108
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.c2
-rw-r--r--source/blender/modifiers/intern/MOD_ocean.c4
-rw-r--r--source/blender/modifiers/intern/MOD_particleinstance.c2
-rw-r--r--source/blender/modifiers/intern/MOD_remesh.c2
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c4
-rw-r--r--source/blender/modifiers/intern/MOD_skin.c2
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_extrude.c2
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_nonmanifold.c2
-rw-r--r--source/blender/modifiers/intern/MOD_triangulate.c2
-rw-r--r--source/blender/modifiers/intern/MOD_util.c1
-rw-r--r--source/blender/modifiers/intern/MOD_weld.c3
-rw-r--r--source/blender/modifiers/intern/MOD_wireframe.c2
-rw-r--r--source/blender/nodes/CMakeLists.txt5
-rw-r--r--source/blender/nodes/NOD_geometry.h5
-rw-r--r--source/blender/nodes/NOD_static_types.h2
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_material_assign.cc95
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_select_by_material.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_select_by_material.cc)10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc62
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc512
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_material_assign.cc29
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_material_selection.cc131
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_position.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc7
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transform.cc3
-rw-r--r--source/blender/python/generic/idprop_py_api.c3
-rw-r--r--source/blender/render/intern/render_result.c3
-rw-r--r--source/blender/windowmanager/WM_api.h6
-rw-r--r--source/blender/windowmanager/WM_types.h25
-rw-r--r--source/blender/windowmanager/intern/wm.c3
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c26
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c194
-rw-r--r--source/blender/windowmanager/intern/wm_files.c54
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c59
-rw-r--r--source/blender/windowmanager/intern/wm_gesture_ops.c2
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c29
-rw-r--r--source/blender/windowmanager/intern/wm_window.c8
-rw-r--r--source/blender/windowmanager/wm_cursors.h2
-rw-r--r--tests/python/CMakeLists.txt2
139 files changed, 2195 insertions, 657 deletions
diff --git a/release/datafiles/userdef/userdef_default.c b/release/datafiles/userdef/userdef_default.c
index 29288dcd8fd..b82d78b927e 100644
--- a/release/datafiles/userdef/userdef_default.c
+++ b/release/datafiles/userdef/userdef_default.c
@@ -231,7 +231,7 @@ const UserDef U_default = {
.collection_instance_empty_size = 1.0f,
.statusbar_flag = STATUSBAR_SHOW_VERSION,
- .file_preview_type = USER_FILE_PREVIEW_CAMERA,
+ .file_preview_type = USER_FILE_PREVIEW_AUTO,
.runtime =
{
diff --git a/release/scripts/modules/bl_keymap_utils/io.py b/release/scripts/modules/bl_keymap_utils/io.py
index 96832cbd9c7..d8b68822feb 100644
--- a/release/scripts/modules/bl_keymap_utils/io.py
+++ b/release/scripts/modules/bl_keymap_utils/io.py
@@ -63,16 +63,11 @@ def kmi_args_as_data(kmi):
if kmi.any:
s.append("\"any\": True")
else:
- if kmi.shift:
- s.append("\"shift\": True")
- if kmi.ctrl:
- s.append("\"ctrl\": True")
- if kmi.alt:
- s.append("\"alt\": True")
- if kmi.oskey:
- s.append("\"oskey\": True")
- if kmi.key_modifier and kmi.key_modifier != 'NONE':
- s.append(f"\"key_modifier\": '{kmi.key_modifier}'")
+ for attr in ("shift", "ctrl", "alt", "oskey"):
+ if mod := getattr(kmi, attr):
+ s.append(f"\"{attr:s}\": " + ("-1" if mod == -1 else "True"))
+ if (mod := kmi.key_modifier) and (mod != 'NONE'):
+ s.append(f"\"key_modifier\": '{mod:s}'")
if kmi.repeat:
if (
diff --git a/release/scripts/modules/rna_keymap_ui.py b/release/scripts/modules/rna_keymap_ui.py
index b42539ac44a..08035d25481 100644
--- a/release/scripts/modules/rna_keymap_ui.py
+++ b/release/scripts/modules/rna_keymap_ui.py
@@ -199,10 +199,12 @@ def draw_kmi(display_keymaps, kc, km, kmi, layout, level):
subrow = sub.row()
subrow.scale_x = 0.75
subrow.prop(kmi, "any", toggle=True)
- subrow.prop(kmi, "shift", toggle=True)
- subrow.prop(kmi, "ctrl", toggle=True)
- subrow.prop(kmi, "alt", toggle=True)
- subrow.prop(kmi, "oskey", text="Cmd", toggle=True)
+ # Use `*_ui` properties as integers aren't practical.
+ subrow.prop(kmi, "shift_ui", toggle=True)
+ subrow.prop(kmi, "ctrl_ui", toggle=True)
+ subrow.prop(kmi, "alt_ui", toggle=True)
+ subrow.prop(kmi, "oskey_ui", text="Cmd", toggle=True)
+
subrow.prop(kmi, "key_modifier", text="", event=True)
# Operator properties
diff --git a/release/scripts/startup/bl_ui/properties_mask_common.py b/release/scripts/startup/bl_ui/properties_mask_common.py
index 40a704a65dd..705539e979c 100644
--- a/release/scripts/startup/bl_ui/properties_mask_common.py
+++ b/release/scripts/startup/bl_ui/properties_mask_common.py
@@ -417,6 +417,7 @@ class MASK_MT_select(Menu):
layout.operator("mask.select_box")
layout.operator("mask.select_circle")
+ layout.operator_menu_enum("mask.select_lasso", "mode")
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py
index a1e5b509295..c18d77987ad 100644
--- a/release/scripts/startup/bl_ui/space_clip.py
+++ b/release/scripts/startup/bl_ui/space_clip.py
@@ -1578,6 +1578,7 @@ class CLIP_MT_select(Menu):
layout.operator("clip.select_box")
layout.operator("clip.select_circle")
+ layout.operator_menu_enum("clip.select_lasso", "mode")
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py
index 84d1c36c53d..781c430a752 100644
--- a/release/scripts/startup/bl_ui/space_dopesheet.py
+++ b/release/scripts/startup/bl_ui/space_dopesheet.py
@@ -394,6 +394,7 @@ class DOPESHEET_MT_select(Menu):
layout.operator("action.select_box", text="Box Select (Axis Range)").axis_range = True
layout.operator("action.select_circle")
+ layout.operator_menu_enum("action.select_lasso", "mode")
layout.separator()
layout.operator("action.select_column", text="Columns on Selected Keys").mode = 'KEYS'
diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py
index f8521592dd9..612b7ba2b09 100644
--- a/release/scripts/startup/bl_ui/space_graph.py
+++ b/release/scripts/startup/bl_ui/space_graph.py
@@ -179,6 +179,7 @@ class GRAPH_MT_select(Menu):
props.include_handles = True
layout.operator("graph.select_circle")
+ layout.operator_menu_enum("graph.select_lasso", "mode")
layout.separator()
layout.operator("graph.select_column", text="Columns on Selected Keys").mode = 'KEYS'
diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py
index fba86676ad4..5f36009901a 100644
--- a/release/scripts/startup/bl_ui/space_node.py
+++ b/release/scripts/startup/bl_ui/space_node.py
@@ -289,6 +289,7 @@ class NODE_MT_select(Menu):
layout.operator("node.select_box").tweak = False
layout.operator("node.select_circle")
+ layout.operator_menu_enum("node.select_lasso", "mode")
layout.separator()
layout.operator("node.select_all").action = 'TOGGLE'
diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py
index bacca6dedc2..1d75ad8ff0a 100644
--- a/release/scripts/startup/bl_ui/space_topbar.py
+++ b/release/scripts/startup/bl_ui/space_topbar.py
@@ -209,9 +209,9 @@ class TOPBAR_MT_editor_menus(Menu):
# Allow calling this menu directly (this might not be a header area).
if getattr(context.area, "show_menus", False):
- layout.menu("TOPBAR_MT_app", text="", icon='BLENDER')
+ layout.menu("TOPBAR_MT_blender", text="", icon='BLENDER')
else:
- layout.menu("TOPBAR_MT_app", text="Blender")
+ layout.menu("TOPBAR_MT_blender", text="Blender")
layout.menu("TOPBAR_MT_file")
layout.menu("TOPBAR_MT_edit")
@@ -222,7 +222,7 @@ class TOPBAR_MT_editor_menus(Menu):
layout.menu("TOPBAR_MT_help")
-class TOPBAR_MT_app(Menu):
+class TOPBAR_MT_blender(Menu):
bl_label = "Blender"
def draw(self, _context):
@@ -238,7 +238,7 @@ class TOPBAR_MT_app(Menu):
layout.separator()
- layout.menu("TOPBAR_MT_app_system")
+ layout.menu("TOPBAR_MT_blender_system")
class TOPBAR_MT_file_cleanup(Menu):
@@ -430,7 +430,7 @@ class TOPBAR_MT_file_defaults(Menu):
# Include technical operators here which would otherwise have no way for users to access.
-class TOPBAR_MT_app_system(Menu):
+class TOPBAR_MT_blender_system(Menu):
bl_label = "System"
def draw(self, _context):
@@ -655,6 +655,7 @@ class TOPBAR_MT_window(Menu):
layout.separator()
layout.operator("screen.screenshot")
+ layout.operator("screen.screenshot_area")
if sys.platform[:3] == "win":
layout.separator()
@@ -854,8 +855,8 @@ classes = (
TOPBAR_MT_file_context_menu,
TOPBAR_MT_workspace_menu,
TOPBAR_MT_editor_menus,
- TOPBAR_MT_app,
- TOPBAR_MT_app_system,
+ TOPBAR_MT_blender,
+ TOPBAR_MT_blender_system,
TOPBAR_MT_file,
TOPBAR_MT_file_new,
TOPBAR_MT_file_recover,
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 1711519bce1..0093110d326 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -267,7 +267,6 @@ class USERPREF_PT_interface_editors(InterfacePanel, CenterAlignMixIn, Panel):
col = layout.column()
col.prop(system, "use_region_overlap")
- col.prop(view, "show_layout_ui", text="Corner Splitting")
col.prop(view, "show_navigate_ui")
col.prop(view, "color_picker_type")
col.row().prop(view, "header_align")
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index c6bc6d9b5d3..a332295715c 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -1362,6 +1362,7 @@ class VIEW3D_MT_select_object(Menu):
layout.operator("view3d.select_box")
layout.operator("view3d.select_circle")
+ layout.operator_menu_enum("view3d.select_lasso", "mode")
layout.separator()
@@ -1422,6 +1423,7 @@ class VIEW3D_MT_select_pose(Menu):
layout.operator("view3d.select_box")
layout.operator("view3d.select_circle")
+ layout.operator_menu_enum("view3d.select_lasso", "mode")
layout.separator()
@@ -1456,6 +1458,7 @@ class VIEW3D_MT_select_particle(Menu):
layout.operator("view3d.select_box")
layout.operator("view3d.select_circle")
+ layout.operator_menu_enum("view3d.select_lasso", "mode")
layout.separator()
@@ -1562,6 +1565,7 @@ class VIEW3D_MT_select_edit_mesh(Menu):
layout.operator("view3d.select_box")
layout.operator("view3d.select_circle")
+ layout.operator_menu_enum("view3d.select_lasso", "mode")
layout.separator()
@@ -1615,6 +1619,7 @@ class VIEW3D_MT_select_edit_curve(Menu):
layout.operator("view3d.select_box")
layout.operator("view3d.select_circle")
+ layout.operator_menu_enum("view3d.select_lasso", "mode")
layout.separator()
@@ -1650,6 +1655,7 @@ class VIEW3D_MT_select_edit_surface(Menu):
layout.operator("view3d.select_box")
layout.operator("view3d.select_circle")
+ layout.operator_menu_enum("view3d.select_lasso", "mode")
layout.separator()
@@ -1711,6 +1717,7 @@ class VIEW3D_MT_select_edit_metaball(Menu):
layout.operator("view3d.select_box")
layout.operator("view3d.select_circle")
+ layout.operator_menu_enum("view3d.select_lasso", "mode")
layout.separator()
@@ -1752,6 +1759,7 @@ class VIEW3D_MT_select_edit_lattice(Menu):
layout.operator("view3d.select_box")
layout.operator("view3d.select_circle")
+ layout.operator_menu_enum("view3d.select_lasso", "mode")
layout.separator()
@@ -1782,6 +1790,7 @@ class VIEW3D_MT_select_edit_armature(Menu):
layout.operator("view3d.select_box")
layout.operator("view3d.select_circle")
+ layout.operator_menu_enum("view3d.select_lasso", "mode")
layout.separator()
@@ -1849,6 +1858,7 @@ class VIEW3D_MT_select_gpencil(Menu):
layout.operator("gpencil.select_box")
layout.operator("gpencil.select_circle")
+ layout.operator_menu_enum("gpencil.select_lasso", "mode")
layout.separator()
@@ -1885,6 +1895,7 @@ class VIEW3D_MT_select_paint_mask(Menu):
layout.operator("view3d.select_box")
layout.operator("view3d.select_circle")
+ layout.operator_menu_enum("view3d.select_lasso", "mode")
layout.separator()
@@ -1905,6 +1916,7 @@ class VIEW3D_MT_select_paint_mask_vertex(Menu):
layout.operator("view3d.select_box")
layout.operator("view3d.select_circle")
+ layout.operator_menu_enum("view3d.select_lasso", "mode")
layout.separator()
@@ -3983,6 +3995,7 @@ class VIEW3D_MT_edit_mesh_vertices(Menu):
layout.operator_context = 'INVOKE_REGION_WIN'
layout.operator("mesh.extrude_vertices_move", text="Extrude Vertices")
+ layout.operator("mesh.dupli_extrude_cursor").rotate_source = True
layout.operator("mesh.bevel", text="Bevel Vertices").affect = 'VERTICES'
layout.separator()
@@ -4414,6 +4427,7 @@ class VIEW3D_MT_edit_curve_ctrlpoints(Menu):
if edit_object.type in {'CURVE', 'SURFACE'}:
layout.operator("curve.extrude_move")
+ layout.operator("curve.vertex_add")
layout.separator()
@@ -4742,6 +4756,7 @@ class VIEW3D_MT_edit_armature(Menu):
layout.separator()
layout.operator("armature.extrude_move")
+ layout.operator("armature.click_extrude")
if arm.use_mirror_x:
layout.operator("armature.extrude_forked")
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index c0af91b7ad6..569c5291576 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -564,6 +564,8 @@ geometry_node_categories = [
NodeItem("GeometryNodeLegacyMaterialAssign", poll=geometry_nodes_fields_legacy_poll),
NodeItem("GeometryNodeLegacySelectByMaterial", poll=geometry_nodes_fields_legacy_poll),
+ NodeItem("GeometryNodeMaterialAssign", poll=geometry_nodes_fields_poll),
+ NodeItem("GeometryNodeMaterialSelection", poll=geometry_nodes_fields_poll),
NodeItem("GeometryNodeMaterialReplace"),
]),
GeometryNodeCategory("GEO_MESH", "Mesh", items=[
diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh
index 9d309d8a1c1..cf54e7efa0d 100644
--- a/source/blender/blenkernel/BKE_attribute_access.hh
+++ b/source/blender/blenkernel/BKE_attribute_access.hh
@@ -247,7 +247,7 @@ class OutputAttribute {
GVMutableArrayPtr varray_;
AttributeDomain domain_;
SaveFn save_;
- std::optional<fn::GVMutableArray_GSpan> optional_span_varray_;
+ std::unique_ptr<fn::GVMutableArray_GSpan> optional_span_varray_;
bool ignore_old_values_ = false;
bool save_has_been_called_ = false;
@@ -306,9 +306,10 @@ class OutputAttribute {
fn::GMutableSpan as_span()
{
- if (!optional_span_varray_.has_value()) {
+ if (!optional_span_varray_) {
const bool materialize_old_values = !ignore_old_values_;
- optional_span_varray_.emplace(*varray_, materialize_old_values);
+ optional_span_varray_ = std::make_unique<fn::GVMutableArray_GSpan>(*varray_,
+ materialize_old_values);
}
fn::GVMutableArray_GSpan &span_varray = *optional_span_varray_;
return span_varray;
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index 3da35cb4fe1..bf38294257a 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -103,6 +103,7 @@ class GeometryComponent {
virtual int attribute_domain_size(const AttributeDomain domain) const;
bool attribute_is_builtin(const blender::StringRef attribute_name) const;
+ bool attribute_is_builtin(const blender::bke::AttributeIDRef &attribute_id) const;
/* Get read-only access to the highest priority attribute with the given name.
* Returns null if the attribute does not exist. */
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index 89713e9ad0a..7696b5c0189 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -124,7 +124,10 @@ enum {
/** Don't overwrite these flags when reading a file. */
#define G_FLAG_ALL_RUNTIME \
(G_FLAG_SCRIPT_AUTOEXEC | G_FLAG_SCRIPT_OVERRIDE_PREF | G_FLAG_EVENT_SIMULATE | \
- G_FLAG_USERPREF_NO_SAVE_ON_EXIT)
+ G_FLAG_USERPREF_NO_SAVE_ON_EXIT | \
+\
+ /* #BPY_python_reset is responsible for resetting these flags on file load. */ \
+ G_FLAG_SCRIPT_AUTOEXEC_FAIL | G_FLAG_SCRIPT_AUTOEXEC_FAIL_QUIET)
/** Flags to read from blend file. */
#define G_FLAG_ALL_READFILE 0
diff --git a/source/blender/blenkernel/BKE_idtype.h b/source/blender/blenkernel/BKE_idtype.h
index b0939ec884d..7136a3fd7af 100644
--- a/source/blender/blenkernel/BKE_idtype.h
+++ b/source/blender/blenkernel/BKE_idtype.h
@@ -45,8 +45,10 @@ enum {
IDTYPE_FLAGS_NO_COPY = 1 << 0,
/** Indicates that the given IDType does not support linking/appending from a library file. */
IDTYPE_FLAGS_NO_LIBLINKING = 1 << 1,
- /** Indicates that the given IDType does not support making a library-linked ID local. */
- IDTYPE_FLAGS_NO_MAKELOCAL = 1 << 2,
+ /** Indicates that the given IDType should not be directly linked from a library file, but may be
+ * appended.
+ * NOTE: Mutually exclusive with `IDTYPE_FLAGS_NO_LIBLINKING`. */
+ IDTYPE_FLAGS_ONLY_APPEND = 1 << 2,
/** Indicates that the given IDType does not have animation data. */
IDTYPE_FLAGS_NO_ANIMDATA = 1 << 3,
};
@@ -283,9 +285,14 @@ const struct IDTypeInfo *BKE_idtype_get_info_from_id(const struct ID *id);
const char *BKE_idtype_idcode_to_name(const short idcode);
const char *BKE_idtype_idcode_to_name_plural(const short idcode);
const char *BKE_idtype_idcode_to_translation_context(const short idcode);
-bool BKE_idtype_idcode_is_linkable(const short idcode);
+
bool BKE_idtype_idcode_is_valid(const short idcode);
+bool BKE_idtype_idcode_is_linkable(const short idcode);
+bool BKE_idtype_idcode_is_only_appendable(const short idcode);
+/* Macro currently, since any linkable IDtype should be localizable. */
+#define BKE_idtype_idcode_is_localizable BKE_idtype_idcode_is_linkable
+
short BKE_idtype_idcode_from_name(const char *idtype_name);
uint64_t BKE_idtype_idcode_to_idfilter(const short idcode);
diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h
index 7fa21cc0656..36f57209e33 100644
--- a/source/blender/blenkernel/BKE_lib_id.h
+++ b/source/blender/blenkernel/BKE_lib_id.h
@@ -230,7 +230,7 @@ void id_us_plus(struct ID *id);
void id_us_min(struct ID *id);
void id_fake_user_set(struct ID *id);
void id_fake_user_clear(struct ID *id);
-void BKE_id_clear_newpoin(struct ID *id);
+void BKE_id_newptr_and_tag_clear(struct ID *id);
/** Flags to control make local code behavior. */
enum {
@@ -248,7 +248,7 @@ enum {
};
void BKE_lib_id_make_local_generic(struct Main *bmain, struct ID *id, const int flags);
-bool BKE_lib_id_make_local(struct Main *bmain, struct ID *id, const bool test, const int flags);
+bool BKE_lib_id_make_local(struct Main *bmain, struct ID *id, const int flags);
bool id_single_user(struct bContext *C,
struct ID *id,
struct PointerRNA *ptr,
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index dbcefb8b6d5..b0a8fee1178 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -123,7 +123,7 @@ void BKE_mesh_eval_delete(struct Mesh *mesh_eval);
/* Performs copy for use during evaluation,
* optional referencing original arrays to reduce memory. */
-struct Mesh *BKE_mesh_copy_for_eval(struct Mesh *source, bool reference);
+struct Mesh *BKE_mesh_copy_for_eval(const struct Mesh *source, bool reference);
/* These functions construct a new Mesh,
* contrary to BKE_mesh_to_curve_nurblist which modifies ob itself. */
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 2f099495d02..5603b78d259 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1491,6 +1491,8 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_INPUT_INDEX 1078
#define GEO_NODE_INPUT_NORMAL 1079
#define GEO_NODE_ATTRIBUTE_CAPTURE 1080
+#define GEO_NODE_MATERIAL_SELECTION 1081
+#define GEO_NODE_MATERIAL_ASSIGN 1082
/** \} */
diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh
index fc145f1ddf1..0fbf39a52fa 100644
--- a/source/blender/blenkernel/BKE_spline.hh
+++ b/source/blender/blenkernel/BKE_spline.hh
@@ -131,6 +131,11 @@ class Spline {
virtual void transform(const blender::float4x4 &matrix);
/**
+ * Change the direction of the spline (switch the start and end) without changing its shape.
+ */
+ void reverse();
+
+ /**
* Mark all caches for re-computation. This must be called after any operation that would
* change the generated positions, tangents, normals, mapping, etc. of the evaluated points.
*/
@@ -210,6 +215,7 @@ class Spline {
virtual void correct_end_tangents() const = 0;
virtual void copy_settings(Spline &dst) const = 0;
virtual void copy_data(Spline &dst) const = 0;
+ virtual void reverse_impl() = 0;
};
/**
@@ -353,6 +359,9 @@ class BezierSpline final : public Spline {
void correct_end_tangents() const final;
void copy_settings(Spline &dst) const final;
void copy_data(Spline &dst) const final;
+
+ protected:
+ void reverse_impl() override;
};
/**
@@ -469,6 +478,7 @@ class NURBSpline final : public Spline {
void correct_end_tangents() const final;
void copy_settings(Spline &dst) const final;
void copy_data(Spline &dst) const final;
+ void reverse_impl() override;
void calculate_knots() const;
blender::Span<BasisCache> calculate_basis_cache() const;
@@ -519,6 +529,7 @@ class PolySpline final : public Spline {
void correct_end_tangents() const final;
void copy_settings(Spline &dst) const final;
void copy_data(Spline &dst) const final;
+ void reverse_impl() override;
};
/**
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 26d81ec3b34..0b082bf1c5a 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -186,7 +186,7 @@ set(SRC
intern/mball_tessellate.c
intern/mesh.c
intern/mesh_boolean_convert.cc
- intern/mesh_convert.c
+ intern/mesh_convert.cc
intern/mesh_evaluate.cc
intern/mesh_fair.cc
intern/mesh_iterators.c
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index bdf1891a55a..8c4f87be91f 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -190,7 +190,7 @@ AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains)
void OutputAttribute::save()
{
save_has_been_called_ = true;
- if (optional_span_varray_.has_value()) {
+ if (optional_span_varray_) {
optional_span_varray_->save();
}
if (save_) {
@@ -817,6 +817,12 @@ bool GeometryComponent::attribute_is_builtin(const blender::StringRef attribute_
return providers->builtin_attribute_providers().contains_as(attribute_name);
}
+bool GeometryComponent::attribute_is_builtin(const AttributeIDRef &attribute_id) const
+{
+ /* Anonymous attributes cannot be built-in. */
+ return attribute_id.is_named() && this->attribute_is_builtin(attribute_id.name());
+}
+
blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read(
const AttributeIDRef &attribute_id) const
{
@@ -1210,7 +1216,7 @@ static OutputAttribute create_output_attribute(GeometryComponent &component,
BLI_assert(cpp_type != nullptr);
const nodes::DataTypeConversions &conversions = nodes::get_implicit_type_conversions();
- if (attribute_id.is_named() && component.attribute_is_builtin(attribute_id.name())) {
+ if (component.attribute_is_builtin(attribute_id)) {
const StringRef attribute_name = attribute_id.name();
WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_name);
if (!attribute) {
@@ -1315,7 +1321,9 @@ const GVArray *AttributeFieldInput::get_varray_for_context(const fn::FieldContex
const AttributeDomain domain = geometry_context->domain();
const CustomDataType data_type = cpp_type_to_custom_data_type(*type_);
GVArrayPtr attribute = component.attribute_try_get_for_read(name_, domain, data_type);
- return scope.add(std::move(attribute));
+ if (attribute) {
+ return scope.add(std::move(attribute));
+ }
}
return nullptr;
}
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 50264f348e9..d70b941695e 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -161,7 +161,13 @@ static void brush_make_local(Main *bmain, ID *id, const int flags)
if (brush->clone.image) {
/* Special case: ima always local immediately. Clone image should only have one user anyway. */
- BKE_lib_id_make_local(bmain, &brush->clone.image->id, false, 0);
+ /* FIXME: Recursive calls affecting other non-embedded IDs are really bad and should be avoided
+ * in IDType callbacks. Higher-level ID management code usually does not expect such things and
+ * does not deal properly with it. */
+ /* NOTE: assert below ensures that the comment above is valid, and that that exception is
+ * acceptable for the time being. */
+ BKE_lib_id_make_local(bmain, &brush->clone.image->id, 0);
+ BLI_assert(brush->clone.image->id.lib == NULL && brush->clone.image->id.newid == NULL);
}
if (!force_local && !force_copy) {
diff --git a/source/blender/blenkernel/intern/displist.cc b/source/blender/blenkernel/intern/displist.cc
index f37978d14bb..e756daa1156 100644
--- a/source/blender/blenkernel/intern/displist.cc
+++ b/source/blender/blenkernel/intern/displist.cc
@@ -1504,7 +1504,7 @@ void BKE_displist_make_curveTypes(Depsgraph *depsgraph,
cow_curve.curve_eval = nullptr;
ob->runtime.curve_cache = (CurveCache *)MEM_callocN(sizeof(CurveCache), __func__);
- ListBase *dispbase = &(ob->runtime.curve_cache->disp);
+ ListBase *dispbase = &ob->runtime.curve_cache->disp;
if (ob->type == OB_SURF) {
Mesh *mesh_eval;
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 0dc4f64cec1..d75b3259148 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -2064,7 +2064,7 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object *
}
if (update_normals) {
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
}
}
/* make a copy of mesh to use as brush data */
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index f13ed1f2bf7..1324b37f39c 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -3573,7 +3573,7 @@ static Mesh *create_smoke_geometry(FluidDomainSettings *fds, Mesh *orgmesh, Obje
}
BKE_mesh_calc_edges(result, false, false);
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
return result;
}
diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c
index 5aa3815729f..121927513cc 100644
--- a/source/blender/blenkernel/intern/fmodifier.c
+++ b/source/blender/blenkernel/intern/fmodifier.c
@@ -1419,17 +1419,19 @@ static float eval_fmodifier_influence(FModifier *fcm, float evaltime)
/* restricted range or full range? */
if (fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) {
- if ((evaltime <= fcm->sfra) || (evaltime >= fcm->efra)) {
+ if ((evaltime < fcm->sfra) || (evaltime > fcm->efra)) {
/* out of range */
return 0.0f;
}
- if ((evaltime > fcm->sfra) && (evaltime < fcm->sfra + fcm->blendin)) {
+ if ((fcm->blendin != 0.0f) && (evaltime >= fcm->sfra) &&
+ (evaltime <= fcm->sfra + fcm->blendin)) {
/* blend in range */
float a = fcm->sfra;
float b = fcm->sfra + fcm->blendin;
return influence * (evaltime - a) / (b - a);
}
- if ((evaltime < fcm->efra) && (evaltime > fcm->efra - fcm->blendout)) {
+ if ((fcm->blendout != 0.0f) && (evaltime <= fcm->efra) &&
+ (evaltime >= fcm->efra - fcm->blendout)) {
/* blend out range */
float a = fcm->efra;
float b = fcm->efra - fcm->blendout;
diff --git a/source/blender/blenkernel/intern/geometry_component_curve.cc b/source/blender/blenkernel/intern/geometry_component_curve.cc
index afafd766760..7d0537178ef 100644
--- a/source/blender/blenkernel/intern/geometry_component_curve.cc
+++ b/source/blender/blenkernel/intern/geometry_component_curve.cc
@@ -222,6 +222,37 @@ static void adapt_curve_domain_point_to_spline_impl(const CurveEval &curve,
mixer.finalize();
}
+/**
+ * A spline is selected if all of its control points were selected.
+ *
+ * \note Theoretically this interpolation does not need to compute all values at once.
+ * However, doing that makes the implementation simpler, and this can be optimized in the future if
+ * only some values are required.
+ */
+template<>
+void adapt_curve_domain_point_to_spline_impl(const CurveEval &curve,
+ const VArray<bool> &old_values,
+ MutableSpan<bool> r_values)
+{
+ const int splines_len = curve.splines().size();
+ Array<int> offsets = curve.control_point_offsets();
+ BLI_assert(r_values.size() == splines_len);
+
+ r_values.fill(true);
+
+ for (const int i_spline : IndexRange(splines_len)) {
+ const int spline_offset = offsets[i_spline];
+ const int spline_point_len = offsets[i_spline + 1] - spline_offset;
+
+ for (const int i_point : IndexRange(spline_point_len)) {
+ if (!old_values[spline_offset + i_point]) {
+ r_values[i_spline] = false;
+ break;
+ }
+ }
+ }
+}
+
static GVArrayPtr adapt_curve_domain_point_to_spline(const CurveEval &curve, GVArrayPtr varray)
{
GVArrayPtr new_varray;
diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc
index 9a4b8f4eb92..0c98aa5551b 100644
--- a/source/blender/blenkernel/intern/geometry_component_mesh.cc
+++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc
@@ -175,6 +175,34 @@ static void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh,
mixer.finalize();
}
+/* A vertex is selected if all connected face corners were selected and it is not loose. */
+template<>
+void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh,
+ const VArray<bool> &old_values,
+ MutableSpan<bool> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totvert);
+ Array<bool> loose_verts(mesh.totvert, true);
+
+ r_values.fill(true);
+ for (const int loop_index : IndexRange(mesh.totloop)) {
+ const MLoop &loop = mesh.mloop[loop_index];
+ const int point_index = loop.v;
+
+ loose_verts[point_index] = false;
+ if (!old_values[loop_index]) {
+ r_values[point_index] = false;
+ }
+ }
+
+ /* Deselect loose vertices without corners that are still selected from the 'true' default. */
+ for (const int vert_index : IndexRange(mesh.totvert)) {
+ if (loose_verts[vert_index]) {
+ r_values[vert_index] = false;
+ }
+ }
+}
+
static GVArrayPtr adapt_mesh_domain_corner_to_point(const Mesh &mesh, GVArrayPtr varray)
{
GVArrayPtr new_varray;
@@ -191,6 +219,13 @@ static GVArrayPtr adapt_mesh_domain_corner_to_point(const Mesh &mesh, GVArrayPtr
return new_varray;
}
+/**
+ * Each corner's value is simply a copy of the value at its vertex.
+ *
+ * \note Theoretically this interpolation does not need to compute all values at once.
+ * However, doing that makes the implementation simpler, and this can be optimized in the future if
+ * only some values are required.
+ */
template<typename T>
static void adapt_mesh_domain_point_to_corner_impl(const Mesh &mesh,
const VArray<T> &old_values,
@@ -209,10 +244,6 @@ static GVArrayPtr adapt_mesh_domain_point_to_corner(const Mesh &mesh, GVArrayPtr
GVArrayPtr new_varray;
attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) {
using T = decltype(dummy);
- /* It is not strictly necessary to compute the value for all corners here. Instead one could
- * lazily lookup the mesh topology when a specific index accessed. This can be more efficient
- * when an algorithm only accesses very few of the corner values. However, for the algorithms
- * we currently have, precomputing the array is fine. Also, it is easier to implement. */
Array<T> values(mesh.totloop);
adapt_mesh_domain_point_to_corner_impl<T>(mesh, varray->typed<T>(), values);
new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
@@ -244,6 +275,26 @@ static void adapt_mesh_domain_corner_to_face_impl(const Mesh &mesh,
mixer.finalize();
}
+/* A face is selected if all of its corners were selected. */
+template<>
+void adapt_mesh_domain_corner_to_face_impl(const Mesh &mesh,
+ const VArray<bool> &old_values,
+ MutableSpan<bool> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totpoly);
+
+ r_values.fill(true);
+ for (const int poly_index : IndexRange(mesh.totpoly)) {
+ const MPoly &poly = mesh.mpoly[poly_index];
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ if (!old_values[loop_index]) {
+ r_values[poly_index] = false;
+ break;
+ }
+ }
+ }
+}
+
static GVArrayPtr adapt_mesh_domain_corner_to_face(const Mesh &mesh, GVArrayPtr varray)
{
GVArrayPtr new_varray;
@@ -282,6 +333,41 @@ static void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh,
mixer.finalize();
}
+/* An edge is selected if all corners on adjacent faces were selected. */
+template<>
+void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh,
+ const VArray<bool> &old_values,
+ MutableSpan<bool> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totedge);
+
+ /* It may be possible to rely on the #ME_LOOSEEDGE flag, but that seems error-prone. */
+ Array<bool> loose_edges(mesh.totedge, true);
+
+ r_values.fill(true);
+ for (const int poly_index : IndexRange(mesh.totpoly)) {
+ const MPoly &poly = mesh.mpoly[poly_index];
+
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const int loop_index_next = (loop_index == poly.totloop) ? poly.loopstart : (loop_index + 1);
+ const MLoop &loop = mesh.mloop[loop_index];
+ const int edge_index = loop.e;
+ loose_edges[edge_index] = false;
+
+ if (!old_values[loop_index] || !old_values[loop_index_next]) {
+ r_values[edge_index] = false;
+ }
+ }
+ }
+
+ /* Deselect loose edges without corners that are still selected from the 'true' default. */
+ for (const int edge_index : IndexRange(mesh.totedge)) {
+ if (loose_edges[edge_index]) {
+ r_values[edge_index] = false;
+ }
+ }
+}
+
static GVArrayPtr adapt_mesh_domain_corner_to_edge(const Mesh &mesh, GVArrayPtr varray)
{
GVArrayPtr new_varray;
@@ -317,6 +403,27 @@ void adapt_mesh_domain_face_to_point_impl(const Mesh &mesh,
mixer.finalize();
}
+/* A vertex is selected if any of the connected faces were selected. */
+template<>
+void adapt_mesh_domain_face_to_point_impl(const Mesh &mesh,
+ const VArray<bool> &old_values,
+ MutableSpan<bool> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totvert);
+
+ r_values.fill(false);
+ for (const int poly_index : IndexRange(mesh.totpoly)) {
+ const MPoly &poly = mesh.mpoly[poly_index];
+ if (old_values[poly_index]) {
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const MLoop &loop = mesh.mloop[loop_index];
+ const int vert_index = loop.v;
+ r_values[vert_index] = true;
+ }
+ }
+ }
+}
+
static GVArrayPtr adapt_mesh_domain_face_to_point(const Mesh &mesh, GVArrayPtr varray)
{
GVArrayPtr new_varray;
@@ -331,6 +438,7 @@ static GVArrayPtr adapt_mesh_domain_face_to_point(const Mesh &mesh, GVArrayPtr v
return new_varray;
}
+/* Each corner's value is simply a copy of the value at its face. */
template<typename T>
void adapt_mesh_domain_face_to_corner_impl(const Mesh &mesh,
const VArray<T> &old_values,
@@ -378,6 +486,27 @@ void adapt_mesh_domain_face_to_edge_impl(const Mesh &mesh,
mixer.finalize();
}
+/* An edge is selected if any connected face was selected. */
+template<>
+void adapt_mesh_domain_face_to_edge_impl(const Mesh &mesh,
+ const VArray<bool> &old_values,
+ MutableSpan<bool> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totedge);
+
+ r_values.fill(false);
+ for (const int poly_index : IndexRange(mesh.totpoly)) {
+ const MPoly &poly = mesh.mpoly[poly_index];
+ if (old_values[poly_index]) {
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const MLoop &loop = mesh.mloop[loop_index];
+ const int edge_index = loop.e;
+ r_values[edge_index] = true;
+ }
+ }
+ }
+}
+
static GVArrayPtr adapt_mesh_domain_face_to_edge(const Mesh &mesh, GVArrayPtr varray)
{
GVArrayPtr new_varray;
@@ -416,6 +545,28 @@ static void adapt_mesh_domain_point_to_face_impl(const Mesh &mesh,
mixer.finalize();
}
+/* A face is selected if all of its vertices were selected too. */
+template<>
+void adapt_mesh_domain_point_to_face_impl(const Mesh &mesh,
+ const VArray<bool> &old_values,
+ MutableSpan<bool> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totpoly);
+
+ r_values.fill(true);
+ for (const int poly_index : IndexRange(mesh.totpoly)) {
+ const MPoly &poly = mesh.mpoly[poly_index];
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ MLoop &loop = mesh.mloop[loop_index];
+ const int vert_index = loop.v;
+ if (!old_values[vert_index]) {
+ r_values[poly_index] = false;
+ break;
+ }
+ }
+ }
+}
+
static GVArrayPtr adapt_mesh_domain_point_to_face(const Mesh &mesh, GVArrayPtr varray)
{
GVArrayPtr new_varray;
@@ -452,6 +603,20 @@ static void adapt_mesh_domain_point_to_edge_impl(const Mesh &mesh,
mixer.finalize();
}
+/* An edge is selected if both of its vertices were selected. */
+template<>
+void adapt_mesh_domain_point_to_edge_impl(const Mesh &mesh,
+ const VArray<bool> &old_values,
+ MutableSpan<bool> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totedge);
+
+ for (const int edge_index : IndexRange(mesh.totedge)) {
+ const MEdge &edge = mesh.medge[edge_index];
+ r_values[edge_index] = old_values[edge.v1] && old_values[edge.v2];
+ }
+}
+
static GVArrayPtr adapt_mesh_domain_point_to_edge(const Mesh &mesh, GVArrayPtr varray)
{
GVArrayPtr new_varray;
@@ -490,6 +655,29 @@ void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh,
mixer.finalize();
}
+/* A corner is selected if its two adjacent edges were selected. */
+template<>
+void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh,
+ const VArray<bool> &old_values,
+ MutableSpan<bool> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totloop);
+
+ r_values.fill(false);
+
+ for (const int poly_index : IndexRange(mesh.totpoly)) {
+ const MPoly &poly = mesh.mpoly[poly_index];
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const int loop_index_prev = loop_index - 1 + (loop_index == poly.loopstart) * poly.totloop;
+ const MLoop &loop = mesh.mloop[loop_index];
+ const MLoop &loop_prev = mesh.mloop[loop_index_prev];
+ if (old_values[loop.e] && old_values[loop_prev.e]) {
+ r_values[loop_index] = true;
+ }
+ }
+ }
+}
+
static GVArrayPtr adapt_mesh_domain_edge_to_corner(const Mesh &mesh, GVArrayPtr varray)
{
GVArrayPtr new_varray;
@@ -522,6 +710,24 @@ static void adapt_mesh_domain_edge_to_point_impl(const Mesh &mesh,
mixer.finalize();
}
+/* A vertex is selected if any connected edge was selected. */
+template<>
+void adapt_mesh_domain_edge_to_point_impl(const Mesh &mesh,
+ const VArray<bool> &old_values,
+ MutableSpan<bool> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totvert);
+
+ r_values.fill(false);
+ for (const int edge_index : IndexRange(mesh.totedge)) {
+ const MEdge &edge = mesh.medge[edge_index];
+ if (old_values[edge_index]) {
+ r_values[edge.v1] = true;
+ r_values[edge.v2] = true;
+ }
+ }
+}
+
static GVArrayPtr adapt_mesh_domain_edge_to_point(const Mesh &mesh, GVArrayPtr varray)
{
GVArrayPtr new_varray;
@@ -560,6 +766,28 @@ static void adapt_mesh_domain_edge_to_face_impl(const Mesh &mesh,
mixer.finalize();
}
+/* A face is selected if all of its edges are selected. */
+template<>
+void adapt_mesh_domain_edge_to_face_impl(const Mesh &mesh,
+ const VArray<bool> &old_values,
+ MutableSpan<bool> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totpoly);
+
+ r_values.fill(true);
+ for (const int poly_index : IndexRange(mesh.totpoly)) {
+ const MPoly &poly = mesh.mpoly[poly_index];
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const MLoop &loop = mesh.mloop[loop_index];
+ const int edge_index = loop.e;
+ if (!old_values[edge_index]) {
+ r_values[poly_index] = false;
+ break;
+ }
+ }
+ }
+}
+
static GVArrayPtr adapt_mesh_domain_edge_to_face(const Mesh &mesh, GVArrayPtr varray)
{
GVArrayPtr new_varray;
@@ -698,7 +926,7 @@ static void tag_normals_dirty_when_writing_position(GeometryComponent &component
{
Mesh *mesh = get_mesh_from_component_for_write(component);
if (mesh != nullptr) {
- mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(mesh);
}
}
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
index b120c901499..6be03bffb3c 100644
--- a/source/blender/blenkernel/intern/gpencil_modifier.c
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -1025,6 +1025,9 @@ void BKE_gpencil_modifier_blend_read_data(BlendDataReader *reader, ListBase *lb)
else if (md->type == eGpencilModifierType_Dash) {
DashGpencilModifierData *gpmd = (DashGpencilModifierData *)md;
BLO_read_data_address(reader, &gpmd->segments);
+ for (int i = 0; i < gpmd->segments_len; i++) {
+ gpmd->segments[i].dmd = gpmd;
+ }
}
}
}
diff --git a/source/blender/blenkernel/intern/idtype.c b/source/blender/blenkernel/intern/idtype.c
index fee70922570..b2efccc53c4 100644
--- a/source/blender/blenkernel/intern/idtype.c
+++ b/source/blender/blenkernel/intern/idtype.c
@@ -224,10 +224,10 @@ bool BKE_idtype_idcode_is_valid(const short idcode)
}
/**
- * Return non-zero when an ID type is linkable.
+ * Check if an ID type is linkable.
*
- * \param idcode: The code to check.
- * \return Boolean, 0 when non linkable.
+ * \param idcode: The IDType code to check.
+ * \return Boolean, false when non linkable, true otherwise.
*/
bool BKE_idtype_idcode_is_linkable(const short idcode)
{
@@ -237,6 +237,24 @@ bool BKE_idtype_idcode_is_linkable(const short idcode)
}
/**
+ * Check if an ID type is only appendable.
+ *
+ * \param idcode: The IDType code to check.
+ * \return Boolean, false when also linkable, true when only appendable.
+ */
+bool BKE_idtype_idcode_is_only_appendable(const short idcode)
+{
+ const IDTypeInfo *id_type = BKE_idtype_get_info_from_idcode(idcode);
+ BLI_assert(id_type != NULL);
+ if (id_type != NULL && (id_type->flags & IDTYPE_FLAGS_ONLY_APPEND) != 0) {
+ /* Only appendable ID types should also always be linkable. */
+ BLI_assert((id_type->flags & IDTYPE_FLAGS_NO_LIBLINKING) == 0);
+ return true;
+ }
+ return false;
+}
+
+/**
* Convert an \a idcode into an \a idfilter (e.g. ID_OB -> FILTER_ID_OB).
*/
uint64_t BKE_idtype_idcode_to_idfilter(const short idcode)
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index aac081991e3..9b72a2d1a72 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -184,8 +184,7 @@ IDTypeInfo IDType_ID_IP = {
.name = "Ipo",
.name_plural = "ipos",
.translation_context = "",
- .flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING | IDTYPE_FLAGS_NO_MAKELOCAL |
- IDTYPE_FLAGS_NO_ANIMDATA,
+ .flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING | IDTYPE_FLAGS_NO_ANIMDATA,
.init_data = NULL,
.copy_data = NULL,
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index f79058dcf21..44fc86877a7 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -212,7 +212,7 @@ IDTypeInfo IDType_ID_KE = {
.name = "Key",
.name_plural = "shape_keys",
.translation_context = BLT_I18NCONTEXT_ID_SHAPEKEY,
- .flags = IDTYPE_FLAGS_NO_LIBLINKING | IDTYPE_FLAGS_NO_MAKELOCAL,
+ .flags = IDTYPE_FLAGS_NO_LIBLINKING,
.init_data = NULL,
.copy_data = shapekey_copy_data,
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index 4d7d675e364..60b6d7ad66d 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -98,7 +98,7 @@ IDTypeInfo IDType_ID_LINK_PLACEHOLDER = {
.name = "LinkPlaceholder",
.name_plural = "link_placeholders",
.translation_context = BLT_I18NCONTEXT_ID_ID,
- .flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING | IDTYPE_FLAGS_NO_MAKELOCAL,
+ .flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING,
.init_data = NULL,
.copy_data = NULL,
@@ -336,12 +336,34 @@ void id_fake_user_clear(ID *id)
}
}
-void BKE_id_clear_newpoin(ID *id)
+void BKE_id_newptr_and_tag_clear(ID *id)
{
- if (id->newid) {
- id->newid->tag &= ~LIB_TAG_NEW;
+ /* We assume that if this ID has no new ID, its embedded data has not either. */
+ if (id->newid == NULL) {
+ return;
}
+
+ id->newid->tag &= ~LIB_TAG_NEW;
id->newid = NULL;
+
+ /* Deal with embedded data too. */
+ /* NOTE: even though ShapeKeys are not technically embedded data currently, they behave as such
+ * in most cases, so for sake of consistency treat them as such here. Also mirrors the behavior
+ * in `BKE_lib_id_make_local`. */
+ Key *key = BKE_key_from_id(id);
+ if (key != NULL) {
+ BKE_id_newptr_and_tag_clear(&key->id);
+ }
+ bNodeTree *ntree = ntreeFromID(id);
+ if (ntree != NULL) {
+ BKE_id_newptr_and_tag_clear(&ntree->id);
+ }
+ if (GS(id->name) == ID_SCE) {
+ Collection *master_collection = ((Scene *)id)->master_collection;
+ if (master_collection != NULL) {
+ BKE_id_newptr_and_tag_clear(&master_collection->id);
+ }
+ }
}
static int lib_id_expand_local_cb(LibraryIDLinkCallbackData *cb_data)
@@ -480,10 +502,9 @@ void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags)
*
* \param flags: Special flag used when making a whole library's content local,
* it needs specific handling.
- *
- * \return true if the block can be made local.
+ * \return true is the ID has successfully been made local.
*/
-bool BKE_lib_id_make_local(Main *bmain, ID *id, const bool test, const int flags)
+bool BKE_lib_id_make_local(Main *bmain, ID *id, const int flags)
{
const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
@@ -495,23 +516,21 @@ bool BKE_lib_id_make_local(Main *bmain, ID *id, const bool test, const int flags
const IDTypeInfo *idtype_info = BKE_idtype_get_info_from_id(id);
- if (idtype_info != NULL) {
- if ((idtype_info->flags & IDTYPE_FLAGS_NO_MAKELOCAL) == 0) {
- if (!test) {
- if (idtype_info->make_local != NULL) {
- idtype_info->make_local(bmain, id, flags);
- }
- else {
- BKE_lib_id_make_local_generic(bmain, id, flags);
- }
- }
- return true;
- }
+ if (idtype_info == NULL) {
+ BLI_assert_msg(0, "IDType Missing IDTypeInfo");
return false;
}
- BLI_assert_msg(0, "IDType Missing IDTypeInfo");
- return false;
+ BLI_assert((idtype_info->flags & IDTYPE_FLAGS_NO_LIBLINKING) == 0);
+
+ if (idtype_info->make_local != NULL) {
+ idtype_info->make_local(bmain, id, flags);
+ }
+ else {
+ BKE_lib_id_make_local_generic(bmain, id, flags);
+ }
+
+ return true;
}
struct IDCopyLibManagementData {
@@ -1766,8 +1785,7 @@ void BKE_main_id_newptr_and_tag_clear(Main *bmain)
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
- id->newid = NULL;
- id->tag &= ~LIB_TAG_NEW;
+ BKE_id_newptr_and_tag_clear(id);
}
FOREACH_MAIN_ID_END;
}
@@ -2034,11 +2052,8 @@ void BKE_library_make_local(Main *bmain,
* Note that for objects, we don't want proxy pointers to be cleared yet. This will happen
* down the road in this function.
*/
- BKE_lib_id_make_local(bmain,
- id,
- false,
- LIB_ID_MAKELOCAL_FULL_LIBRARY |
- LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING);
+ BKE_lib_id_make_local(
+ bmain, id, LIB_ID_MAKELOCAL_FULL_LIBRARY | LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING);
if (id->newid) {
if (GS(id->newid->name) == ID_OB) {
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 07a3396ad5f..36958e36004 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -68,8 +68,7 @@ IDTypeInfo IDType_ID_LI = {
.name = "Library",
.name_plural = "libraries",
.translation_context = BLT_I18NCONTEXT_ID_LIBRARY,
- .flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING | IDTYPE_FLAGS_NO_MAKELOCAL |
- IDTYPE_FLAGS_NO_ANIMDATA,
+ .flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING | IDTYPE_FLAGS_NO_ANIMDATA,
.init_data = NULL,
.copy_data = NULL,
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 2efe0d77d87..d631993c4e8 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -1111,7 +1111,7 @@ void BKE_mesh_eval_delete(struct Mesh *mesh_eval)
MEM_freeN(mesh_eval);
}
-Mesh *BKE_mesh_copy_for_eval(struct Mesh *source, bool reference)
+Mesh *BKE_mesh_copy_for_eval(const Mesh *source, bool reference)
{
int flags = LIB_ID_COPY_LOCALIZE;
@@ -1859,7 +1859,7 @@ void BKE_mesh_vert_coords_apply(Mesh *mesh, const float (*vert_coords)[3])
for (int i = 0; i < mesh->totvert; i++, mv++) {
copy_v3_v3(mv->co, vert_coords[i]);
}
- mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(mesh);
}
void BKE_mesh_vert_coords_apply_with_mat4(Mesh *mesh,
@@ -1872,7 +1872,7 @@ void BKE_mesh_vert_coords_apply_with_mat4(Mesh *mesh,
for (int i = 0; i < mesh->totvert; i++, mv++) {
mul_v3_m4v3(mv->co, mat, vert_coords[i]);
}
- mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(mesh);
}
void BKE_mesh_vert_normals_apply(Mesh *mesh, const short (*vert_normals)[3])
diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.cc
index 9fd75be0d35..07dc6db05aa 100644
--- a/source/blender/blenkernel/intern/mesh_convert.c
+++ b/source/blender/blenkernel/intern/mesh_convert.cc
@@ -68,7 +68,7 @@
#ifdef VALIDATE_MESH
# define ASSERT_IS_VALID_MESH(mesh) \
- (BLI_assert((mesh == NULL) || (BKE_mesh_is_valid(mesh) == true)))
+ (BLI_assert((mesh == nullptr) || (BKE_mesh_is_valid(mesh) == true)))
#else
# define ASSERT_IS_VALID_MESH(mesh)
#endif
@@ -84,15 +84,16 @@ void BKE_mesh_from_metaball(ListBase *lb, Mesh *me)
const float *nors, *verts;
int a, *index;
- dl = lb->first;
- if (dl == NULL) {
+ dl = (DispList *)lb->first;
+ if (dl == nullptr) {
return;
}
if (dl->type == DL_INDEX4) {
- mvert = CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, dl->nr);
- allloop = mloop = CustomData_add_layer(&me->ldata, CD_MLOOP, CD_CALLOC, NULL, dl->parts * 4);
- mpoly = CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CALLOC, NULL, dl->parts);
+ mvert = (MVert *)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, nullptr, dl->nr);
+ allloop = mloop = (MLoop *)CustomData_add_layer(
+ &me->ldata, CD_MLOOP, CD_CALLOC, nullptr, dl->parts * 4);
+ mpoly = (MPoly *)CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CALLOC, nullptr, dl->parts);
me->mvert = mvert;
me->mloop = mloop;
me->mpoly = mpoly;
@@ -177,9 +178,10 @@ static void make_edges_mdata_extend(
MEdge *medge;
uint e_index = totedge;
- *r_alledge = medge = (*r_alledge ?
- MEM_reallocN(*r_alledge, sizeof(MEdge) * (totedge + totedge_new)) :
- MEM_calloc_arrayN(totedge_new, sizeof(MEdge), __func__));
+ *r_alledge = medge = (MEdge *)(*r_alledge ?
+ MEM_reallocN(*r_alledge,
+ sizeof(MEdge) * (totedge + totedge_new)) :
+ MEM_calloc_arrayN(totedge_new, sizeof(MEdge), __func__));
medge += totedge;
totedge += totedge_new;
@@ -209,7 +211,7 @@ static void make_edges_mdata_extend(
}
}
- BLI_edgehash_free(eh, NULL);
+ BLI_edgehash_free(eh, nullptr);
}
/* Initialize mverts, medges and, faces for converting nurbs to mesh and derived mesh */
@@ -229,7 +231,7 @@ static int mesh_nurbs_displist_to_mdata(const Curve *cu,
MVert *mvert;
MPoly *mpoly;
MLoop *mloop;
- MLoopUV *mloopuv = NULL;
+ MLoopUV *mloopuv = nullptr;
MEdge *medge;
const float *data;
int a, b, ofs, vertcount, startvert, totvert = 0, totedge = 0, totloop = 0, totpoly = 0;
@@ -277,14 +279,15 @@ static int mesh_nurbs_displist_to_mdata(const Curve *cu,
return -1;
}
- *r_allvert = mvert = MEM_calloc_arrayN(totvert, sizeof(MVert), "nurbs_init mvert");
- *r_alledge = medge = MEM_calloc_arrayN(totedge, sizeof(MEdge), "nurbs_init medge");
- *r_allloop = mloop = MEM_calloc_arrayN(
+ *r_allvert = mvert = (MVert *)MEM_calloc_arrayN(totvert, sizeof(MVert), "nurbs_init mvert");
+ *r_alledge = medge = (MEdge *)MEM_calloc_arrayN(totedge, sizeof(MEdge), "nurbs_init medge");
+ *r_allloop = mloop = (MLoop *)MEM_calloc_arrayN(
totpoly, sizeof(MLoop[4]), "nurbs_init mloop"); /* totloop */
- *r_allpoly = mpoly = MEM_calloc_arrayN(totpoly, sizeof(MPoly), "nurbs_init mloop");
+ *r_allpoly = mpoly = (MPoly *)MEM_calloc_arrayN(totpoly, sizeof(MPoly), "nurbs_init mloop");
if (r_alluv) {
- *r_alluv = mloopuv = MEM_calloc_arrayN(totpoly, sizeof(MLoopUV[4]), "nurbs_init mloopuv");
+ *r_alluv = mloopuv = (MLoopUV *)MEM_calloc_arrayN(
+ totpoly, sizeof(MLoopUV[4]), "nurbs_init mloopuv");
}
/* verts and faces */
@@ -500,13 +503,13 @@ static void mesh_copy_texture_space_from_curve_type(const Curve *cu, Mesh *me)
Mesh *BKE_mesh_new_nomain_from_curve_displist(const Object *ob, const ListBase *dispbase)
{
- const Curve *cu = ob->data;
+ const Curve *cu = (const Curve *)ob->data;
Mesh *mesh;
MVert *allvert;
MEdge *alledge;
MLoop *allloop;
MPoly *allpoly;
- MLoopUV *alluv = NULL;
+ MLoopUV *alluv = nullptr;
int totvert, totedge, totloop, totpoly;
if (mesh_nurbs_displist_to_mdata(cu,
@@ -525,7 +528,7 @@ Mesh *BKE_mesh_new_nomain_from_curve_displist(const Object *ob, const ListBase *
}
mesh = BKE_mesh_new_nomain(totvert, totedge, 0, totloop, totpoly);
- mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(mesh);
if (totvert != 0) {
memcpy(mesh->mvert, allvert, totvert * sizeof(MVert));
@@ -561,7 +564,7 @@ Mesh *BKE_mesh_new_nomain_from_curve_displist(const Object *ob, const ListBase *
Mesh *BKE_mesh_new_nomain_from_curve(const Object *ob)
{
- ListBase disp = {NULL, NULL};
+ ListBase disp = {nullptr, nullptr};
if (ob->runtime.curve_cache) {
disp = ob->runtime.curve_cache->disp;
@@ -578,16 +581,16 @@ static void mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const char
Mesh *me_eval = (Mesh *)ob->runtime.data_eval;
Mesh *me;
- MVert *allvert = NULL;
- MEdge *alledge = NULL;
- MLoop *allloop = NULL;
- MLoopUV *alluv = NULL;
- MPoly *allpoly = NULL;
+ MVert *allvert = nullptr;
+ MEdge *alledge = nullptr;
+ MLoop *allloop = nullptr;
+ MLoopUV *alluv = nullptr;
+ MPoly *allpoly = nullptr;
int totvert, totedge, totloop, totpoly;
- Curve *cu = ob->data;
+ Curve *cu = (Curve *)ob->data;
- if (me_eval == NULL) {
+ if (me_eval == nullptr) {
if (mesh_nurbs_displist_to_mdata(cu,
dispbase,
&allvert,
@@ -604,30 +607,34 @@ static void mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const char
}
/* make mesh */
- me = BKE_id_new_nomain(ID_ME, obdata_name);
+ me = (Mesh *)BKE_id_new_nomain(ID_ME, obdata_name);
me->totvert = totvert;
me->totedge = totedge;
me->totloop = totloop;
me->totpoly = totpoly;
- me->mvert = CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, allvert, me->totvert);
- me->medge = CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, alledge, me->totedge);
- me->mloop = CustomData_add_layer(&me->ldata, CD_MLOOP, CD_ASSIGN, allloop, me->totloop);
- me->mpoly = CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, allpoly, me->totpoly);
+ me->mvert = (MVert *)CustomData_add_layer(
+ &me->vdata, CD_MVERT, CD_ASSIGN, allvert, me->totvert);
+ me->medge = (MEdge *)CustomData_add_layer(
+ &me->edata, CD_MEDGE, CD_ASSIGN, alledge, me->totedge);
+ me->mloop = (MLoop *)CustomData_add_layer(
+ &me->ldata, CD_MLOOP, CD_ASSIGN, allloop, me->totloop);
+ me->mpoly = (MPoly *)CustomData_add_layer(
+ &me->pdata, CD_MPOLY, CD_ASSIGN, allpoly, me->totpoly);
if (alluv) {
const char *uvname = "UVMap";
- me->mloopuv = CustomData_add_layer_named(
+ me->mloopuv = (MLoopUV *)CustomData_add_layer_named(
&me->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, me->totloop, uvname);
}
BKE_mesh_calc_normals(me);
}
else {
- me = BKE_id_new_nomain(ID_ME, obdata_name);
+ me = (Mesh *)BKE_id_new_nomain(ID_ME, obdata_name);
- ob->runtime.data_eval = NULL;
+ ob->runtime.data_eval = nullptr;
BKE_mesh_nomain_to_mesh(me_eval, me, ob, &CD_MASK_MESH, true);
}
@@ -636,7 +643,7 @@ static void mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const char
mesh_copy_texture_space_from_curve_type(cu, me);
- cu->mat = NULL;
+ cu->mat = nullptr;
cu->totcol = 0;
/* Do not decrement ob->data usercount here,
@@ -647,29 +654,29 @@ static void mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const char
/* For temporary objects in BKE_mesh_new_from_object don't remap
* the entire scene with associated depsgraph updates, which are
* problematic for renderers exporting data. */
- BKE_id_free(NULL, cu);
+ BKE_id_free(nullptr, cu);
}
-typedef struct EdgeLink {
+struct EdgeLink {
struct EdgeLink *next, *prev;
void *edge;
-} EdgeLink;
+};
-typedef struct VertLink {
+struct VertLink {
Link *next, *prev;
uint index;
-} VertLink;
+};
static void prependPolyLineVert(ListBase *lb, uint index)
{
- VertLink *vl = MEM_callocN(sizeof(VertLink), "VertLink");
+ VertLink *vl = (VertLink *)MEM_callocN(sizeof(VertLink), "VertLink");
vl->index = index;
BLI_addhead(lb, vl);
}
static void appendPolyLineVert(ListBase *lb, uint index)
{
- VertLink *vl = MEM_callocN(sizeof(VertLink), "VertLink");
+ VertLink *vl = (VertLink *)MEM_callocN(sizeof(VertLink), "VertLink");
vl->index = index;
BLI_addtail(lb, vl);
}
@@ -689,10 +696,10 @@ void BKE_mesh_to_curve_nurblist(const Mesh *me, ListBase *nurblist, const int ed
/* only to detect edge polylines */
int *edge_users;
- ListBase edges = {NULL, NULL};
+ ListBase edges = {nullptr, nullptr};
/* get boundary edges */
- edge_users = MEM_calloc_arrayN(medge_len, sizeof(int), __func__);
+ edge_users = (int *)MEM_calloc_arrayN(medge_len, sizeof(int), __func__);
for (i = 0, mp = mpoly; i < mpoly_len; i++, mp++) {
MLoop *ml = &mloop[mp->loopstart];
int j;
@@ -705,7 +712,7 @@ void BKE_mesh_to_curve_nurblist(const Mesh *me, ListBase *nurblist, const int ed
med = medge;
for (i = 0; i < medge_len; i++, med++) {
if (edge_users[i] == edge_users_test) {
- EdgeLink *edl = MEM_callocN(sizeof(EdgeLink), "EdgeLink");
+ EdgeLink *edl = (EdgeLink *)MEM_callocN(sizeof(EdgeLink), "EdgeLink");
edl->edge = med;
BLI_addtail(&edges, edl);
@@ -718,10 +725,10 @@ void BKE_mesh_to_curve_nurblist(const Mesh *me, ListBase *nurblist, const int ed
while (edges.first) {
/* each iteration find a polyline and add this as a nurbs poly spline */
- ListBase polyline = {NULL, NULL}; /* store a list of VertLink's */
+ ListBase polyline = {nullptr, nullptr}; /* store a list of VertLink's */
bool closed = false;
int totpoly = 0;
- MEdge *med_current = ((EdgeLink *)edges.last)->edge;
+ MEdge *med_current = (MEdge *)((EdgeLink *)edges.last)->edge;
uint startVert = med_current->v1;
uint endVert = med_current->v2;
bool ok = true;
@@ -734,12 +741,12 @@ void BKE_mesh_to_curve_nurblist(const Mesh *me, ListBase *nurblist, const int ed
totedges--;
while (ok) { /* while connected edges are found... */
- EdgeLink *edl = edges.last;
+ EdgeLink *edl = (EdgeLink *)edges.last;
ok = false;
while (edl) {
EdgeLink *edl_prev = edl->prev;
- med = edl->edge;
+ med = (MEdge *)edl->edge;
if (med->v1 == endVert) {
endVert = med->v2;
@@ -803,7 +810,7 @@ void BKE_mesh_to_curve_nurblist(const Mesh *me, ListBase *nurblist, const int ed
nu->bp = (BPoint *)MEM_calloc_arrayN(totpoly, sizeof(BPoint), "bpoints");
/* add points */
- vl = polyline.first;
+ vl = (VertLink *)polyline.first;
for (i = 0, bp = nu->bp; i < totpoly; i++, bp++, vl = (VertLink *)vl->next) {
copy_v3_v3(bp->vec, mvert[vl->index].co);
bp->f1 = SELECT;
@@ -825,7 +832,7 @@ void BKE_mesh_to_curve(Main *bmain, Depsgraph *depsgraph, Scene *UNUSED(scene),
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &CD_MASK_MESH);
- ListBase nurblist = {NULL, NULL};
+ ListBase nurblist = {nullptr, nullptr};
BKE_mesh_to_curve_nurblist(me_eval, &nurblist, 0);
BKE_mesh_to_curve_nurblist(me_eval, &nurblist, 1);
@@ -846,16 +853,13 @@ void BKE_mesh_to_curve(Main *bmain, Depsgraph *depsgraph, Scene *UNUSED(scene),
void BKE_pointcloud_from_mesh(Mesh *me, PointCloud *pointcloud)
{
- BLI_assert(me != NULL);
+ BLI_assert(me != nullptr);
pointcloud->totpoint = me->totvert;
CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint);
/* Copy over all attributes. */
- const CustomData_MeshMasks mask = {
- .vmask = CD_MASK_PROP_ALL,
- };
- CustomData_merge(&me->vdata, &pointcloud->pdata, mask.vmask, CD_DUPLICATE, me->totvert);
+ CustomData_merge(&me->vdata, &pointcloud->pdata, CD_MASK_PROP_ALL, CD_DUPLICATE, me->totvert);
BKE_pointcloud_update_customdata_pointers(pointcloud);
CustomData_update_typemap(&pointcloud->pdata);
@@ -874,7 +878,7 @@ void BKE_mesh_to_pointcloud(Main *bmain, Depsgraph *depsgraph, Scene *UNUSED(sce
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &CD_MASK_MESH);
- PointCloud *pointcloud = BKE_pointcloud_add(bmain, ob->id.name + 2);
+ PointCloud *pointcloud = (PointCloud *)BKE_pointcloud_add(bmain, ob->id.name + 2);
BKE_pointcloud_from_mesh(me_eval, pointcloud);
@@ -889,24 +893,22 @@ void BKE_mesh_to_pointcloud(Main *bmain, Depsgraph *depsgraph, Scene *UNUSED(sce
void BKE_mesh_from_pointcloud(const PointCloud *pointcloud, Mesh *me)
{
- BLI_assert(pointcloud != NULL);
+ BLI_assert(pointcloud != nullptr);
me->totvert = pointcloud->totpoint;
/* Merge over all attributes. */
- const CustomData_MeshMasks mask = {
- .vmask = CD_MASK_PROP_ALL,
- };
- CustomData_merge(&pointcloud->pdata, &me->vdata, mask.vmask, CD_DUPLICATE, pointcloud->totpoint);
+ CustomData_merge(
+ &pointcloud->pdata, &me->vdata, CD_MASK_PROP_ALL, CD_DUPLICATE, pointcloud->totpoint);
/* Convert the Position attribute to a mesh vertex. */
- me->mvert = CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert);
+ me->mvert = (MVert *)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, nullptr, me->totvert);
CustomData_update_typemap(&me->vdata);
const int layer_idx = CustomData_get_named_layer_index(
&me->vdata, CD_PROP_FLOAT3, POINTCLOUD_ATTR_POSITION);
CustomDataLayer *pos_layer = &me->vdata.layers[layer_idx];
- float(*positions)[3] = pos_layer->data;
+ float(*positions)[3] = (float(*)[3])pos_layer->data;
MVert *mvert;
mvert = me->mvert;
@@ -956,7 +958,8 @@ static Object *object_for_curve_to_mesh_create(Object *object)
Curve *curve = (Curve *)object->data;
/* Create object itself. */
- Object *temp_object = (Object *)BKE_id_copy_ex(NULL, &object->id, NULL, LIB_ID_COPY_LOCALIZE);
+ Object *temp_object = (Object *)BKE_id_copy_ex(
+ nullptr, &object->id, nullptr, LIB_ID_COPY_LOCALIZE);
/* Remove all modifiers, since we don't want them to be applied. */
BKE_object_free_modifiers(temp_object, LIB_ID_CREATE_NO_USER_REFCOUNT);
@@ -965,26 +968,27 @@ static Object *object_for_curve_to_mesh_create(Object *object)
*
* Note that there are extra fields in there like bevel and path, but those are not needed during
* conversion, so they are not copied to save unnecessary allocations. */
- if (temp_object->runtime.curve_cache == NULL) {
- temp_object->runtime.curve_cache = MEM_callocN(sizeof(CurveCache),
- "CurveCache for curve types");
+ if (temp_object->runtime.curve_cache == nullptr) {
+ temp_object->runtime.curve_cache = (CurveCache *)MEM_callocN(sizeof(CurveCache),
+ "CurveCache for curve types");
}
- if (object->runtime.curve_cache != NULL) {
+ if (object->runtime.curve_cache != nullptr) {
BKE_displist_copy(&temp_object->runtime.curve_cache->disp, &object->runtime.curve_cache->disp);
}
/* Constructive modifiers will use mesh to store result. */
- if (object->runtime.data_eval != NULL) {
+ if (object->runtime.data_eval != nullptr) {
BKE_id_copy_ex(
- NULL, object->runtime.data_eval, &temp_object->runtime.data_eval, LIB_ID_COPY_LOCALIZE);
+ nullptr, object->runtime.data_eval, &temp_object->runtime.data_eval, LIB_ID_COPY_LOCALIZE);
}
/* Need to create copy of curve itself as well, it will be freed by underlying conversion
* functions.
*
* NOTE: Copies the data, but not the shapekeys. */
- BKE_id_copy_ex(NULL, object->data, (ID **)&temp_object->data, LIB_ID_COPY_LOCALIZE);
+ BKE_id_copy_ex(
+ nullptr, (const ID *)object->data, (ID **)&temp_object->data, LIB_ID_COPY_LOCALIZE);
Curve *temp_curve = (Curve *)temp_object->data;
/* Make sure texture space is calculated for a copy of curve, it will be used for the final
@@ -1011,8 +1015,9 @@ static void curve_to_mesh_eval_ensure(Object *object)
remapped_object.data = &remapped_curve;
- if (object->runtime.curve_cache == NULL) {
- object->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve");
+ if (object->runtime.curve_cache == nullptr) {
+ object->runtime.curve_cache = (CurveCache *)MEM_callocN(sizeof(CurveCache),
+ "CurveCache for Curve");
}
/* Temporarily share the curve-cache with the temporary object, owned by `object`. */
@@ -1025,8 +1030,8 @@ static void curve_to_mesh_eval_ensure(Object *object)
*
* So we create temporary copy of the object which will use same data as the original bevel, but
* will have no modifiers. */
- Object bevel_object = {{NULL}};
- if (remapped_curve.bevobj != NULL) {
+ Object bevel_object = {{nullptr}};
+ if (remapped_curve.bevobj != nullptr) {
bevel_object = *remapped_curve.bevobj;
BLI_listbase_clear(&bevel_object.modifiers);
BKE_object_runtime_reset(&bevel_object);
@@ -1034,34 +1039,34 @@ static void curve_to_mesh_eval_ensure(Object *object)
}
/* Same thing for taper. */
- Object taper_object = {{NULL}};
- if (remapped_curve.taperobj != NULL) {
+ Object taper_object = {{nullptr}};
+ if (remapped_curve.taperobj != nullptr) {
taper_object = *remapped_curve.taperobj;
BLI_listbase_clear(&taper_object.modifiers);
BKE_object_runtime_reset(&taper_object);
remapped_curve.taperobj = &taper_object;
}
- /* NOTE: We don't have dependency graph or scene here, so we pass NULL. This is all fine since
+ /* NOTE: We don't have dependency graph or scene here, so we pass nullptr. This is all fine since
* they are only used for modifier stack, which we have explicitly disabled for all objects.
*
* TODO(sergey): This is a very fragile logic, but proper solution requires re-writing quite a
* bit of internal functions (#mesh_from_nurbs_displist, BKE_mesh_nomain_to_mesh) and also
* Mesh From Curve operator.
* Brecht says hold off with that. */
- Mesh *mesh_eval = NULL;
+ Mesh *mesh_eval = nullptr;
BKE_displist_make_curveTypes_forRender(
- NULL, NULL, &remapped_object, &remapped_object.runtime.curve_cache->disp, &mesh_eval);
+ nullptr, nullptr, &remapped_object, &remapped_object.runtime.curve_cache->disp, &mesh_eval);
/* NOTE: this is to be consistent with `BKE_displist_make_curveTypes()`, however that is not a
* real issue currently, code here is broken in more than one way, fix(es) will be done
* separately. */
- if (mesh_eval != NULL) {
+ if (mesh_eval != nullptr) {
BKE_object_eval_assign_data(&remapped_object, &mesh_eval->id, true);
}
/* Owned by `object` & needed by the caller to create the mesh. */
- remapped_object.runtime.curve_cache = NULL;
+ remapped_object.runtime.curve_cache = nullptr;
BKE_object_runtime_free_data(&remapped_object);
BKE_object_runtime_free_data(&taper_object);
@@ -1070,7 +1075,7 @@ static void curve_to_mesh_eval_ensure(Object *object)
static Mesh *mesh_new_from_curve_type_object(Object *object)
{
- Curve *curve = object->data;
+ Curve *curve = (Curve *)object->data;
Object *temp_object = object_for_curve_to_mesh_create(object);
Curve *temp_curve = (Curve *)temp_object->data;
@@ -1081,8 +1086,8 @@ static Mesh *mesh_new_from_curve_type_object(Object *object)
}
/* Reset pointers before conversion. */
- temp_curve->editfont = NULL;
- temp_curve->editnurb = NULL;
+ temp_curve->editfont = nullptr;
+ temp_curve->editnurb = nullptr;
/* Convert to mesh. */
mesh_from_nurbs_displist(
@@ -1091,14 +1096,14 @@ static Mesh *mesh_new_from_curve_type_object(Object *object)
/* #mesh_from_nurbs_displist changes the type to a mesh, check it worked. If it didn't
* the curve did not have any segments or otherwise would have generated an empty mesh. */
if (temp_object->type != OB_MESH) {
- BKE_id_free(NULL, temp_object->data);
- BKE_id_free(NULL, temp_object);
- return NULL;
+ BKE_id_free(nullptr, temp_object->data);
+ BKE_id_free(nullptr, temp_object);
+ return nullptr;
}
- Mesh *mesh_result = temp_object->data;
+ Mesh *mesh_result = (Mesh *)temp_object->data;
- BKE_id_free(NULL, temp_object);
+ BKE_id_free(nullptr, temp_object);
/* NOTE: Materials are copied in #mesh_from_nurbs_displist(). */
@@ -1114,19 +1119,19 @@ static Mesh *mesh_new_from_mball_object(Object *object)
* ball).
*
* We create empty mesh so scripters don't run into None objects. */
- if (!DEG_is_evaluated_object(object) || object->runtime.curve_cache == NULL ||
+ if (!DEG_is_evaluated_object(object) || object->runtime.curve_cache == nullptr ||
BLI_listbase_is_empty(&object->runtime.curve_cache->disp)) {
- return BKE_id_new_nomain(ID_ME, ((ID *)object->data)->name + 2);
+ return (Mesh *)BKE_id_new_nomain(ID_ME, ((ID *)object->data)->name + 2);
}
- Mesh *mesh_result = BKE_id_new_nomain(ID_ME, ((ID *)object->data)->name + 2);
+ Mesh *mesh_result = (Mesh *)BKE_id_new_nomain(ID_ME, ((ID *)object->data)->name + 2);
BKE_mesh_from_metaball(&object->runtime.curve_cache->disp, mesh_result);
BKE_mesh_texspace_copy_from_object(mesh_result, object);
/* Copy materials. */
mesh_result->totcol = mball->totcol;
- mesh_result->mat = MEM_dupallocN(mball->mat);
- if (mball->mat != NULL) {
+ mesh_result->mat = (Material **)MEM_dupallocN(mball->mat);
+ if (mball->mat != nullptr) {
for (int i = mball->totcol; i-- > 0;) {
mesh_result->mat[i] = BKE_object_material_get(object, i + 1);
}
@@ -1142,7 +1147,7 @@ static Mesh *mesh_new_from_mesh(Object *object, Mesh *mesh)
BKE_mesh_wrapper_ensure_mdata(mesh);
Mesh *mesh_result = (Mesh *)BKE_id_copy_ex(
- NULL, &mesh->id, NULL, LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT);
+ nullptr, &mesh->id, nullptr, LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT);
/* NOTE: Materials should already be copied. */
/* Copy original mesh name. This is because edit meshes might not have one properly set name. */
BLI_strncpy(mesh_result->id.name, ((ID *)object->data)->name, sizeof(mesh_result->id.name));
@@ -1157,12 +1162,12 @@ static Mesh *mesh_new_from_mesh_object_with_layers(Depsgraph *depsgraph,
return mesh_new_from_mesh(object, (Mesh *)object->data);
}
- if (depsgraph == NULL) {
- return NULL;
+ if (depsgraph == nullptr) {
+ return nullptr;
}
Object object_for_eval = *object;
- if (object_for_eval.runtime.data_orig != NULL) {
+ if (object_for_eval.runtime.data_orig != nullptr) {
object_for_eval.data = object_for_eval.runtime.data_orig;
}
@@ -1186,10 +1191,10 @@ static Mesh *mesh_new_from_mesh_object(Depsgraph *depsgraph,
if (preserve_all_data_layers || preserve_origindex) {
return mesh_new_from_mesh_object_with_layers(depsgraph, object, preserve_origindex);
}
- Mesh *mesh_input = object->data;
+ Mesh *mesh_input = (Mesh *)object->data;
/* If we are in edit mode, use evaluated mesh from edit structure, matching to what
* viewport is using for visualization. */
- if (mesh_input->edit_mesh != NULL && mesh_input->edit_mesh->mesh_eval_final) {
+ if (mesh_input->edit_mesh != nullptr && mesh_input->edit_mesh->mesh_eval_final) {
mesh_input = mesh_input->edit_mesh->mesh_eval_final;
}
return mesh_new_from_mesh(object, mesh_input);
@@ -1200,7 +1205,7 @@ Mesh *BKE_mesh_new_from_object(Depsgraph *depsgraph,
const bool preserve_all_data_layers,
const bool preserve_origindex)
{
- Mesh *new_mesh = NULL;
+ Mesh *new_mesh = nullptr;
switch (object->type) {
case OB_FONT:
case OB_CURVE:
@@ -1216,11 +1221,11 @@ Mesh *BKE_mesh_new_from_object(Depsgraph *depsgraph,
break;
default:
/* Object does not have geometry data. */
- return NULL;
+ return nullptr;
}
- if (new_mesh == NULL) {
+ if (new_mesh == nullptr) {
/* Happens in special cases like request of mesh for non-mother meta ball. */
- return NULL;
+ return nullptr;
}
/* The result must have 0 users, since it's just a mesh which is free-dangling data-block.
@@ -1233,9 +1238,9 @@ Mesh *BKE_mesh_new_from_object(Depsgraph *depsgraph,
* ownership.
*
* Here we are constructing a mesh which is supposed to be independent, which means no shared
- * ownership is allowed, so we make sure edit mesh is reset to NULL (which is similar to as if
+ * ownership is allowed, so we make sure edit mesh is reset to nullptr (which is similar to as if
* one duplicates the objects and applies all the modifiers). */
- new_mesh->edit_mesh = NULL;
+ new_mesh->edit_mesh = nullptr;
return new_mesh;
}
@@ -1243,7 +1248,7 @@ Mesh *BKE_mesh_new_from_object(Depsgraph *depsgraph,
static int foreach_libblock_make_original_callback(LibraryIDLinkCallbackData *cb_data)
{
ID **id_p = cb_data->id_pointer;
- if (*id_p == NULL) {
+ if (*id_p == nullptr) {
return IDWALK_RET_NOP;
}
*id_p = DEG_get_original_id(*id_p);
@@ -1254,7 +1259,7 @@ static int foreach_libblock_make_original_callback(LibraryIDLinkCallbackData *cb
static int foreach_libblock_make_usercounts_callback(LibraryIDLinkCallbackData *cb_data)
{
ID **id_p = cb_data->id_pointer;
- if (*id_p == NULL) {
+ if (*id_p == nullptr) {
return IDWALK_RET_NOP;
}
@@ -1278,7 +1283,7 @@ Mesh *BKE_mesh_new_from_object_to_bmain(Main *bmain,
BLI_assert(ELEM(object->type, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL, OB_MESH));
Mesh *mesh = BKE_mesh_new_from_object(depsgraph, object, preserve_all_data_layers, false);
- if (mesh == NULL) {
+ if (mesh == nullptr) {
/* Unable to convert the object to a mesh, return an empty one. */
Mesh *mesh_in_bmain = BKE_mesh_add(bmain, ((ID *)object->data)->name + 2);
id_us_min(&mesh_in_bmain->id);
@@ -1294,7 +1299,7 @@ Mesh *BKE_mesh_new_from_object_to_bmain(Main *bmain,
* Note that user-count updates has to be done *after* mesh has been transferred to Main database
* (since doing refcounting on non-Main IDs is forbidden). */
BKE_library_foreach_ID_link(
- NULL, &mesh->id, foreach_libblock_make_original_callback, NULL, IDWALK_NOP);
+ nullptr, &mesh->id, foreach_libblock_make_original_callback, nullptr, IDWALK_NOP);
/* Append the mesh to 'bmain'.
* We do it a bit longer way since there is no simple and clear way of adding existing data-block
@@ -1311,14 +1316,14 @@ Mesh *BKE_mesh_new_from_object_to_bmain(Main *bmain,
mesh_in_bmain->totcol = mesh->totcol;
mesh_in_bmain->flag = mesh->flag;
mesh_in_bmain->smoothresh = mesh->smoothresh;
- mesh->mat = NULL;
+ mesh->mat = nullptr;
- BKE_mesh_nomain_to_mesh(mesh, mesh_in_bmain, NULL, &CD_MASK_MESH, true);
+ BKE_mesh_nomain_to_mesh(mesh, mesh_in_bmain, nullptr, &CD_MASK_MESH, true);
/* User-count is required because so far mesh was in a limbo, where library management does
* not perform any user management (i.e. copy of a mesh will not increase users of materials). */
BKE_library_foreach_ID_link(
- NULL, &mesh_in_bmain->id, foreach_libblock_make_usercounts_callback, NULL, IDWALK_NOP);
+ nullptr, &mesh_in_bmain->id, foreach_libblock_make_usercounts_callback, nullptr, IDWALK_NOP);
/* Make sure user count from BKE_mesh_add() is the one we expect here and bring it down to 0. */
BLI_assert(mesh_in_bmain->id.us == 1);
@@ -1347,7 +1352,7 @@ static void add_shapekey_layers(Mesh *mesh_dest, Mesh *mesh_src)
return;
}
- for (i = 0, kb = key->block.first; kb; kb = kb->next, i++) {
+ for (i = 0, kb = (KeyBlock *)key->block.first; kb; kb = kb->next, i++) {
int ci;
float *array;
@@ -1358,10 +1363,10 @@ static void add_shapekey_layers(Mesh *mesh_dest, Mesh *mesh_src)
mesh_src->totvert,
kb->name,
kb->totelem);
- array = MEM_calloc_arrayN((size_t)mesh_src->totvert, sizeof(float[3]), __func__);
+ array = (float *)MEM_calloc_arrayN((size_t)mesh_src->totvert, sizeof(float[3]), __func__);
}
else {
- array = MEM_malloc_arrayN((size_t)mesh_src->totvert, sizeof(float[3]), __func__);
+ array = (float *)MEM_malloc_arrayN((size_t)mesh_src->totvert, sizeof(float[3]), __func__);
memcpy(array, kb->data, sizeof(float[3]) * (size_t)mesh_src->totvert);
}
@@ -1379,9 +1384,10 @@ Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph,
ModifierData *md_eval,
const bool build_shapekey_layers)
{
- Mesh *me = ob_eval->runtime.data_orig ? ob_eval->runtime.data_orig : ob_eval->data;
- const ModifierTypeInfo *mti = BKE_modifier_get_info(md_eval->type);
- Mesh *result = NULL;
+ Mesh *me = ob_eval->runtime.data_orig ? (Mesh *)ob_eval->runtime.data_orig :
+ (Mesh *)ob_eval->data;
+ const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md_eval->type);
+ Mesh *result = nullptr;
KeyBlock *kb;
ModifierEvalContext mectx = {depsgraph, ob_eval, MOD_APPLY_TO_BASE_MESH};
@@ -1389,12 +1395,12 @@ Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph,
return result;
}
- if (mti->isDisabled && mti->isDisabled(scene, md_eval, 0)) {
+ if (mti->isDisabled && mti->isDisabled(scene, md_eval, false)) {
return result;
}
if (build_shapekey_layers && me->key &&
- (kb = BLI_findlink(&me->key->block, ob_eval->shapenr - 1))) {
+ (kb = (KeyBlock *)BLI_findlink(&me->key->block, ob_eval->shapenr - 1))) {
BKE_keyblock_convert_to_mesh(kb, me);
}
@@ -1402,7 +1408,7 @@ Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph,
int numVerts;
float(*deformedVerts)[3] = BKE_mesh_vert_coords_alloc(me, &numVerts);
- result = (Mesh *)BKE_id_copy_ex(NULL, &me->id, NULL, LIB_ID_COPY_LOCALIZE);
+ result = (Mesh *)BKE_id_copy_ex(nullptr, &me->id, nullptr, LIB_ID_COPY_LOCALIZE);
mti->deformVerts(md_eval, &mectx, result, deformedVerts, numVerts);
BKE_mesh_vert_coords_apply(result, deformedVerts);
@@ -1413,7 +1419,7 @@ Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph,
MEM_freeN(deformedVerts);
}
else {
- Mesh *mesh_temp = (Mesh *)BKE_id_copy_ex(NULL, &me->id, NULL, LIB_ID_COPY_LOCALIZE);
+ Mesh *mesh_temp = (Mesh *)BKE_id_copy_ex(nullptr, &me->id, nullptr, LIB_ID_COPY_LOCALIZE);
if (build_shapekey_layers) {
add_shapekey_layers(mesh_temp, me);
@@ -1423,7 +1429,7 @@ Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph,
ASSERT_IS_VALID_MESH(result);
if (mesh_temp != result) {
- BKE_id_free(NULL, mesh_temp);
+ BKE_id_free(nullptr, mesh_temp);
}
}
@@ -1446,7 +1452,7 @@ static void shapekey_layers_to_keyblocks(Mesh *mesh_src, Mesh *mesh_dst, int act
&mesh_src->vdata.layers[CustomData_get_layer_index_n(&mesh_src->vdata, CD_SHAPEKEY, i)];
float(*cos)[3], (*kbcos)[3];
- for (kb = mesh_dst->key->block.first; kb; kb = kb->next) {
+ for (kb = (KeyBlock *)mesh_dst->key->block.first; kb; kb = kb->next) {
if (kb->uid == layer->uid) {
break;
}
@@ -1461,10 +1467,10 @@ static void shapekey_layers_to_keyblocks(Mesh *mesh_src, Mesh *mesh_dst, int act
MEM_freeN(kb->data);
}
- cos = CustomData_get_layer_n(&mesh_src->vdata, CD_SHAPEKEY, i);
+ cos = (float(*)[3])CustomData_get_layer_n(&mesh_src->vdata, CD_SHAPEKEY, i);
kb->totelem = mesh_src->totvert;
- kb->data = kbcos = MEM_malloc_arrayN(kb->totelem, sizeof(float[3]), __func__);
+ kb->data = kbcos = (float(*)[3])MEM_malloc_arrayN(kb->totelem, sizeof(float[3]), __func__);
if (kb->uid == actshape_uid) {
MVert *mvert = mesh_src->mvert;
@@ -1479,7 +1485,7 @@ static void shapekey_layers_to_keyblocks(Mesh *mesh_src, Mesh *mesh_dst, int act
}
}
- for (kb = mesh_dst->key->block.first; kb; kb = kb->next) {
+ for (kb = (KeyBlock *)mesh_dst->key->block.first; kb; kb = kb->next) {
if (kb->totelem != mesh_src->totvert) {
if (kb->data) {
MEM_freeN(kb->data);
@@ -1544,7 +1550,7 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
int uid;
if (ob) {
- kb = BLI_findlink(&mesh_dst->key->block, ob->shapenr - 1);
+ kb = (KeyBlock *)BLI_findlink(&mesh_dst->key->block, ob->shapenr - 1);
if (kb) {
uid = kb->uid;
}
@@ -1607,11 +1613,11 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
/* NOTE(nazgul): maybe some other layers should be copied? */
if (CustomData_has_layer(&mesh_dst->ldata, CD_MDISPS)) {
if (totloop == mesh_dst->totloop) {
- MDisps *mdisps = CustomData_get_layer(&mesh_dst->ldata, CD_MDISPS);
+ MDisps *mdisps = (MDisps *)CustomData_get_layer(&mesh_dst->ldata, CD_MDISPS);
CustomData_add_layer(&tmp.ldata, CD_MDISPS, alloctype, mdisps, totloop);
if (alloctype == CD_ASSIGN) {
- /* Assign NULL to prevent double-free. */
- CustomData_set_layer(&mesh_dst->ldata, CD_MDISPS, NULL);
+ /* Assign nullptr to prevent double-free. */
+ CustomData_set_layer(&mesh_dst->ldata, CD_MDISPS, nullptr);
}
}
}
@@ -1633,7 +1639,7 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
if (tmp.key && !(tmp.id.tag & LIB_TAG_NO_MAIN)) {
id_us_min(&tmp.key->id);
}
- tmp.key = NULL;
+ tmp.key = nullptr;
}
/* Clear selection history */
@@ -1660,7 +1666,7 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
CustomData_free_typemask(&mesh_src->ldata, mesh_src->totloop, ~mask->lmask);
CustomData_free_typemask(&mesh_src->pdata, mesh_src->totpoly, ~mask->pmask);
}
- BKE_id_free(NULL, mesh_src);
+ BKE_id_free(nullptr, mesh_src);
}
}
@@ -1682,7 +1688,7 @@ void BKE_mesh_nomain_to_meshkey(Mesh *mesh_src, Mesh *mesh_dst, KeyBlock *kb)
kb->data = MEM_malloc_arrayN(mesh_dst->key->elemsize, mesh_dst->totvert, "kb->data");
kb->totelem = totvert;
- fp = kb->data;
+ fp = (float *)kb->data;
mvert = mesh_src->mvert;
for (a = 0; a < kb->totelem; a++, fp += 3, mvert++) {
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index b2ebab67100..3fcc0db017f 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -5259,6 +5259,9 @@ static void registerGeometryNodes()
{
register_node_type_geo_group();
+ register_node_type_geo_legacy_material_assign();
+ register_node_type_geo_legacy_select_by_material();
+
register_node_type_geo_align_rotation_to_vector();
register_node_type_geo_attribute_clamp();
register_node_type_geo_attribute_color_ramp();
@@ -5331,7 +5334,7 @@ static void registerGeometryNodes()
register_node_type_geo_raycast();
register_node_type_geo_sample_texture();
register_node_type_geo_select_by_handle_type();
- register_node_type_geo_select_by_material();
+ register_node_type_geo_material_selection();
register_node_type_geo_separate_components();
register_node_type_geo_set_position();
register_node_type_geo_subdivision_surface();
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 065240bddbc..73e25a22225 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -312,7 +312,7 @@ IDTypeInfo IDType_ID_SCR = {
.name = "Screen",
.name_plural = "screens",
.translation_context = BLT_I18NCONTEXT_ID_SCREEN,
- .flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_MAKELOCAL | IDTYPE_FLAGS_NO_ANIMDATA,
+ .flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_ONLY_APPEND | IDTYPE_FLAGS_NO_ANIMDATA,
.init_data = NULL,
.copy_data = NULL,
diff --git a/source/blender/blenkernel/intern/spline_base.cc b/source/blender/blenkernel/intern/spline_base.cc
index 732fabc6582..a8871777420 100644
--- a/source/blender/blenkernel/intern/spline_base.cc
+++ b/source/blender/blenkernel/intern/spline_base.cc
@@ -19,6 +19,8 @@
#include "BLI_task.hh"
#include "BLI_timeit.hh"
+#include "BKE_attribute_access.hh"
+#include "BKE_attribute_math.hh"
#include "BKE_spline.hh"
#include "FN_generic_virtual_array.hh"
@@ -28,6 +30,8 @@ using blender::float3;
using blender::IndexRange;
using blender::MutableSpan;
using blender::Span;
+using blender::attribute_math::convert_to_static_type;
+using blender::bke::AttributeIDRef;
using blender::fn::GMutableSpan;
using blender::fn::GSpan;
using blender::fn::GVArray;
@@ -110,6 +114,31 @@ void Spline::transform(const blender::float4x4 &matrix)
this->mark_cache_invalid();
}
+void Spline::reverse()
+{
+ this->positions().reverse();
+ this->radii().reverse();
+ this->tilts().reverse();
+
+ this->attributes.foreach_attribute(
+ [&](const AttributeIDRef &id, const AttributeMetaData &meta_data) {
+ std::optional<blender::fn::GMutableSpan> attribute = this->attributes.get_for_write(id);
+ if (!attribute) {
+ BLI_assert_unreachable();
+ return false;
+ }
+ convert_to_static_type(meta_data.data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ attribute->typed<T>().reverse();
+ });
+ return true;
+ },
+ ATTR_DOMAIN_POINT);
+
+ this->reverse_impl();
+ this->mark_cache_invalid();
+}
+
int Spline::evaluated_edges_size() const
{
const int eval_size = this->evaluated_points_size();
diff --git a/source/blender/blenkernel/intern/spline_bezier.cc b/source/blender/blenkernel/intern/spline_bezier.cc
index b6764f65631..79d2137ee84 100644
--- a/source/blender/blenkernel/intern/spline_bezier.cc
+++ b/source/blender/blenkernel/intern/spline_bezier.cc
@@ -166,6 +166,17 @@ MutableSpan<float3> BezierSpline::handle_positions_right()
return handle_positions_right_;
}
+void BezierSpline::reverse_impl()
+{
+ this->handle_positions_left().reverse();
+ this->handle_positions_right().reverse();
+ std::swap(this->handle_positions_left_, this->handle_positions_right_);
+
+ this->handle_types_left().reverse();
+ this->handle_types_right().reverse();
+ std::swap(this->handle_types_left_, this->handle_types_right_);
+}
+
static float3 previous_position(Span<float3> positions, const bool cyclic, const int i)
{
if (i == 0) {
diff --git a/source/blender/blenkernel/intern/spline_nurbs.cc b/source/blender/blenkernel/intern/spline_nurbs.cc
index ac6f1bd082c..6d30d8ba916 100644
--- a/source/blender/blenkernel/intern/spline_nurbs.cc
+++ b/source/blender/blenkernel/intern/spline_nurbs.cc
@@ -142,6 +142,11 @@ Span<float> NURBSpline::weights() const
return weights_;
}
+void NURBSpline::reverse_impl()
+{
+ this->weights().reverse();
+}
+
void NURBSpline::mark_cache_invalid()
{
basis_cache_dirty_ = true;
diff --git a/source/blender/blenkernel/intern/spline_poly.cc b/source/blender/blenkernel/intern/spline_poly.cc
index dfd24b2566e..338b5d0ac9e 100644
--- a/source/blender/blenkernel/intern/spline_poly.cc
+++ b/source/blender/blenkernel/intern/spline_poly.cc
@@ -91,6 +91,10 @@ Span<float> PolySpline::tilts() const
return tilts_;
}
+void PolySpline::reverse_impl()
+{
+}
+
void PolySpline::mark_cache_invalid()
{
tangent_cache_dirty_ = true;
diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c
index da6ee8d8779..e9cd0b70019 100644
--- a/source/blender/blenkernel/intern/subdiv_mesh.c
+++ b/source/blender/blenkernel/intern/subdiv_mesh.c
@@ -1232,7 +1232,7 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
// BKE_mesh_validate(result, true, true);
BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
if (!subdiv_context.can_evaluate_normals) {
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
}
/* Free used memory. */
subdiv_mesh_context_free(&subdiv_context);
diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c
index 329633c6759..3c168a6c7b2 100644
--- a/source/blender/blenkernel/intern/workspace.c
+++ b/source/blender/blenkernel/intern/workspace.c
@@ -186,7 +186,7 @@ IDTypeInfo IDType_ID_WS = {
.name = "WorkSpace",
.name_plural = "workspaces",
.translation_context = BLT_I18NCONTEXT_ID_WORKSPACE,
- .flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_MAKELOCAL | IDTYPE_FLAGS_NO_ANIMDATA,
+ .flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_ONLY_APPEND | IDTYPE_FLAGS_NO_ANIMDATA,
.init_data = workspace_init_data,
.copy_data = NULL,
diff --git a/source/blender/blenlib/BLI_span.hh b/source/blender/blenlib/BLI_span.hh
index e04295b0e51..5adb47ba0b0 100644
--- a/source/blender/blenlib/BLI_span.hh
+++ b/source/blender/blenlib/BLI_span.hh
@@ -644,6 +644,16 @@ template<typename T> class MutableSpan {
}
/**
+ * Reverse the data in the MutableSpan.
+ */
+ constexpr void reverse()
+ {
+ for (const int i : IndexRange(size_ / 2)) {
+ std::swap(data_[size_ - 1 - i], data_[i]);
+ }
+ }
+
+ /**
* Returns an (immutable) Span that references the same array. This is usually not needed,
* due to implicit conversions. However, sometimes automatic type deduction needs some help.
*/
diff --git a/source/blender/blenlib/tests/BLI_span_test.cc b/source/blender/blenlib/tests/BLI_span_test.cc
index 4d23a53c08a..fb88fb63e53 100644
--- a/source/blender/blenlib/tests/BLI_span_test.cc
+++ b/source/blender/blenlib/tests/BLI_span_test.cc
@@ -362,6 +362,29 @@ TEST(span, ReverseIterator)
EXPECT_EQ_ARRAY(reversed_vec.data(), Span({7, 6, 5, 4}).data(), 4);
}
+TEST(span, ReverseMutableSpan)
+{
+ std::array<int, 0> src0 = {};
+ MutableSpan<int> span0 = src0;
+ span0.reverse();
+ EXPECT_EQ_ARRAY(span0.data(), Span<int>({}).data(), 0);
+
+ std::array<int, 1> src1 = {4};
+ MutableSpan<int> span1 = src1;
+ span1.reverse();
+ EXPECT_EQ_ARRAY(span1.data(), Span<int>({4}).data(), 1);
+
+ std::array<int, 2> src2 = {4, 5};
+ MutableSpan<int> span2 = src2;
+ span2.reverse();
+ EXPECT_EQ_ARRAY(span2.data(), Span<int>({5, 4}).data(), 2);
+
+ std::array<int, 5> src5 = {4, 5, 6, 7, 8};
+ MutableSpan<int> span5 = src5;
+ span5.reverse();
+ EXPECT_EQ_ARRAY(span5.data(), Span<int>({8, 7, 6, 5, 4}).data(), 5);
+}
+
TEST(span, MutableReverseIterator)
{
std::array<int, 4> src = {4, 5, 6, 7};
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index 4eba9f5f42e..538634f4c9e 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -239,6 +239,16 @@ static void do_versions_idproperty_bones_recursive(Bone *bone)
}
}
+static void do_versions_idproperty_seq_recursive(ListBase *seqbase)
+{
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ version_idproperty_ui_data(seq->prop);
+ if (seq->type == SEQ_TYPE_META) {
+ do_versions_idproperty_seq_recursive(&seq->seqbase);
+ }
+ }
+}
+
/**
* For every data block that supports them, initialize the new IDProperty UI data struct based on
* the old more complicated storage. Assumes only the top level of IDProperties below the parent
@@ -299,9 +309,7 @@ static void do_versions_idproperty_ui_data(Main *bmain)
/* Sequences. */
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
if (scene->ed != NULL) {
- LISTBASE_FOREACH (Sequence *, seq, &scene->ed->seqbase) {
- version_idproperty_ui_data(seq->prop);
- }
+ do_versions_idproperty_seq_recursive(&scene->ed->seqbase);
}
}
}
@@ -1253,5 +1261,18 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
*/
{
/* Keep this block, even when empty. */
+
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_FILE) {
+ SpaceFile *sfile = (SpaceFile *)sl;
+ if (sfile->asset_params) {
+ sfile->asset_params->base_params.recursion_level = FILE_SELECT_MAX_RECURSIONS;
+ }
+ }
+ }
+ }
+ }
}
}
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index 19f6c1cbbf6..f4853ff803f 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -887,7 +887,7 @@ void blo_do_versions_userdef(UserDef *userdef)
if (!USER_VERSION_ATLEAST(300, 21)) {
/* Deprecated userdef->flag USER_SAVE_PREVIEWS */
- userdef->file_preview_type = (userdef->flag & USER_FLAG_UNUSED_5) ? USER_FILE_PREVIEW_CAMERA :
+ userdef->file_preview_type = (userdef->flag & USER_FLAG_UNUSED_5) ? USER_FILE_PREVIEW_AUTO :
USER_FILE_PREVIEW_NONE;
/* Clear for reuse. */
userdef->flag &= ~USER_FLAG_UNUSED_5;
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index 45bf18fe1bb..21a5c6c2865 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -259,7 +259,7 @@ static int armature_click_extrude_invoke(bContext *C, wmOperator *op, const wmEv
void ARMATURE_OT_click_extrude(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Click-Extrude";
+ ot->name = "Extrude to Cursor";
ot->idname = "ARMATURE_OT_click_extrude";
ot->description = "Create a new bone going from the last selected joint to the mouse position";
@@ -269,7 +269,7 @@ void ARMATURE_OT_click_extrude(wmOperatorType *ot)
ot->poll = ED_operator_editarmature;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* props */
}
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index c399abfa52d..9b43e23bd32 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -5620,7 +5620,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void CURVE_OT_vertex_add(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Add Vertex";
+ ot->name = "Extrude to Cursor or Add";
ot->idname = "CURVE_OT_vertex_add";
ot->description = "Add a new control point (linked to only selected end-curve one, if any)";
@@ -5630,7 +5630,7 @@ void CURVE_OT_vertex_add(wmOperatorType *ot)
ot->poll = ED_operator_editcurve;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* properties */
RNA_def_float_vector_xyz(ot->srna,
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index aa3178ddc2c..75ddfa47c57 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -5243,7 +5243,7 @@ void GPENCIL_OT_stroke_cutter(wmOperatorType *ot)
ot->cancel = WM_gesture_lasso_cancel;
/* flag */
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* properties */
WM_operator_properties_gesture_lasso(ot);
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index 93bae7d3614..6ad2fffc773 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -2347,7 +2347,7 @@ void GPENCIL_OT_select_lasso(wmOperatorType *ot)
ot->cancel = WM_gesture_lasso_cancel;
/* flags */
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* properties */
WM_operator_properties_select_operation(ot);
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 977e9661dd9..77ae16d7cc7 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -508,6 +508,7 @@ typedef struct uiAfterFunc {
bContextStore *context;
char undostr[BKE_UNDO_STR_MAX];
+ char drawstr[UI_MAX_DRAW_STR];
} uiAfterFunc;
static void button_activate_init(bContext *C,
@@ -790,6 +791,10 @@ static void ui_handle_afterfunc_add_operator_ex(wmOperatorType *ot,
if (context_but && context_but->context) {
after->context = CTX_store_copy(context_but->context);
}
+
+ if (context_but) {
+ ui_but_drawstr_without_sep_char(context_but, after->drawstr, sizeof(after->drawstr));
+ }
}
void ui_handle_afterfunc_add_operator(wmOperatorType *ot, int opcontext)
@@ -900,6 +905,8 @@ static void ui_apply_but_func(bContext *C, uiBut *but)
after->context = CTX_store_copy(but->context);
}
+ ui_but_drawstr_without_sep_char(but, after->drawstr, sizeof(after->drawstr));
+
but->optype = NULL;
but->opcontext = 0;
but->opptr = NULL;
@@ -1021,7 +1028,8 @@ static void ui_apply_but_funcs_after(bContext *C)
}
if (after.optype) {
- WM_operator_name_call_ptr(C, after.optype, after.opcontext, (after.opptr) ? &opptr : NULL);
+ WM_operator_name_call_ptr_with_depends_on_cursor(
+ C, after.optype, after.opcontext, (after.opptr) ? &opptr : NULL, after.drawstr);
}
if (after.opptr) {
@@ -4190,10 +4198,11 @@ static void ui_but_extra_operator_icon_apply(bContext *C, uiBut *but, uiButExtra
ui_apply_but(C, but->block, but, but->active, true);
}
button_activate_state(C, but, BUTTON_STATE_EXIT);
- WM_operator_name_call_ptr(C,
- op_icon->optype_params->optype,
- op_icon->optype_params->opcontext,
- op_icon->optype_params->opptr);
+ WM_operator_name_call_ptr_with_depends_on_cursor(C,
+ op_icon->optype_params->optype,
+ op_icon->optype_params->opcontext,
+ op_icon->optype_params->opptr,
+ NULL);
/* Force recreation of extra operator icons (pseudo update). */
ui_but_extra_operator_icons_free(but);
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index ec5a30f7793..66c75c63050 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -921,10 +921,10 @@ static void ui_keymap_but_cb(bContext *UNUSED(C), void *but_v, void *UNUSED(key_
{
uiBut *but = but_v;
- RNA_boolean_set(&but->rnapoin, "shift", (but->modifier_key & KM_SHIFT) != 0);
- RNA_boolean_set(&but->rnapoin, "ctrl", (but->modifier_key & KM_CTRL) != 0);
- RNA_boolean_set(&but->rnapoin, "alt", (but->modifier_key & KM_ALT) != 0);
- RNA_boolean_set(&but->rnapoin, "oskey", (but->modifier_key & KM_OSKEY) != 0);
+ RNA_int_set(&but->rnapoin, "shift", (but->modifier_key & KM_SHIFT) ? KM_MOD_HELD : KM_NOTHING);
+ RNA_int_set(&but->rnapoin, "ctrl", (but->modifier_key & KM_CTRL) ? KM_MOD_HELD : KM_NOTHING);
+ RNA_int_set(&but->rnapoin, "alt", (but->modifier_key & KM_ALT) ? KM_MOD_HELD : KM_NOTHING);
+ RNA_int_set(&but->rnapoin, "oskey", (but->modifier_key & KM_OSKEY) ? KM_MOD_HELD : KM_NOTHING);
}
/**
diff --git a/source/blender/editors/interface/interface_template_search_menu.c b/source/blender/editors/interface/interface_template_search_menu.c
index 3105891142f..672f1b64943 100644
--- a/source/blender/editors/interface/interface_template_search_menu.c
+++ b/source/blender/editors/interface/interface_template_search_menu.c
@@ -955,7 +955,8 @@ static void menu_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2)
switch (item->type) {
case MENU_SEARCH_TYPE_OP: {
CTX_store_set(C, item->op.context);
- WM_operator_name_call_ptr(C, item->op.type, item->op.opcontext, item->op.opptr);
+ WM_operator_name_call_ptr_with_depends_on_cursor(
+ C, item->op.type, item->op.opcontext, item->op.opptr, item->drawstr);
CTX_store_set(C, NULL);
break;
}
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 08d78552710..0c9eb20af19 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -673,8 +673,8 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
}
}
else {
- if (BKE_lib_id_make_local(bmain, id, false, 0)) {
- BKE_main_id_newptr_and_tag_clear(bmain);
+ if (BKE_lib_id_make_local(bmain, id, 0)) {
+ BKE_id_newptr_and_tag_clear(id);
/* Reassign to get proper updates/notifiers. */
idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
@@ -1031,7 +1031,7 @@ static void template_ID(const bContext *C,
UI_but_flag_enable(but, UI_BUT_DISABLED);
}
else {
- const bool disabled = (!BKE_lib_id_make_local(CTX_data_main(C), id, true /* test */, 0) ||
+ const bool disabled = (!BKE_idtype_idcode_is_localizable(GS(id->name)) ||
(idfrom && idfrom->lib));
but = uiDefIconBut(block,
UI_BTYPE_BUT,
diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c
index 6a1be8dcef3..fe6acac7d29 100644
--- a/source/blender/editors/mask/mask_select.c
+++ b/source/blender/editors/mask/mask_select.c
@@ -629,7 +629,7 @@ void MASK_OT_select_lasso(wmOperatorType *ot)
ot->cancel = WM_gesture_lasso_cancel;
/* flags */
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* properties */
WM_operator_properties_gesture_lasso(ot);
diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c
index 5cb57594ec3..27a1bf9658f 100644
--- a/source/blender/editors/mesh/editmesh_bisect.c
+++ b/source/blender/editors/mesh/editmesh_bisect.c
@@ -777,7 +777,7 @@ static void MESH_GGT_bisect(struct wmGizmoGroupType *gzgt)
gzgt->name = "Mesh Bisect";
gzgt->idname = "MESH_GGT_bisect";
- gzgt->flag = WM_GIZMOGROUPTYPE_3D;
+ gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index 907881a44f3..e4cd48d95bb 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -925,7 +925,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Duplicate or Extrude to Cursor";
+ ot->name = "Extrude to Cursor or Add";
ot->idname = "MESH_OT_dupli_extrude_cursor";
ot->description =
"Duplicate and extrude selected vertices, edges or faces towards the mouse cursor";
@@ -935,7 +935,7 @@ void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot)
ot->poll = ED_operator_editmesh_region_view3d;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
RNA_def_boolean(ot->srna,
"rotate_source",
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index 0553fa077f8..d1df063d9d0 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -1124,7 +1124,7 @@ void MESH_OT_rip(wmOperatorType *ot)
ot->poll = EDBM_view3d_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* to give to transform */
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY);
diff --git a/source/blender/editors/mesh/editmesh_rip_edge.c b/source/blender/editors/mesh/editmesh_rip_edge.c
index f7e88284d93..ce49f0f80a3 100644
--- a/source/blender/editors/mesh/editmesh_rip_edge.c
+++ b/source/blender/editors/mesh/editmesh_rip_edge.c
@@ -249,7 +249,7 @@ void MESH_OT_rip_edge(wmOperatorType *ot)
ot->poll = EDBM_view3d_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* to give to transform */
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY);
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 956658bd2b7..122214b87d5 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -4323,7 +4323,7 @@ void MESH_OT_knife_cut(wmOperatorType *ot)
ot->poll = EDBM_view3d_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* properties */
PropertyRNA *prop;
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index b2d3216b101..50dd9322c5c 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -191,6 +191,7 @@ void OBJECT_OT_skin_radii_equalize(struct wmOperatorType *ot);
void OBJECT_OT_skin_armature_create(struct wmOperatorType *ot);
void OBJECT_OT_laplaciandeform_bind(struct wmOperatorType *ot);
void OBJECT_OT_surfacedeform_bind(struct wmOperatorType *ot);
+void OBJECT_OT_geometry_nodes_input_attribute_toggle(struct wmOperatorType *ot);
/* object_gpencil_modifiers.c */
void OBJECT_OT_gpencil_modifier_add(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index 2a1a6696493..b9942bc563a 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -3242,3 +3242,54 @@ void OBJECT_OT_surfacedeform_bind(wmOperatorType *ot)
}
/** \} */
+
+/* ------------------------------------------------------------------- */
+/** \name Toggle Value or Attribute Operator
+ *
+ * \note This operator basically only exists to provide a better tooltip for the toggle button,
+ * since it is stored as an IDProperty. It also stops the button from being highlighted when
+ * "use_attribute" is on, which isn't expected.
+ * \{ */
+
+static int geometry_nodes_input_attribute_toggle_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_active_context(C);
+
+ char modifier_name[MAX_NAME];
+ RNA_string_get(op->ptr, "modifier_name", modifier_name);
+ NodesModifierData *nmd = (NodesModifierData *)BKE_modifiers_findby_name(ob, modifier_name);
+ if (nmd == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ char prop_path[MAX_NAME];
+ RNA_string_get(op->ptr, "prop_path", prop_path);
+
+ PointerRNA mod_ptr;
+ RNA_pointer_create(&ob->id, &RNA_Modifier, nmd, &mod_ptr);
+
+ const int old_value = RNA_int_get(&mod_ptr, prop_path);
+ const int new_value = !old_value;
+ RNA_int_set(&mod_ptr, prop_path, new_value);
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_geometry_nodes_input_attribute_toggle(wmOperatorType *ot)
+{
+ ot->name = "Input Attribute Toggle";
+ ot->description =
+ "Switch between an attribute and a single value to define the data for every element";
+ ot->idname = "OBJECT_OT_geometry_nodes_input_attribute_toggle";
+
+ ot->exec = geometry_nodes_input_attribute_toggle_exec;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+
+ RNA_def_string(ot->srna, "prop_path", NULL, 0, "Prop Path", "");
+ RNA_def_string(ot->srna, "modifier_name", NULL, MAX_NAME, "Modifier Name", "");
+}
+
+/** \} */
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index 4b8431be530..aa9ae082317 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -145,6 +145,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_skin_loose_mark_clear);
WM_operatortype_append(OBJECT_OT_skin_radii_equalize);
WM_operatortype_append(OBJECT_OT_skin_armature_create);
+ WM_operatortype_append(OBJECT_OT_geometry_nodes_input_attribute_toggle);
/* grease pencil modifiers */
WM_operatortype_append(OBJECT_OT_gpencil_modifier_add);
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index e08a4e946f6..9546035375c 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -882,7 +882,7 @@ static void area_azone_init(wmWindow *win, const bScreen *screen, ScrArea *area)
return;
}
- if (U.app_flag & USER_APP_LOCK_UI_LAYOUT) {
+ if (U.app_flag & USER_APP_LOCK_CORNER_SPLIT) {
return;
}
@@ -1058,6 +1058,14 @@ static bool region_azone_edge_poll(const ARegion *region, const bool is_fullscre
return false;
}
+ if (is_hidden && (U.app_flag & USER_APP_HIDE_REGION_TOGGLE)) {
+ return false;
+ }
+
+ if (!is_hidden && (U.app_flag & USER_APP_LOCK_EDGE_RESIZE)) {
+ return false;
+ }
+
return true;
}
diff --git a/source/blender/editors/screen/screen_geometry.c b/source/blender/editors/screen/screen_geometry.c
index 51edad0332b..e67c933cb8e 100644
--- a/source/blender/editors/screen/screen_geometry.c
+++ b/source/blender/editors/screen/screen_geometry.c
@@ -130,6 +130,10 @@ ScrEdge *screen_geom_find_active_scredge(const wmWindow *win,
const int mx,
const int my)
{
+ if (U.app_flag & USER_APP_LOCK_EDGE_RESIZE) {
+ return NULL;
+ }
+
/* Use layout size (screen excluding global areas) for screen-layout area edges */
rcti screen_rect;
WM_window_screen_rect_calc(win, &screen_rect);
diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h
index 683f2844371..4016ef84bfd 100644
--- a/source/blender/editors/screen/screen_intern.h
+++ b/source/blender/editors/screen/screen_intern.h
@@ -128,6 +128,7 @@ extern const char *screen_context_dir[]; /* doc access */
/* screendump.c */
void SCREEN_OT_screenshot(struct wmOperatorType *ot);
+void SCREEN_OT_screenshot_area(struct wmOperatorType *ot);
/* workspace_layout_edit.c */
bool workspace_layout_set_poll(const struct WorkSpaceLayout *layout);
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 3efe4ae85d5..674a2deb929 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -5690,6 +5690,7 @@ void ED_operatortypes_screen(void)
WM_operatortype_append(SCREEN_OT_back_to_previous);
WM_operatortype_append(SCREEN_OT_spacedata_cleanup);
WM_operatortype_append(SCREEN_OT_screenshot);
+ WM_operatortype_append(SCREEN_OT_screenshot_area);
WM_operatortype_append(SCREEN_OT_userpref_show);
WM_operatortype_append(SCREEN_OT_drivers_editor_show);
WM_operatortype_append(SCREEN_OT_info_log_show);
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index 6df96b1e30f..8056e02d17a 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -42,6 +42,7 @@
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_report.h"
+#include "BKE_screen.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -57,12 +58,13 @@ typedef struct ScreenshotData {
uint *dumprect;
int dumpsx, dumpsy;
rcti crop;
+ bool use_crop;
ImageFormatData im_format;
} ScreenshotData;
/* call from both exec and invoke */
-static int screenshot_data_create(bContext *C, wmOperator *op)
+static int screenshot_data_create(bContext *C, wmOperator *op, ScrArea *area)
{
int dumprect_size[2];
@@ -76,7 +78,6 @@ static int screenshot_data_create(bContext *C, wmOperator *op)
if (dumprect) {
ScreenshotData *scd = MEM_callocN(sizeof(ScreenshotData), "screenshot");
- ScrArea *area = CTX_wm_area(C);
scd->dumpsx = dumprect_size[0];
scd->dumpsy = dumprect_size[1];
@@ -110,12 +111,13 @@ static void screenshot_data_free(wmOperator *op)
static int screenshot_exec(bContext *C, wmOperator *op)
{
+ const bool use_crop = STREQ(op->idname, "SCREEN_OT_screenshot_area");
ScreenshotData *scd = op->customdata;
bool ok = false;
if (scd == NULL) {
/* when running exec directly */
- screenshot_data_create(C, op);
+ screenshot_data_create(C, op, use_crop ? CTX_wm_area(C) : NULL);
scd = op->customdata;
}
@@ -132,7 +134,7 @@ static int screenshot_exec(bContext *C, wmOperator *op)
ibuf->rect = scd->dumprect;
/* crop to show only single editor */
- if (!RNA_boolean_get(op->ptr, "full")) {
+ if (use_crop) {
IMB_rect_crop(ibuf, &scd->crop);
scd->dumprect = ibuf->rect;
}
@@ -157,9 +159,20 @@ static int screenshot_exec(bContext *C, wmOperator *op)
return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
-static int screenshot_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static int screenshot_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- if (screenshot_data_create(C, op)) {
+ const bool use_crop = STREQ(op->idname, "SCREEN_OT_screenshot_area");
+ ScrArea *area = NULL;
+ 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->x, event->y);
+ if (area_test != NULL) {
+ area = area_test;
+ }
+ }
+
+ if (screenshot_data_create(C, op, area)) {
if (RNA_struct_property_is_set(op->ptr, "filepath")) {
return screenshot_exec(C, op);
}
@@ -226,12 +239,8 @@ static bool screenshot_poll(bContext *C)
return WM_operator_winactive(C);
}
-void SCREEN_OT_screenshot(wmOperatorType *ot)
+static void screen_screenshot_impl(wmOperatorType *ot)
{
- ot->name = "Save Screenshot";
- ot->idname = "SCREEN_OT_screenshot";
- ot->description = "Capture a picture of the active area or whole Blender window";
-
ot->invoke = screenshot_invoke;
ot->check = screenshot_check;
ot->exec = screenshot_exec;
@@ -239,8 +248,6 @@ void SCREEN_OT_screenshot(wmOperatorType *ot)
ot->ui = screenshot_draw;
ot->poll = screenshot_poll;
- ot->flag = 0;
-
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_IMAGE,
FILE_SPECIAL,
@@ -248,9 +255,26 @@ void SCREEN_OT_screenshot(wmOperatorType *ot)
WM_FILESEL_FILEPATH,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
- RNA_def_boolean(ot->srna,
- "full",
- 1,
- "Full Screen",
- "Capture the whole window (otherwise only capture the active area)");
+}
+
+void SCREEN_OT_screenshot(wmOperatorType *ot)
+{
+ ot->name = "Save Screenshot";
+ ot->idname = "SCREEN_OT_screenshot";
+ ot->description = "Capture a picture of the whole Blender window";
+
+ screen_screenshot_impl(ot);
+
+ ot->flag = 0;
+}
+
+void SCREEN_OT_screenshot_area(wmOperatorType *ot)
+{
+ ot->name = "Save Screenshot (Area)";
+ ot->idname = "SCREEN_OT_screenshot_area";
+ ot->description = "Capture a picture of the active area";
+
+ screen_screenshot_impl(ot);
+
+ ot->flag = OPTYPE_DEPENDS_ON_CURSOR;
}
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index d968b6cc319..e65d6ce2d48 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -1300,7 +1300,7 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext)
}),
sculpt_mesh);
BM_mesh_free(bm);
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
BKE_mesh_nomain_to_mesh(
result, sgcontext->vc.obact->data, sgcontext->vc.obact, &CD_MASK_MESH, true);
}
@@ -1651,7 +1651,7 @@ void PAINT_OT_mask_lasso_gesture(wmOperatorType *ot)
ot->poll = SCULPT_mode_poll_view3d;
- ot->flag = OPTYPE_REGISTER;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_DEPENDS_ON_CURSOR;
/* Properties. */
WM_operator_properties_gesture_lasso(ot);
@@ -1714,6 +1714,8 @@ void SCULPT_OT_face_set_lasso_gesture(wmOperatorType *ot)
ot->poll = SCULPT_mode_poll_view3d;
+ ot->flag = OPTYPE_DEPENDS_ON_CURSOR;
+
/* Properties. */
WM_operator_properties_gesture_lasso(ot);
sculpt_gesture_operator_properties(ot);
@@ -1750,7 +1752,7 @@ void SCULPT_OT_trim_lasso_gesture(wmOperatorType *ot)
ot->poll = SCULPT_mode_poll_view3d;
- ot->flag = OPTYPE_REGISTER;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_DEPENDS_ON_CURSOR;
/* Properties. */
WM_operator_properties_gesture_lasso(ot);
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index a5e75e31e38..26d71178b68 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -834,7 +834,7 @@ void ACTION_OT_select_lasso(wmOperatorType *ot)
ot->cancel = WM_gesture_lasso_cancel;
/* flags */
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* properties */
WM_operator_properties_gesture_lasso(ot);
diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c
index c7f0f4c228f..73a73eb7911 100644
--- a/source/blender/editors/space_clip/tracking_select.c
+++ b/source/blender/editors/space_clip/tracking_select.c
@@ -721,7 +721,7 @@ void CLIP_OT_select_lasso(wmOperatorType *ot)
ot->cancel = WM_gesture_lasso_cancel;
/* flags */
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* properties */
WM_operator_properties_gesture_lasso(ot);
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 4ab7014cf82..11b06d2b414 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -135,7 +135,8 @@ static void fileselect_ensure_updated_asset_params(SpaceFile *sfile)
base_params->filter_id = FILTER_ID_OB | FILTER_ID_GR;
base_params->display = FILE_IMGDISPLAY;
base_params->sort = FILE_SORT_ALPHA;
- base_params->recursion_level = 1;
+ /* Asset libraries include all sub-directories, so enable maximal recursion. */
+ base_params->recursion_level = FILE_SELECT_MAX_RECURSIONS;
/* 'SMALL' size by default. More reasonable since this is typically used as regular editor,
* space is more of an issue here. */
base_params->thumbnail_size = 96;
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index a853efb1ace..ffe74e20bdf 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -1006,7 +1006,7 @@ void GRAPH_OT_select_lasso(wmOperatorType *ot)
ot->cancel = WM_gesture_lasso_cancel;
/* Flags. */
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* Properties. */
WM_operator_properties_gesture_lasso(ot);
diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc
index 4d2e00e97a1..7b6ca5e6e61 100644
--- a/source/blender/editors/space_node/node_add.cc
+++ b/source/blender/editors/space_node/node_add.cc
@@ -312,7 +312,7 @@ void NODE_OT_add_reroute(wmOperatorType *ot)
ot->poll = ED_operator_node_editable;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* properties */
PropertyRNA *prop;
diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc
index e908a61eed9..7d95659e403 100644
--- a/source/blender/editors/space_node/node_relationships.cc
+++ b/source/blender/editors/space_node/node_relationships.cc
@@ -1427,7 +1427,7 @@ void NODE_OT_links_cut(wmOperatorType *ot)
ot->poll = ED_operator_node_editable;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* properties */
PropertyRNA *prop;
@@ -1533,7 +1533,7 @@ void NODE_OT_links_mute(wmOperatorType *ot)
ot->poll = ED_operator_node_editable;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* properties */
PropertyRNA *prop;
diff --git a/source/blender/editors/space_node/node_select.cc b/source/blender/editors/space_node/node_select.cc
index adff85a2b8c..29b8372d043 100644
--- a/source/blender/editors/space_node/node_select.cc
+++ b/source/blender/editors/space_node/node_select.cc
@@ -923,7 +923,7 @@ void NODE_OT_select_lasso(wmOperatorType *ot)
ot->cancel = WM_gesture_lasso_cancel;
/* flags */
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* properties */
RNA_def_boolean(ot->srna,
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 7709c6bb053..9e314701719 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -737,13 +737,8 @@ static void id_local_fn(bContext *C,
{
if (ID_IS_LINKED(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) {
Main *bmain = CTX_data_main(C);
- /* if the ID type has no special local function,
- * just clear the lib */
- if (BKE_lib_id_make_local(bmain, tselem->id, false, 0) == false) {
- BKE_lib_id_clear_library_data(bmain, tselem->id);
- }
- else {
- BKE_main_id_newptr_and_tag_clear(bmain);
+ if (BKE_lib_id_make_local(bmain, tselem->id, 0)) {
+ BKE_id_newptr_and_tag_clear(tselem->id);
}
}
else if (ID_IS_OVERRIDE_LIBRARY_REAL(tselem->id)) {
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index ff98762e373..3f572bf9d5a 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -1438,7 +1438,7 @@ void VIEW3D_OT_select_lasso(wmOperatorType *ot)
ot->cancel = WM_gesture_lasso_cancel;
/* flags */
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* properties */
WM_operator_properties_gesture_lasso(ot);
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 9638ec8750e..3a4a9342e18 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -911,7 +911,8 @@ static void TRANSFORM_OT_bend(struct wmOperatorType *ot)
ot->name = "Bend";
ot->description = "Bend selected items between the 3D cursor and the mouse";
ot->idname = OP_BEND;
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+ /* Depend on cursor location because the cursor location is used to define the region to bend. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_DEPENDS_ON_CURSOR;
/* api callbacks */
ot->invoke = transform_invoke;
@@ -1091,7 +1092,7 @@ static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot)
ot->name = "Edge Slide";
ot->description = "Slide an edge loop along a mesh";
ot->idname = OP_EDGE_SLIDE;
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_DEPENDS_ON_CURSOR;
/* api callbacks */
ot->invoke = transform_invoke;
@@ -1129,7 +1130,7 @@ static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot)
ot->name = "Vertex Slide";
ot->description = "Slide a vertex along a mesh";
ot->idname = OP_VERT_SLIDE;
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_DEPENDS_ON_CURSOR;
/* api callbacks */
ot->invoke = transform_invoke;
diff --git a/source/blender/editors/uvedit/uvedit_rip.c b/source/blender/editors/uvedit/uvedit_rip.c
index 631b831411f..7e4b18340c5 100644
--- a/source/blender/editors/uvedit/uvedit_rip.c
+++ b/source/blender/editors/uvedit/uvedit_rip.c
@@ -953,7 +953,7 @@ void UV_OT_rip(wmOperatorType *ot)
ot->name = "UV Rip";
ot->description = "Rip selected vertices or a selected region";
ot->idname = "UV_OT_rip";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* api callbacks */
ot->exec = uv_rip_exec;
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
index 5a82cd31112..c0ccf1b7095 100644
--- a/source/blender/editors/uvedit/uvedit_select.c
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -3450,7 +3450,7 @@ void UV_OT_select_lasso(wmOperatorType *ot)
ot->cancel = WM_gesture_lasso_cancel;
/* flags */
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* properties */
WM_operator_properties_gesture_lasso(ot);
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 13e6904662e..5475e1bacd8 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -913,6 +913,13 @@ enum eFileDetails {
#define FILE_MAX_LIBEXTRA (FILE_MAX + MAX_ID_NAME)
+/**
+ * Maximum level of recursions accepted for #FileSelectParams.recursion_level. Rather than a
+ * completely arbitrary limit or none at all, make it just enough to support the most extreme case
+ * where the maximal path length is used with single letter directory/file names only.
+ */
+#define FILE_SELECT_MAX_RECURSIONS (FILE_MAX_LIBEXTRA / 2)
+
/* filesel types */
typedef enum eFileSelectType {
FILE_LOADLIB = 1,
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 7160d2c3751..4f86201ced2 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -1015,6 +1015,7 @@ typedef enum eUserPref_Flag {
/** #UserDef.file_preview_type */
typedef enum eUserpref_File_Preview_Type {
USER_FILE_PREVIEW_NONE = 0,
+ USER_FILE_PREVIEW_AUTO,
USER_FILE_PREVIEW_SCREENSHOT,
USER_FILE_PREVIEW_CAMERA,
} eUserpref_File_Preview_Type;
@@ -1135,7 +1136,9 @@ typedef enum eUserpref_TableAPI {
/** #UserDef.app_flag */
typedef enum eUserpref_APP_Flag {
- USER_APP_LOCK_UI_LAYOUT = (1 << 0),
+ USER_APP_LOCK_CORNER_SPLIT = (1 << 0),
+ USER_APP_HIDE_REGION_TOGGLE = (1 << 1),
+ USER_APP_LOCK_EDGE_RESIZE = (1 << 2),
} eUserpref_APP_Flag;
/** #UserDef.statusbar_flag */
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 8f8ad077935..eb887e1881b 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -931,11 +931,10 @@ static void rna_ID_user_remap(ID *id, Main *bmain, ID *new_id)
static struct ID *rna_ID_make_local(struct ID *self, Main *bmain, bool clear_proxy)
{
- BKE_lib_id_make_local(
- bmain, self, false, clear_proxy ? 0 : LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING);
+ BKE_lib_id_make_local(bmain, self, clear_proxy ? 0 : LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING);
ID *ret_id = self->newid ? self->newid : self;
- BKE_id_clear_newpoin(self);
+ BKE_id_newptr_and_tag_clear(self);
return ret_id;
}
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 13aea804957..563c6ea35e0 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -559,6 +559,11 @@ static PointerRNA rna_UserDef_system_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_PreferencesSystem, ptr->data);
}
+static PointerRNA rna_UserDef_apps_get(PointerRNA *ptr)
+{
+ return rna_pointer_inherit_refine(ptr, &RNA_PreferencesApps, ptr->data);
+}
+
static void rna_UserDef_audio_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
BKE_sound_init(bmain);
@@ -4590,12 +4595,6 @@ static void rna_def_userdef_view(BlenderRNA *brna)
"Color range used for weight visualization in weight painting mode");
RNA_def_property_update(prop, 0, "rna_UserDef_weight_color_update");
- prop = RNA_def_property(srna, "show_layout_ui", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "app_flag", USER_APP_LOCK_UI_LAYOUT);
- RNA_def_property_ui_text(
- prop, "Editor Corner Splitting", "Split and join editors by dragging from corners");
- RNA_def_property_update(prop, 0, "rna_userdef_screen_update");
-
prop = RNA_def_property(srna, "show_navigate_ui", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_SHOW_GIZMO_NAVIGATE);
RNA_def_property_ui_text(
@@ -6061,6 +6060,7 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna)
static const EnumPropertyItem preview_type_items[] = {
{USER_FILE_PREVIEW_NONE, "NONE", 0, "None", "Do not create blend previews"},
+ {USER_FILE_PREVIEW_AUTO, "AUTO", 0, "Auto", "Automatically select best preview type"},
{USER_FILE_PREVIEW_SCREENSHOT, "SCREENSHOT", 0, "Screenshot", "Capture the entire window"},
{USER_FILE_PREVIEW_CAMERA, "CAMERA", 0, "Camera View", "Workbench render of scene"},
{0, NULL, 0, NULL, NULL},
@@ -6230,6 +6230,35 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Asset Libraries", "");
}
+static void rna_def_userdef_apps(BlenderRNA *brna)
+{
+ PropertyRNA *prop;
+ StructRNA *srna;
+
+ srna = RNA_def_struct(brna, "PreferencesApps", NULL);
+ RNA_def_struct_sdna(srna, "UserDef");
+ RNA_def_struct_nested(brna, srna, "Preferences");
+ RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
+ RNA_def_struct_ui_text(srna, "Apps", "Preferences that work only for apps");
+
+ prop = RNA_def_property(srna, "show_corner_split", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "app_flag", USER_APP_LOCK_CORNER_SPLIT);
+ RNA_def_property_ui_text(
+ prop, "Corner Splitting", "Split and join editors by dragging from corners");
+ RNA_def_property_update(prop, 0, "rna_userdef_screen_update");
+
+ prop = RNA_def_property(srna, "show_edge_resize", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "app_flag", USER_APP_LOCK_EDGE_RESIZE);
+ RNA_def_property_ui_text(prop, "Edge Resize", "Resize editors by dragging from the edges");
+ RNA_def_property_update(prop, 0, "rna_userdef_screen_update");
+
+ prop = RNA_def_property(srna, "show_regions_visibility_toggle", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "app_flag", USER_APP_HIDE_REGION_TOGGLE);
+ RNA_def_property_ui_text(
+ prop, "Regions Visibility Toggle", "Header and side bars visibility toggles");
+ RNA_def_property_update(prop, 0, "rna_userdef_screen_update");
+}
+
static void rna_def_userdef_experimental(BlenderRNA *brna)
{
StructRNA *srna;
@@ -6445,6 +6474,12 @@ void RNA_def_userdef(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "System & OpenGL", "Graphics driver and operating system settings");
+ prop = RNA_def_property(srna, "apps", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "PreferencesApps");
+ RNA_def_property_pointer_funcs(prop, "rna_UserDef_apps_get", NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Apps", "Preferences that work only for apps");
+
prop = RNA_def_property(srna, "experimental", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_struct_type(prop, "PreferencesExperimental");
@@ -6506,6 +6541,7 @@ void RNA_def_userdef(BlenderRNA *brna)
rna_def_userdef_studiolights(brna);
rna_def_userdef_studiolight(brna);
rna_def_userdef_pathcompare(brna);
+ rna_def_userdef_apps(brna);
rna_def_userdef_experimental(brna);
USERDEF_TAG_DIRTY_PROPERTY_UPDATE_DISABLE;
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 21a3c087197..c2d1ac67675 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -440,8 +440,7 @@ const EnumPropertyItem rna_enum_event_type_mask_items[] = {
static const EnumPropertyItem keymap_modifiers_items[] = {
{KM_ANY, "ANY", 0, "Any", ""},
{0, "NONE", 0, "None", ""},
- {1, "FIRST", 0, "First", ""},
- {2, "SECOND", 0, "Second", ""},
+ {KM_MOD_HELD, "HELD", 0, "Held", ""},
{0, NULL, 0, NULL, NULL},
};
#endif
@@ -468,6 +467,13 @@ const EnumPropertyItem rna_enum_operator_type_flag_items[] = {
"is enabled"},
{OPTYPE_GRAB_CURSOR_X, "GRAB_CURSOR_X", 0, "Grab Pointer X", "Grab, only warping the X axis"},
{OPTYPE_GRAB_CURSOR_Y, "GRAB_CURSOR_Y", 0, "Grab Pointer Y", "Grab, only warping the Y axis"},
+ {OPTYPE_DEPENDS_ON_CURSOR,
+ "DEPENDS_ON_CURSOR",
+ 0,
+ "Depends on Cursor",
+ "The initial cursor location is used, "
+ "when running from a menus or buttons the user is prompted to place the cursor "
+ "before beginning the operation"},
{OPTYPE_PRESET, "PRESET", 0, "Preset", "Display a preset button with the operators settings"},
{OPTYPE_INTERNAL, "INTERNAL", 0, "Internal", "Removes the operator from search results"},
{0, NULL, 0, NULL, NULL},
@@ -2725,38 +2731,62 @@ static void rna_def_keyconfig(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Any", "Any modifier keys pressed");
RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
- prop = RNA_def_property(srna, "shift", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "shift", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "shift");
+ RNA_def_property_range(prop, KM_ANY, KM_MOD_HELD);
+ RNA_def_property_ui_text(prop, "Shift", "Shift key pressed, -1 for any state");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_WINDOWMANAGER);
+ RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
+
+ prop = RNA_def_property(srna, "ctrl", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "ctrl");
+ RNA_def_property_range(prop, KM_ANY, KM_MOD_HELD);
+ RNA_def_property_ui_text(prop, "Ctrl", "Control key pressed, -1 for any state");
+ RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
+
+ prop = RNA_def_property(srna, "alt", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "alt");
+ RNA_def_property_range(prop, KM_ANY, KM_MOD_HELD);
+ RNA_def_property_ui_text(prop, "Alt", "Alt key pressed, -1 for any state");
+ RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
+
+ prop = RNA_def_property(srna, "oskey", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "oskey");
+ RNA_def_property_range(prop, KM_ANY, KM_MOD_HELD);
+ RNA_def_property_ui_text(prop, "OS Key", "Operating system key pressed, -1 for any state");
+ RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
+
+ /* XXX(@campbellbarton): the `*_ui` suffix is only for the UI, may be removed,
+ * since this is only exposed so the UI can show these settings as toggle-buttons. */
+ prop = RNA_def_property(srna, "shift_ui", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "shift", 0);
RNA_def_property_boolean_funcs(prop, "rna_KeyMapItem_shift_get", NULL);
- /* RNA_def_property_enum_sdna(prop, NULL, "shift"); */
/* RNA_def_property_enum_items(prop, keymap_modifiers_items); */
RNA_def_property_ui_text(prop, "Shift", "Shift key pressed");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_WINDOWMANAGER);
RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
- prop = RNA_def_property(srna, "ctrl", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "ctrl_ui", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "ctrl", 0);
RNA_def_property_boolean_funcs(prop, "rna_KeyMapItem_ctrl_get", NULL);
- /* RNA_def_property_enum_sdna(prop, NULL, "ctrl"); */
/* RNA_def_property_enum_items(prop, keymap_modifiers_items); */
RNA_def_property_ui_text(prop, "Ctrl", "Control key pressed");
RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
- prop = RNA_def_property(srna, "alt", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "alt_ui", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "alt", 0);
RNA_def_property_boolean_funcs(prop, "rna_KeyMapItem_alt_get", NULL);
- /* RNA_def_property_enum_sdna(prop, NULL, "alt"); */
/* RNA_def_property_enum_items(prop, keymap_modifiers_items); */
RNA_def_property_ui_text(prop, "Alt", "Alt key pressed");
RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
- prop = RNA_def_property(srna, "oskey", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "oskey_ui", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "oskey", 0);
RNA_def_property_boolean_funcs(prop, "rna_KeyMapItem_oskey_get", NULL);
- /* RNA_def_property_enum_sdna(prop, NULL, "oskey"); */
/* RNA_def_property_enum_items(prop, keymap_modifiers_items); */
RNA_def_property_ui_text(prop, "OS Key", "Operating system key pressed");
RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
+ /* End `_ui` modifiers. */
prop = RNA_def_property(srna, "key_modifier", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "keymodifier");
diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c
index e123604cbe9..7c3b119abb9 100644
--- a/source/blender/makesrna/intern/rna_wm_api.c
+++ b/source/blender/makesrna/intern/rna_wm_api.c
@@ -39,6 +39,8 @@
#include "wm_cursors.h"
#include "wm_event_types.h"
+#include "WM_types.h"
+
#include "rna_internal.h" /* own include */
/* confusing 2 enums mixed up here */
@@ -216,49 +218,70 @@ static int rna_Operator_props_popup(bContext *C, wmOperator *op, wmEvent *event)
return WM_operator_props_popup(C, op, event);
}
+static int keymap_item_modifier_flag_from_args(bool any, int shift, int ctrl, int alt, int oskey)
+{
+ int modifier = 0;
+ if (any) {
+ modifier = KM_ANY;
+ }
+ else {
+ if (shift == KM_MOD_HELD) {
+ modifier |= KM_SHIFT;
+ }
+ else if (shift == KM_ANY) {
+ modifier |= KM_SHIFT_ANY;
+ }
+
+ if (ctrl == KM_MOD_HELD) {
+ modifier |= KM_CTRL;
+ }
+ else if (ctrl == KM_ANY) {
+ modifier |= KM_CTRL_ANY;
+ }
+
+ if (alt == KM_MOD_HELD) {
+ modifier |= KM_ALT;
+ }
+ else if (alt == KM_ANY) {
+ modifier |= KM_ALT_ANY;
+ }
+
+ if (oskey == KM_MOD_HELD) {
+ modifier |= KM_OSKEY;
+ }
+ else if (oskey == KM_ANY) {
+ modifier |= KM_OSKEY_ANY;
+ }
+ }
+ return modifier;
+}
+
static wmKeyMapItem *rna_KeyMap_item_new(wmKeyMap *km,
ReportList *reports,
const char *idname,
int type,
int value,
bool any,
- bool shift,
- bool ctrl,
- bool alt,
- bool oskey,
+ int shift,
+ int ctrl,
+ int alt,
+ int oskey,
int keymodifier,
bool repeat,
bool head)
{
- // wmWindowManager *wm = CTX_wm_manager(C);
- wmKeyMapItem *kmi = NULL;
- char idname_bl[OP_MAX_TYPENAME];
- int modifier = 0;
-
/* only on non-modal maps */
if (km->flag & KEYMAP_MODAL) {
BKE_report(reports, RPT_ERROR, "Not a non-modal keymap");
return NULL;
}
- WM_operator_bl_idname(idname_bl, idname);
-
- if (shift) {
- modifier |= KM_SHIFT;
- }
- if (ctrl) {
- modifier |= KM_CTRL;
- }
- if (alt) {
- modifier |= KM_ALT;
- }
- if (oskey) {
- modifier |= KM_OSKEY;
- }
+ // wmWindowManager *wm = CTX_wm_manager(C);
+ wmKeyMapItem *kmi = NULL;
+ char idname_bl[OP_MAX_TYPENAME];
+ const int modifier = keymap_item_modifier_flag_from_args(any, shift, ctrl, alt, oskey);
- if (any) {
- modifier = KM_ANY;
- }
+ WM_operator_bl_idname(idname_bl, idname);
/* create keymap item */
kmi = WM_keymap_add_item(km, idname_bl, type, value, modifier, keymodifier);
@@ -305,39 +328,22 @@ static wmKeyMapItem *rna_KeyMap_item_new_modal(wmKeyMap *km,
int type,
int value,
bool any,
- bool shift,
- bool ctrl,
- bool alt,
- bool oskey,
+ int shift,
+ int ctrl,
+ int alt,
+ int oskey,
int keymodifier,
bool repeat)
{
- wmKeyMapItem *kmi = NULL;
- int modifier = 0;
- int propvalue = 0;
-
/* only modal maps */
if ((km->flag & KEYMAP_MODAL) == 0) {
BKE_report(reports, RPT_ERROR, "Not a modal keymap");
return NULL;
}
- if (shift) {
- modifier |= KM_SHIFT;
- }
- if (ctrl) {
- modifier |= KM_CTRL;
- }
- if (alt) {
- modifier |= KM_ALT;
- }
- if (oskey) {
- modifier |= KM_OSKEY;
- }
-
- if (any) {
- modifier = KM_ANY;
- }
+ wmKeyMapItem *kmi = NULL;
+ const int modifier = keymap_item_modifier_flag_from_args(any, shift, ctrl, alt, oskey);
+ int propvalue = 0;
/* not initialized yet, do delayed lookup */
if (!km->modal_items) {
@@ -641,7 +647,7 @@ static wmEvent *rna_Window_event_add_simulate(wmWindow *win,
e.is_repeat = false;
e.x = x;
e.y = y;
- /* NOTE: KM_MOD_FIRST, KM_MOD_SECOND aren't used anywhere, set as bools. */
+
e.shift = shift;
e.ctrl = ctrl;
e.alt = alt;
@@ -1131,10 +1137,10 @@ void RNA_api_keymapitems(StructRNA *srna)
parm = RNA_def_enum(func, "value", rna_enum_event_value_all_items, 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "any", 0, "Any", "");
- RNA_def_boolean(func, "shift", 0, "Shift", "");
- RNA_def_boolean(func, "ctrl", 0, "Ctrl", "");
- RNA_def_boolean(func, "alt", 0, "Alt", "");
- RNA_def_boolean(func, "oskey", 0, "OS Key", "");
+ RNA_def_int(func, "shift", KM_NOTHING, KM_ANY, KM_MOD_HELD, "Shift", "", KM_ANY, KM_MOD_HELD);
+ RNA_def_int(func, "ctrl", KM_NOTHING, KM_ANY, KM_MOD_HELD, "Ctrl", "", KM_ANY, KM_MOD_HELD);
+ RNA_def_int(func, "alt", KM_NOTHING, KM_ANY, KM_MOD_HELD, "Alt", "", KM_ANY, KM_MOD_HELD);
+ RNA_def_int(func, "oskey", KM_NOTHING, KM_ANY, KM_MOD_HELD, "OS Key", "", KM_ANY, KM_MOD_HELD);
RNA_def_enum(func, "key_modifier", rna_enum_event_type_items, 0, "Key Modifier", "");
RNA_def_boolean(func, "repeat", false, "Repeat", "When set, accept key-repeat events");
RNA_def_boolean(func,
@@ -1155,10 +1161,10 @@ void RNA_api_keymapitems(StructRNA *srna)
parm = RNA_def_enum(func, "value", rna_enum_event_value_all_items, 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "any", 0, "Any", "");
- RNA_def_boolean(func, "shift", 0, "Shift", "");
- RNA_def_boolean(func, "ctrl", 0, "Ctrl", "");
- RNA_def_boolean(func, "alt", 0, "Alt", "");
- RNA_def_boolean(func, "oskey", 0, "OS Key", "");
+ RNA_def_int(func, "shift", KM_NOTHING, KM_ANY, KM_MOD_HELD, "Shift", "", KM_ANY, KM_MOD_HELD);
+ RNA_def_int(func, "ctrl", KM_NOTHING, KM_ANY, KM_MOD_HELD, "Ctrl", "", KM_ANY, KM_MOD_HELD);
+ RNA_def_int(func, "alt", KM_NOTHING, KM_ANY, KM_MOD_HELD, "Alt", "", KM_ANY, KM_MOD_HELD);
+ RNA_def_int(func, "oskey", KM_NOTHING, KM_ANY, KM_MOD_HELD, "OS Key", "", KM_ANY, KM_MOD_HELD);
RNA_def_enum(func, "key_modifier", rna_enum_event_type_items, 0, "Key Modifier", "");
RNA_def_boolean(func, "repeat", false, "Repeat", "When set, accept key-repeat events");
parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", "Added key map item");
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index 6a9c9715994..2f0f11ab56d 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -786,7 +786,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
* TODO: we may need to set other dirty flags as well?
*/
if (use_recalc_normals) {
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
}
if (vgroup_start_cap_remap) {
diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c
index 8fdd222402e..add95a0d248 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -243,7 +243,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
BM_mesh_free(bm);
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_boolean.cc b/source/blender/modifiers/intern/MOD_boolean.cc
index bdb791dc8e7..c5d6902e1bc 100644
--- a/source/blender/modifiers/intern/MOD_boolean.cc
+++ b/source/blender/modifiers/intern/MOD_boolean.cc
@@ -161,7 +161,7 @@ static Mesh *get_quick_mesh(
mul_m4_v3(omat, mv->co);
}
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
}
break;
@@ -506,7 +506,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh);
BM_mesh_free(bm);
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
}
if (result == nullptr) {
@@ -541,7 +541,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh);
BM_mesh_free(bm);
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
}
}
}
diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c
index a344a15b0c1..6cd8d70383d 100644
--- a/source/blender/modifiers/intern/MOD_build.c
+++ b/source/blender/modifiers/intern/MOD_build.c
@@ -281,7 +281,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, struct
MEM_freeN(faceMap);
if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
}
/* TODO(sybren): also copy flags & tags? */
diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c
index faad1175f3a..56fcbbd8b7c 100644
--- a/source/blender/modifiers/intern/MOD_decimate.c
+++ b/source/blender/modifiers/intern/MOD_decimate.c
@@ -222,7 +222,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
TIMEIT_END(decim);
#endif
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c
index 82a6e169a7a..b21a536ad8a 100644
--- a/source/blender/modifiers/intern/MOD_edgesplit.c
+++ b/source/blender/modifiers/intern/MOD_edgesplit.c
@@ -115,7 +115,7 @@ Mesh *doEdgeSplit(const Mesh *mesh, EdgeSplitModifierData *emd)
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
BM_mesh_free(bm);
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_mask.cc b/source/blender/modifiers/intern/MOD_mask.cc
index 306e79aa647..9a8af35109a 100644
--- a/source/blender/modifiers/intern/MOD_mask.cc
+++ b/source/blender/modifiers/intern/MOD_mask.cc
@@ -814,8 +814,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx)
}
BKE_mesh_calc_edges_loose(result);
- /* Tag to recalculate normals later. */
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c
index 6116cf8146a..7fd90c71c9f 100644
--- a/source/blender/modifiers/intern/MOD_mirror.c
+++ b/source/blender/modifiers/intern/MOD_mirror.c
@@ -117,7 +117,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
result = mirrorModifier__doMirror(mmd, ctx->object, mesh);
if (result != mesh) {
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
}
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index 3b952e1e649..6b976b016e1 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -68,6 +68,8 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "WM_types.h"
+
#include "RNA_access.h"
#include "RNA_enum_types.h"
@@ -291,6 +293,17 @@ static bool logging_enabled(const ModifierEvalContext *ctx)
return true;
}
+static const std::string use_attribute_suffix = "_use_attribute";
+static const std::string attribute_name_suffix = "_attribute_name";
+
+/**
+ * \return Whether using an attribute to input values of this type is supported.
+ */
+static bool socket_type_has_attribute_toggle(const bNodeSocket &socket)
+{
+ return ELEM(socket.type, SOCK_FLOAT, SOCK_VECTOR, SOCK_BOOLEAN, SOCK_RGBA, SOCK_INT);
+}
+
static IDProperty *id_property_create_from_socket(const bNodeSocket &socket)
{
switch (socket.type) {
@@ -546,6 +559,32 @@ void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
new_prop->ui_data = ui_data;
}
}
+
+ if (socket_type_has_attribute_toggle(*socket)) {
+ const std::string use_attribute_id = socket->identifier + use_attribute_suffix;
+ const std::string attribute_name_id = socket->identifier + attribute_name_suffix;
+
+ IDPropertyTemplate idprop = {0};
+ IDProperty *use_attribute_prop = IDP_New(IDP_INT, &idprop, use_attribute_id.c_str());
+ IDP_AddToGroup(nmd->settings.properties, use_attribute_prop);
+
+ IDProperty *attribute_prop = IDP_New(IDP_STRING, &idprop, attribute_name_id.c_str());
+ IDP_AddToGroup(nmd->settings.properties, attribute_prop);
+
+ if (old_properties != nullptr) {
+ IDProperty *old_prop_use_attribute = IDP_GetPropertyFromGroup(old_properties,
+ use_attribute_id.c_str());
+ if (old_prop_use_attribute != nullptr) {
+ IDP_CopyPropertyContent(use_attribute_prop, old_prop_use_attribute);
+ }
+
+ IDProperty *old_attribute_name_prop = IDP_GetPropertyFromGroup(old_properties,
+ attribute_name_id.c_str());
+ if (old_attribute_name_prop != nullptr) {
+ IDP_CopyPropertyContent(attribute_prop, old_attribute_name_prop);
+ }
+ }
+ }
}
if (old_properties != nullptr) {
@@ -601,8 +640,33 @@ static void initialize_group_input(NodesModifierData &nmd,
return;
}
- init_socket_cpp_value_from_property(
- *property, static_cast<eNodeSocketDatatype>(socket.type), r_value);
+ if (!socket_type_has_attribute_toggle(socket)) {
+ init_socket_cpp_value_from_property(
+ *property, static_cast<eNodeSocketDatatype>(socket.type), r_value);
+ return;
+ }
+
+ const IDProperty *property_use_attribute = IDP_GetPropertyFromGroup(
+ nmd.settings.properties, (socket.identifier + use_attribute_suffix).c_str());
+ const IDProperty *property_attribute_name = IDP_GetPropertyFromGroup(
+ nmd.settings.properties, (socket.identifier + attribute_name_suffix).c_str());
+ if (property_use_attribute == nullptr || property_attribute_name == nullptr) {
+ init_socket_cpp_value_from_property(
+ *property, static_cast<eNodeSocketDatatype>(socket.type), r_value);
+ return;
+ }
+
+ const bool use_attribute = IDP_Int(property_use_attribute) != 0;
+ if (use_attribute) {
+ const StringRef attribute_name{IDP_String(property_attribute_name)};
+ auto attribute_input = std::make_shared<blender::bke::AttributeFieldInput>(
+ attribute_name, *socket.typeinfo->get_base_cpp_type());
+ new (r_value) blender::fn::GField(std::move(attribute_input), 0);
+ }
+ else {
+ init_socket_cpp_value_from_property(
+ *property, static_cast<eNodeSocketDatatype>(socket.type), r_value);
+ }
}
static Vector<SpaceSpreadsheet *> find_spreadsheet_editors(Main *bmain)
@@ -912,13 +976,13 @@ static void modifyGeometrySet(ModifierData *md,
* the node socket identifier for the property names, since they are unique, but also having
* the correct label displayed in the UI. */
static void draw_property_for_socket(uiLayout *layout,
+ NodesModifierData *nmd,
PointerRNA *bmain_ptr,
PointerRNA *md_ptr,
- const IDProperty *modifier_props,
const bNodeSocket &socket)
{
/* The property should be created in #MOD_nodes_update_interface with the correct type. */
- IDProperty *property = IDP_GetPropertyFromGroup(modifier_props, socket.identifier);
+ IDProperty *property = IDP_GetPropertyFromGroup(nmd->settings.properties, socket.identifier);
/* IDProperties can be removed with python, so there could be a situation where
* there isn't a property for a socket or it doesn't have the correct type. */
@@ -959,8 +1023,38 @@ static void draw_property_for_socket(uiLayout *layout,
uiItemPointerR(layout, md_ptr, rna_path, bmain_ptr, "textures", socket.name, ICON_TEXTURE);
break;
}
- default:
- uiItemR(layout, md_ptr, rna_path, 0, socket.name, ICON_NONE);
+ default: {
+ if (socket_type_has_attribute_toggle(socket) &&
+ USER_EXPERIMENTAL_TEST(&U, use_geometry_nodes_fields)) {
+ const std::string rna_path_use_attribute = "[\"" + std::string(socket_id_esc) +
+ use_attribute_suffix + "\"]";
+ const std::string rna_path_attribute_name = "[\"" + std::string(socket_id_esc) +
+ attribute_name_suffix + "\"]";
+
+ uiLayout *row = uiLayoutRow(layout, true);
+ const int use_attribute = RNA_int_get(md_ptr, rna_path_use_attribute.c_str()) != 0;
+ if (use_attribute) {
+ uiItemR(row, md_ptr, rna_path_attribute_name.c_str(), 0, socket.name, ICON_NONE);
+ }
+ else {
+ uiItemR(row, md_ptr, rna_path, 0, socket.name, ICON_NONE);
+ }
+ PointerRNA props;
+ uiItemFullO(row,
+ "object.geometry_nodes_input_attribute_toggle",
+ "",
+ ICON_SPREADSHEET,
+ nullptr,
+ WM_OP_INVOKE_DEFAULT,
+ 0,
+ &props);
+ RNA_string_set(&props, "modifier_name", nmd->modifier.name);
+ RNA_string_set(&props, "prop_path", rna_path_use_attribute.c_str());
+ }
+ else {
+ uiItemR(layout, md_ptr, rna_path, 0, socket.name, ICON_NONE);
+ }
+ }
}
}
@@ -991,7 +1085,7 @@ static void panel_draw(const bContext *C, Panel *panel)
RNA_main_pointer_create(bmain, &bmain_ptr);
LISTBASE_FOREACH (bNodeSocket *, socket, &nmd->node_group->inputs) {
- draw_property_for_socket(layout, &bmain_ptr, ptr, nmd->settings.properties, *socket);
+ draw_property_for_socket(layout, nmd, &bmain_ptr, ptr, *socket);
}
}
diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c
index 1dbdcf87d63..db2eedf9c02 100644
--- a/source/blender/modifiers/intern/MOD_normal_edit.c
+++ b/source/blender/modifiers/intern/MOD_normal_edit.c
@@ -450,7 +450,7 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd,
if (do_polynors_fix &&
polygons_check_flip(mloop, nos, &mesh->ldata, mpoly, polynors, num_polys)) {
- mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(mesh);
}
BKE_mesh_normals_loop_custom_set(mvert,
diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c
index 1c502b94bdb..ff1055eff3b 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -317,7 +317,7 @@ static Mesh *generate_ocean_geometry(OceanModifierData *omd, Mesh *mesh_orig, co
}
}
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
return result;
}
@@ -510,7 +510,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
result = doOcean(md, ctx, mesh);
if (result != mesh) {
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
}
return result;
diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c
index 49b5dabe72d..4fffa7c93f3 100644
--- a/source/blender/modifiers/intern/MOD_particleinstance.c
+++ b/source/blender/modifiers/intern/MOD_particleinstance.c
@@ -545,7 +545,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
MEM_SAFE_FREE(vert_part_index);
MEM_SAFE_FREE(vert_part_value);
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_remesh.c b/source/blender/modifiers/intern/MOD_remesh.c
index df3db894f4e..fef1f76c051 100644
--- a/source/blender/modifiers/intern/MOD_remesh.c
+++ b/source/blender/modifiers/intern/MOD_remesh.c
@@ -220,7 +220,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx)
BKE_mesh_copy_parameters_for_eval(result, mesh);
BKE_mesh_calc_edges(result, true, false);
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index 0819b314e32..f24f6951690 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -1135,12 +1135,12 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
ob_axis != NULL ? mtx_tx[3] : NULL,
ltmd->merge_dist);
if (result != result_prev) {
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
}
}
if ((ltmd->flag & MOD_SCREW_NORMAL_CALC) == 0) {
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
}
return result;
diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c
index 543cee18868..7d90935f678 100644
--- a/source/blender/modifiers/intern/MOD_skin.c
+++ b/source/blender/modifiers/intern/MOD_skin.c
@@ -1960,7 +1960,7 @@ static Mesh *base_skin(Mesh *origmesh, SkinModifierData *smd, eSkinErrorFlag *r_
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, origmesh);
BM_mesh_free(bm);
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
skin_set_orig_indices(result);
diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.c b/source/blender/modifiers/intern/MOD_solidify_extrude.c
index 00fa6e24a64..8f9aa86e561 100644
--- a/source/blender/modifiers/intern/MOD_solidify_extrude.c
+++ b/source/blender/modifiers/intern/MOD_solidify_extrude.c
@@ -988,7 +988,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
/* must recalculate normals with vgroups since they can displace unevenly T26888. */
if ((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) || do_rim || dvert) {
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
}
else if (do_shell) {
uint i;
diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
index 5b4716a1a43..f654b69841e 100644
--- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
+++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
@@ -1955,7 +1955,7 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
}
}
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
/* Make edges. */
{
diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c
index ef633494c7b..52d5f3e97ef 100644
--- a/source/blender/modifiers/intern/MOD_triangulate.c
+++ b/source/blender/modifiers/intern/MOD_triangulate.c
@@ -107,7 +107,7 @@ Mesh *triangulate_mesh(Mesh *mesh,
me->flag |= ME_EDGEDRAW | ME_EDGERENDER;
}
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index 5b97d0eb259..d57e92b4b35 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -216,7 +216,6 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob,
* we really need vertexCos here. */
else if (vertexCos) {
BKE_mesh_vert_coords_apply(mesh, vertexCos);
- mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
}
if (use_orco) {
diff --git a/source/blender/modifiers/intern/MOD_weld.c b/source/blender/modifiers/intern/MOD_weld.c
index b1fa2a7d912..503297d5985 100644
--- a/source/blender/modifiers/intern/MOD_weld.c
+++ b/source/blender/modifiers/intern/MOD_weld.c
@@ -1979,8 +1979,7 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
BLI_assert(loop_cur == result_nloops);
/* is this needed? */
- /* recalculate normals */
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
weld_mesh_context_free(&weld_mesh);
}
diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c
index e188a61e975..706960182cf 100644
--- a/source/blender/modifiers/intern/MOD_wireframe.c
+++ b/source/blender/modifiers/intern/MOD_wireframe.c
@@ -109,7 +109,7 @@ static Mesh *WireframeModifier_do(WireframeModifierData *wmd, Object *ob, Mesh *
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
BM_mesh_free(bm);
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
return result;
}
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 614be1d7229..b741461f820 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -141,6 +141,9 @@ set(SRC
function/nodes/node_fn_random_float.cc
function/node_function_util.cc
+ geometry/nodes/legacy/node_geo_material_assign.cc
+ geometry/nodes/legacy/node_geo_select_by_material.cc
+
geometry/nodes/node_geo_align_rotation_to_vector.cc
geometry/nodes/node_geo_attribute_capture.cc
geometry/nodes/node_geo_attribute_clamp.cc
@@ -195,6 +198,7 @@ set(SRC
geometry/nodes/node_geo_join_geometry.cc
geometry/nodes/node_geo_material_assign.cc
geometry/nodes/node_geo_material_replace.cc
+ geometry/nodes/node_geo_material_selection.cc
geometry/nodes/node_geo_mesh_primitive_circle.cc
geometry/nodes/node_geo_mesh_primitive_cone.cc
geometry/nodes/node_geo_mesh_primitive_cube.cc
@@ -214,7 +218,6 @@ set(SRC
geometry/nodes/node_geo_point_translate.cc
geometry/nodes/node_geo_points_to_volume.cc
geometry/nodes/node_geo_raycast.cc
- geometry/nodes/node_geo_select_by_material.cc
geometry/nodes/node_geo_separate_components.cc
geometry/nodes/node_geo_set_position.cc
geometry/nodes/node_geo_subdivision_surface.cc
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index e9fb4ad123c..a713da45f0b 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -29,6 +29,9 @@ void register_node_tree_type_geo(void);
void register_node_type_geo_group(void);
void register_node_type_geo_custom_group(bNodeType *ntype);
+void register_node_type_geo_legacy_material_assign(void);
+void register_node_type_geo_legacy_select_by_material(void);
+
void register_node_type_geo_align_rotation_to_vector(void);
void register_node_type_geo_attribute_clamp(void);
void register_node_type_geo_attribute_color_ramp(void);
@@ -80,6 +83,7 @@ void register_node_type_geo_is_viewport(void);
void register_node_type_geo_join_geometry(void);
void register_node_type_geo_material_assign(void);
void register_node_type_geo_material_replace(void);
+void register_node_type_geo_material_selection(void);
void register_node_type_geo_mesh_primitive_circle(void);
void register_node_type_geo_mesh_primitive_cone(void);
void register_node_type_geo_mesh_primitive_cube(void);
@@ -101,7 +105,6 @@ void register_node_type_geo_points_to_volume(void);
void register_node_type_geo_raycast(void);
void register_node_type_geo_sample_texture(void);
void register_node_type_geo_select_by_handle_type(void);
-void register_node_type_geo_select_by_material(void);
void register_node_type_geo_separate_components(void);
void register_node_type_geo_set_position(void);
void register_node_type_geo_subdivision_surface(void);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 215dca63fa3..51d59821d3c 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -332,7 +332,9 @@ DefNode(GeometryNode, GEO_NODE_INPUT_NORMAL, 0, "INPUT_NORMAL", InputNormal, "No
DefNode(GeometryNode, GEO_NODE_INPUT_POSITION, 0, "POSITION", InputPosition, "Position", "")
DefNode(GeometryNode, GEO_NODE_IS_VIEWPORT, 0, "IS_VIEWPORT", IsViewport, "Is Viewport", "")
DefNode(GeometryNode, GEO_NODE_JOIN_GEOMETRY, 0, "JOIN_GEOMETRY", JoinGeometry, "Join Geometry", "")
+DefNode(GeometryNode, GEO_NODE_MATERIAL_ASSIGN, 0, "MATERIAL_ASSIGN", MaterialAssign, "Material Assign", "")
DefNode(GeometryNode, GEO_NODE_MATERIAL_REPLACE, 0, "MATERIAL_REPLACE", MaterialReplace, "Material Replace", "")
+DefNode(GeometryNode, GEO_NODE_MATERIAL_SELECTION, 0, "MATERIAL_SELECTION", MaterialSelection, "Material Selection", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CIRCLE, def_geo_mesh_circle, "MESH_PRIMITIVE_CIRCLE", MeshCircle, "Mesh Circle", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CONE, def_geo_mesh_cone, "MESH_PRIMITIVE_CONE", MeshCone, "Cone", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CUBE, 0, "MESH_PRIMITIVE_CUBE", MeshCube, "Cube", "")
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_material_assign.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_material_assign.cc
new file mode 100644
index 00000000000..7d3481c1067
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_material_assign.cc
@@ -0,0 +1,95 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_geometry_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_material.h"
+
+namespace blender::nodes {
+
+static void geo_node_legacy_material_assign_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>("Geometry");
+ b.add_input<decl::Material>("Material").hide_label(true);
+ b.add_input<decl::String>("Selection");
+ b.add_output<decl::Geometry>("Geometry");
+}
+
+static void assign_material_to_faces(Mesh &mesh, const VArray<bool> &face_mask, Material *material)
+{
+ int new_material_index = -1;
+ for (const int i : IndexRange(mesh.totcol)) {
+ Material *other_material = mesh.mat[i];
+ if (other_material == material) {
+ new_material_index = i;
+ break;
+ }
+ }
+ if (new_material_index == -1) {
+ /* Append a new material index. */
+ new_material_index = mesh.totcol;
+ BKE_id_material_eval_assign(&mesh.id, new_material_index + 1, material);
+ }
+
+ mesh.mpoly = (MPoly *)CustomData_duplicate_referenced_layer(&mesh.pdata, CD_MPOLY, mesh.totpoly);
+ for (const int i : IndexRange(mesh.totpoly)) {
+ if (face_mask[i]) {
+ MPoly &poly = mesh.mpoly[i];
+ poly.mat_nr = new_material_index;
+ }
+ }
+}
+
+static void geo_node_legacy_material_assign_exec(GeoNodeExecParams params)
+{
+ Material *material = params.extract_input<Material *>("Material");
+ const std::string mask_name = params.extract_input<std::string>("Selection");
+
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+
+ geometry_set = geometry_set_realize_instances(geometry_set);
+
+ if (geometry_set.has<MeshComponent>()) {
+ MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
+ Mesh *mesh = mesh_component.get_for_write();
+ if (mesh != nullptr) {
+ GVArray_Typed<bool> face_mask = mesh_component.attribute_get_for_read<bool>(
+ mask_name, ATTR_DOMAIN_FACE, true);
+ assign_material_to_faces(*mesh, face_mask, material);
+ }
+ }
+
+ params.set_output("Geometry", std::move(geometry_set));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_legacy_material_assign()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_LEGACY_MATERIAL_ASSIGN, "Material Assign", NODE_CLASS_GEOMETRY, 0);
+ ntype.declare = blender::nodes::geo_node_legacy_material_assign_declare;
+ ntype.geometry_node_execute = blender::nodes::geo_node_legacy_material_assign_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_select_by_material.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_select_by_material.cc
index 1d1b9712fe0..eabdd2bcd5a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_select_by_material.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_select_by_material.cc
@@ -28,7 +28,7 @@
namespace blender::nodes {
-static void geo_node_select_by_material_declare(NodeDeclarationBuilder &b)
+static void geo_node_legacy_select_by_material_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Material>("Material").hide_label();
@@ -54,7 +54,7 @@ static void select_mesh_by_material(const Mesh &mesh,
});
}
-static void geo_node_select_by_material_exec(GeoNodeExecParams params)
+static void geo_node_legacy_select_by_material_exec(GeoNodeExecParams params)
{
Material *material = params.extract_input<Material *>("Material");
const std::string selection_name = params.extract_input<std::string>("Selection");
@@ -80,13 +80,13 @@ static void geo_node_select_by_material_exec(GeoNodeExecParams params)
} // namespace blender::nodes
-void register_node_type_geo_select_by_material()
+void register_node_type_geo_legacy_select_by_material()
{
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_SELECT_BY_MATERIAL, "Select by Material", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_select_by_material_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_select_by_material_exec;
+ ntype.declare = blender::nodes::geo_node_legacy_select_by_material_declare;
+ ntype.geometry_node_execute = blender::nodes::geo_node_legacy_select_by_material_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
index 169a169bb1c..0803d43e5c3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
@@ -41,7 +41,7 @@ static std::unique_ptr<CurveEval> create_spiral_curve(const float rotations,
std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
- const int totalpoints = resolution * rotations;
+ const int totalpoints = std::max(int(resolution * rotations), 1);
const float delta_radius = (end_radius - start_radius) / (float)totalpoints;
float radius = start_radius;
const float delta_height = height / (float)totalpoints;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
index 2cb75eda202..32bcbe2c608 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
@@ -29,31 +29,6 @@ static void geo_node_curve_reverse_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>("Curve");
}
-/**
- * Reverse the data in a MutableSpan object.
- */
-template<typename T> static void reverse_data(MutableSpan<T> r_data)
-{
- const int size = r_data.size();
- for (const int i : IndexRange(size / 2)) {
- std::swap(r_data[size - 1 - i], r_data[i]);
- }
-}
-
-/**
- * Reverse and Swap the data between 2 MutableSpans.
- */
-template<typename T> static void reverse_data(MutableSpan<T> left, MutableSpan<T> right)
-{
- BLI_assert(left.size() == right.size());
- const int size = left.size();
-
- for (const int i : IndexRange(size / 2 + size % 2)) {
- std::swap(left[i], right[size - 1 - i]);
- std::swap(right[i], left[size - 1 - i]);
- }
-}
-
static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
@@ -74,42 +49,9 @@ static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
for (const int i : range) {
- if (!selection[i]) {
- continue;
- }
-
- reverse_data<float3>(splines[i]->positions());
- reverse_data<float>(splines[i]->radii());
- reverse_data<float>(splines[i]->tilts());
-
- splines[i]->attributes.foreach_attribute(
- [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
- std::optional<blender::fn::GMutableSpan> output_attribute =
- splines[i]->attributes.get_for_write(attribute_id);
- if (!output_attribute) {
- BLI_assert_unreachable();
- return false;
- }
- attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
- using T = decltype(dummy);
- reverse_data(output_attribute->typed<T>());
- });
- return true;
- },
- ATTR_DOMAIN_POINT);
-
- /* Deal with extra info on derived types. */
- if (BezierSpline *spline = dynamic_cast<BezierSpline *>(splines[i].get())) {
- reverse_data<BezierSpline::HandleType>(spline->handle_types_left());
- reverse_data<BezierSpline::HandleType>(spline->handle_types_right());
- reverse_data<float3>(spline->handle_positions_left(), spline->handle_positions_right());
+ if (selection[i]) {
+ splines[i]->reverse();
}
- else if (NURBSpline *spline = dynamic_cast<NURBSpline *>(splines[i].get())) {
- reverse_data<float>(spline->weights());
- }
- /* Nothing to do for poly splines. */
-
- splines[i]->mark_cache_invalid();
}
});
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
index b0c763c7d06..f46440fd949 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
@@ -39,6 +39,20 @@ static void geo_node_curve_to_mesh_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>("Mesh");
}
+/** Information about the creation of one curve spline and profile spline combination. */
+struct ResultInfo {
+ const Spline &spline;
+ const Spline &profile;
+ int vert_offset;
+ int edge_offset;
+ int loop_offset;
+ int poly_offset;
+ int spline_vert_len;
+ int spline_edge_len;
+ int profile_vert_len;
+ int profile_edge_len;
+};
+
static void vert_extrude_to_mesh_data(const Spline &spline,
const float3 profile_vert,
MutableSpan<MVert> r_verts,
@@ -75,44 +89,33 @@ static void mark_edges_sharp(MutableSpan<MEdge> edges)
}
}
-static void spline_extrude_to_mesh_data(const Spline &spline,
- const Spline &profile_spline,
- const int vert_offset,
- const int edge_offset,
- const int loop_offset,
- const int poly_offset,
+static void spline_extrude_to_mesh_data(const ResultInfo &info,
MutableSpan<MVert> r_verts,
MutableSpan<MEdge> r_edges,
MutableSpan<MLoop> r_loops,
MutableSpan<MPoly> r_polys)
{
- const int spline_vert_len = spline.evaluated_points_size();
- const int spline_edge_len = spline.evaluated_edges_size();
- const int profile_vert_len = profile_spline.evaluated_points_size();
- const int profile_edge_len = profile_spline.evaluated_edges_size();
- if (spline_vert_len == 0) {
- return;
- }
-
- if (profile_vert_len == 1) {
+ const Spline &spline = info.spline;
+ const Spline &profile = info.profile;
+ if (info.profile_vert_len == 1) {
vert_extrude_to_mesh_data(spline,
- profile_spline.evaluated_positions()[0],
+ profile.evaluated_positions()[0],
r_verts,
r_edges,
- vert_offset,
- edge_offset);
+ info.vert_offset,
+ info.edge_offset);
return;
}
/* Add the edges running along the length of the curve, starting at each profile vertex. */
- const int spline_edges_start = edge_offset;
- for (const int i_profile : IndexRange(profile_vert_len)) {
- const int profile_edge_offset = spline_edges_start + i_profile * spline_edge_len;
- for (const int i_ring : IndexRange(spline_edge_len)) {
- const int i_next_ring = (i_ring == spline_vert_len - 1) ? 0 : i_ring + 1;
+ const int spline_edges_start = info.edge_offset;
+ for (const int i_profile : IndexRange(info.profile_vert_len)) {
+ const int profile_edge_offset = spline_edges_start + i_profile * info.spline_edge_len;
+ for (const int i_ring : IndexRange(info.spline_edge_len)) {
+ const int i_next_ring = (i_ring == info.spline_vert_len - 1) ? 0 : i_ring + 1;
- const int ring_vert_offset = vert_offset + profile_vert_len * i_ring;
- const int next_ring_vert_offset = vert_offset + profile_vert_len * i_next_ring;
+ const int ring_vert_offset = info.vert_offset + info.profile_vert_len * i_ring;
+ const int next_ring_vert_offset = info.vert_offset + info.profile_vert_len * i_next_ring;
MEdge &edge = r_edges[profile_edge_offset + i_ring];
edge.v1 = ring_vert_offset + i_profile;
@@ -122,13 +125,14 @@ static void spline_extrude_to_mesh_data(const Spline &spline,
}
/* Add the edges running along each profile ring. */
- const int profile_edges_start = spline_edges_start + profile_vert_len * spline_edge_len;
- for (const int i_ring : IndexRange(spline_vert_len)) {
- const int ring_vert_offset = vert_offset + profile_vert_len * i_ring;
+ const int profile_edges_start = spline_edges_start +
+ info.profile_vert_len * info.spline_edge_len;
+ for (const int i_ring : IndexRange(info.spline_vert_len)) {
+ const int ring_vert_offset = info.vert_offset + info.profile_vert_len * i_ring;
- const int ring_edge_offset = profile_edges_start + i_ring * profile_edge_len;
- for (const int i_profile : IndexRange(profile_edge_len)) {
- const int i_next_profile = (i_profile == profile_vert_len - 1) ? 0 : i_profile + 1;
+ const int ring_edge_offset = profile_edges_start + i_ring * info.profile_edge_len;
+ for (const int i_profile : IndexRange(info.profile_edge_len)) {
+ const int i_next_profile = (i_profile == info.profile_vert_len - 1) ? 0 : i_profile + 1;
MEdge &edge = r_edges[ring_edge_offset + i_profile];
edge.v1 = ring_vert_offset + i_profile;
@@ -138,24 +142,25 @@ static void spline_extrude_to_mesh_data(const Spline &spline,
}
/* Calculate poly and corner indices. */
- for (const int i_ring : IndexRange(spline_edge_len)) {
- const int i_next_ring = (i_ring == spline_vert_len - 1) ? 0 : i_ring + 1;
+ for (const int i_ring : IndexRange(info.spline_edge_len)) {
+ const int i_next_ring = (i_ring == info.spline_vert_len - 1) ? 0 : i_ring + 1;
- const int ring_vert_offset = vert_offset + profile_vert_len * i_ring;
- const int next_ring_vert_offset = vert_offset + profile_vert_len * i_next_ring;
+ const int ring_vert_offset = info.vert_offset + info.profile_vert_len * i_ring;
+ const int next_ring_vert_offset = info.vert_offset + info.profile_vert_len * i_next_ring;
- const int ring_edge_start = profile_edges_start + profile_edge_len * i_ring;
- const int next_ring_edge_offset = profile_edges_start + profile_edge_len * i_next_ring;
+ const int ring_edge_start = profile_edges_start + info.profile_edge_len * i_ring;
+ const int next_ring_edge_offset = profile_edges_start + info.profile_edge_len * i_next_ring;
- const int ring_poly_offset = poly_offset + i_ring * profile_edge_len;
- const int ring_loop_offset = loop_offset + i_ring * profile_edge_len * 4;
+ const int ring_poly_offset = info.poly_offset + i_ring * info.profile_edge_len;
+ const int ring_loop_offset = info.loop_offset + i_ring * info.profile_edge_len * 4;
- for (const int i_profile : IndexRange(profile_edge_len)) {
+ for (const int i_profile : IndexRange(info.profile_edge_len)) {
const int ring_segment_loop_offset = ring_loop_offset + i_profile * 4;
- const int i_next_profile = (i_profile == profile_vert_len - 1) ? 0 : i_profile + 1;
+ const int i_next_profile = (i_profile == info.profile_vert_len - 1) ? 0 : i_profile + 1;
- const int spline_edge_start = spline_edges_start + spline_edge_len * i_profile;
- const int next_spline_edge_start = spline_edges_start + spline_edge_len * i_next_profile;
+ const int spline_edge_start = spline_edges_start + info.spline_edge_len * i_profile;
+ const int next_spline_edge_start = spline_edges_start +
+ info.spline_edge_len * i_next_profile;
MPoly &poly = r_polys[ring_poly_offset + i_profile];
poly.loopstart = ring_segment_loop_offset;
@@ -181,29 +186,30 @@ static void spline_extrude_to_mesh_data(const Spline &spline,
Span<float3> positions = spline.evaluated_positions();
Span<float3> tangents = spline.evaluated_tangents();
Span<float3> normals = spline.evaluated_normals();
- Span<float3> profile_positions = profile_spline.evaluated_positions();
+ Span<float3> profile_positions = profile.evaluated_positions();
GVArray_Typed<float> radii = spline.interpolate_to_evaluated(spline.radii());
- for (const int i_ring : IndexRange(spline_vert_len)) {
+ for (const int i_ring : IndexRange(info.spline_vert_len)) {
float4x4 point_matrix = float4x4::from_normalized_axis_data(
positions[i_ring], normals[i_ring], tangents[i_ring]);
point_matrix.apply_scale(radii[i_ring]);
- const int ring_vert_start = vert_offset + i_ring * profile_vert_len;
- for (const int i_profile : IndexRange(profile_vert_len)) {
+ const int ring_vert_start = info.vert_offset + i_ring * info.profile_vert_len;
+ for (const int i_profile : IndexRange(info.profile_vert_len)) {
MVert &vert = r_verts[ring_vert_start + i_profile];
copy_v3_v3(vert.co, point_matrix * profile_positions[i_profile]);
}
}
/* Mark edge loops from sharp vector control points sharp. */
- if (profile_spline.type() == Spline::Type::Bezier) {
- const BezierSpline &bezier_spline = static_cast<const BezierSpline &>(profile_spline);
+ if (profile.type() == Spline::Type::Bezier) {
+ const BezierSpline &bezier_spline = static_cast<const BezierSpline &>(profile);
Span<int> control_point_offsets = bezier_spline.control_point_offsets();
for (const int i : IndexRange(bezier_spline.size())) {
if (bezier_spline.point_is_sharp(i)) {
- mark_edges_sharp(r_edges.slice(
- spline_edges_start + spline_edge_len * control_point_offsets[i], spline_edge_len));
+ mark_edges_sharp(
+ r_edges.slice(spline_edges_start + info.spline_edge_len * control_point_offsets[i],
+ info.spline_edge_len));
}
}
}
@@ -272,6 +278,372 @@ static ResultOffsets calculate_result_offsets(Span<SplinePtr> profiles, Span<Spl
return {std::move(vert), std::move(edge), std::move(loop), std::move(poly)};
}
+static AttributeDomain get_result_attribute_domain(const MeshComponent &component,
+ const AttributeIDRef &attribute_id)
+{
+ /* Only use a different domain if it is builtin and must only exist on one domain. */
+ if (!component.attribute_is_builtin(attribute_id)) {
+ return ATTR_DOMAIN_POINT;
+ }
+
+ std::optional<AttributeMetaData> meta_data = component.attribute_get_meta_data(attribute_id);
+ if (!meta_data) {
+ /* This function has to return something in this case, but it shouldn't be used,
+ * so return an output that will assert later if the code attempts to handle it. */
+ return ATTR_DOMAIN_AUTO;
+ }
+
+ return meta_data->domain;
+}
+
+/**
+ * The data stored in the attribute and its domain from #OutputAttribute, to avoid calling
+ * `as_span()` for every single profile and curve spline combination, and for readability.
+ */
+struct ResultAttributeData {
+ GMutableSpan data;
+ AttributeDomain domain;
+};
+
+static std::optional<ResultAttributeData> create_attribute_and_get_span(
+ MeshComponent &component,
+ const AttributeIDRef &attribute_id,
+ AttributeMetaData meta_data,
+ Vector<OutputAttribute> &r_attributes)
+{
+ const AttributeDomain domain = get_result_attribute_domain(component, attribute_id);
+ OutputAttribute attribute = component.attribute_try_get_for_output_only(
+ attribute_id, domain, meta_data.data_type);
+ if (!attribute) {
+ return std::nullopt;
+ }
+
+ GMutableSpan span = attribute.as_span();
+ r_attributes.append(std::move(attribute));
+ return std::make_optional<ResultAttributeData>({span, domain});
+}
+
+/**
+ * Store the references to the attribute data from the curve and profile inputs. Here we rely on
+ * the invariants of the storage of curve attributes, that the order will be consistent between
+ * splines, and all splines will have the same attributes.
+ */
+struct ResultAttributes {
+ /**
+ * Result attributes on the mesh corresponding to each attribute on the curve input, in the same
+ * order. The data is optional only in case the attribute does not exist on the mesh for some
+ * reason, like "shade_smooth" when the result has no faces.
+ */
+ Vector<std::optional<ResultAttributeData>> curve_point_attributes;
+ Vector<std::optional<ResultAttributeData>> curve_spline_attributes;
+
+ /**
+ * Result attributes corresponding the attributes on the profile input, in the same order. The
+ * attributes are optional in case the attribute names correspond to a namse used by the curve
+ * input, in which case the curve input attributes take precedence.
+ */
+ Vector<std::optional<ResultAttributeData>> profile_point_attributes;
+ Vector<std::optional<ResultAttributeData>> profile_spline_attributes;
+
+ /**
+ * Because some builtin attributes are not stored contiguously, and the curve inputs might have
+ * attributes with those names, it's necessary to keep OutputAttributes around to give access to
+ * the result data in a contiguous array.
+ */
+ Vector<OutputAttribute> attributes;
+};
+static ResultAttributes create_result_attributes(const CurveEval &curve,
+ const CurveEval &profile,
+ Mesh &mesh)
+{
+ MeshComponent mesh_component;
+ mesh_component.replace(&mesh, GeometryOwnershipType::Editable);
+ Set<AttributeIDRef> curve_attributes;
+
+ /* In order to prefer attributes on the main curve input when there are name collisions, first
+ * check the attributes on the curve, then add attributes on the profile that are not also on the
+ * main curve input. */
+ ResultAttributes result;
+ curve.splines().first()->attributes.foreach_attribute(
+ [&](const AttributeIDRef &id, const AttributeMetaData &meta_data) {
+ curve_attributes.add_new(id);
+ result.curve_point_attributes.append(
+ create_attribute_and_get_span(mesh_component, id, meta_data, result.attributes));
+ return true;
+ },
+ ATTR_DOMAIN_POINT);
+ curve.attributes.foreach_attribute(
+ [&](const AttributeIDRef &id, const AttributeMetaData &meta_data) {
+ curve_attributes.add_new(id);
+ result.curve_spline_attributes.append(
+ create_attribute_and_get_span(mesh_component, id, meta_data, result.attributes));
+ return true;
+ },
+ ATTR_DOMAIN_CURVE);
+ profile.splines().first()->attributes.foreach_attribute(
+ [&](const AttributeIDRef &id, const AttributeMetaData &meta_data) {
+ if (curve_attributes.contains(id)) {
+ result.profile_point_attributes.append({});
+ }
+ else {
+ result.profile_point_attributes.append(
+ create_attribute_and_get_span(mesh_component, id, meta_data, result.attributes));
+ }
+ return true;
+ },
+ ATTR_DOMAIN_POINT);
+ profile.attributes.foreach_attribute(
+ [&](const AttributeIDRef &id, const AttributeMetaData &meta_data) {
+ if (curve_attributes.contains(id)) {
+ result.profile_spline_attributes.append({});
+ }
+ else {
+ result.profile_spline_attributes.append(
+ create_attribute_and_get_span(mesh_component, id, meta_data, result.attributes));
+ }
+ return true;
+ },
+ ATTR_DOMAIN_CURVE);
+
+ return result;
+}
+
+template<typename T>
+static void copy_curve_point_data_to_mesh_verts(const Span<T> src,
+ const ResultInfo &info,
+ MutableSpan<T> dst)
+{
+ for (const int i_ring : IndexRange(info.spline_vert_len)) {
+ const int ring_vert_start = info.vert_offset + i_ring * info.profile_vert_len;
+ dst.slice(ring_vert_start, info.profile_vert_len).fill(src[i_ring]);
+ }
+}
+
+template<typename T>
+static void copy_curve_point_data_to_mesh_edges(const Span<T> src,
+ const ResultInfo &info,
+ MutableSpan<T> dst)
+{
+ const int edges_start = info.edge_offset + info.profile_vert_len * info.spline_edge_len;
+ for (const int i_ring : IndexRange(info.spline_vert_len)) {
+ const int ring_edge_start = edges_start + info.profile_edge_len * i_ring;
+ dst.slice(ring_edge_start, info.profile_edge_len).fill(src[i_ring]);
+ }
+}
+
+template<typename T>
+static void copy_curve_point_data_to_mesh_faces(const Span<T> src,
+ const ResultInfo &info,
+ MutableSpan<T> dst)
+{
+ for (const int i_ring : IndexRange(info.spline_edge_len)) {
+ const int ring_face_start = info.poly_offset + info.profile_edge_len * i_ring;
+ dst.slice(ring_face_start, info.profile_edge_len).fill(src[i_ring]);
+ }
+}
+
+static void copy_curve_point_attribute_to_mesh(const GSpan src,
+ const ResultInfo &info,
+ ResultAttributeData &dst)
+{
+ GVArrayPtr interpolated_gvarray = info.spline.interpolate_to_evaluated(src);
+ GSpan interpolated = interpolated_gvarray->get_internal_span();
+
+ attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ switch (dst.domain) {
+ case ATTR_DOMAIN_POINT:
+ copy_curve_point_data_to_mesh_verts(interpolated.typed<T>(), info, dst.data.typed<T>());
+ break;
+ case ATTR_DOMAIN_EDGE:
+ copy_curve_point_data_to_mesh_edges(interpolated.typed<T>(), info, dst.data.typed<T>());
+ break;
+ case ATTR_DOMAIN_FACE:
+ copy_curve_point_data_to_mesh_faces(interpolated.typed<T>(), info, dst.data.typed<T>());
+ break;
+ case ATTR_DOMAIN_CORNER:
+ /* Unsupported for now, since there are no builtin attributes to convert into. */
+ break;
+ default:
+ BLI_assert_unreachable();
+ break;
+ }
+ });
+}
+
+template<typename T>
+static void copy_profile_point_data_to_mesh_verts(const Span<T> src,
+ const ResultInfo &info,
+ MutableSpan<T> dst)
+{
+ for (const int i_ring : IndexRange(info.spline_vert_len)) {
+ const int profile_vert_start = info.vert_offset + i_ring * info.profile_vert_len;
+ for (const int i_profile : IndexRange(info.profile_vert_len)) {
+ dst[profile_vert_start + i_profile] = src[i_profile];
+ }
+ }
+}
+
+template<typename T>
+static void copy_profile_point_data_to_mesh_edges(const Span<T> src,
+ const ResultInfo &info,
+ MutableSpan<T> dst)
+{
+ for (const int i_profile : IndexRange(info.profile_vert_len)) {
+ const int profile_edge_offset = info.edge_offset + i_profile * info.spline_edge_len;
+ dst.slice(profile_edge_offset, info.spline_edge_len).fill(src[i_profile]);
+ }
+}
+
+template<typename T>
+static void copy_profile_point_data_to_mesh_faces(const Span<T> src,
+ const ResultInfo &info,
+ MutableSpan<T> dst)
+{
+ for (const int i_ring : IndexRange(info.spline_edge_len)) {
+ const int profile_face_start = info.poly_offset + i_ring * info.profile_edge_len;
+ for (const int i_profile : IndexRange(info.profile_edge_len)) {
+ dst[profile_face_start + i_profile] = src[i_profile];
+ }
+ }
+}
+
+static void copy_profile_point_attribute_to_mesh(const GSpan src,
+ const ResultInfo &info,
+ ResultAttributeData &dst)
+{
+ GVArrayPtr interpolated_gvarray = info.profile.interpolate_to_evaluated(src);
+ GSpan interpolated = interpolated_gvarray->get_internal_span();
+
+ attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ switch (dst.domain) {
+ case ATTR_DOMAIN_POINT:
+ copy_profile_point_data_to_mesh_verts(interpolated.typed<T>(), info, dst.data.typed<T>());
+ break;
+ case ATTR_DOMAIN_EDGE:
+ copy_profile_point_data_to_mesh_edges(interpolated.typed<T>(), info, dst.data.typed<T>());
+ break;
+ case ATTR_DOMAIN_FACE:
+ copy_profile_point_data_to_mesh_faces(interpolated.typed<T>(), info, dst.data.typed<T>());
+ break;
+ case ATTR_DOMAIN_CORNER:
+ /* Unsupported for now, since there are no builtin attributes to convert into. */
+ break;
+ default:
+ BLI_assert_unreachable();
+ break;
+ }
+ });
+}
+
+static void copy_point_domain_attributes_to_mesh(const ResultInfo &info,
+ ResultAttributes &attributes)
+{
+ if (!attributes.curve_point_attributes.is_empty()) {
+ int i = 0;
+ info.spline.attributes.foreach_attribute(
+ [&](const AttributeIDRef &id, const AttributeMetaData &UNUSED(meta_data)) {
+ if (attributes.curve_point_attributes[i]) {
+ copy_curve_point_attribute_to_mesh(*info.spline.attributes.get_for_read(id),
+ info,
+ *attributes.curve_point_attributes[i]);
+ }
+ i++;
+ return true;
+ },
+ ATTR_DOMAIN_POINT);
+ }
+ if (!attributes.profile_point_attributes.is_empty()) {
+ int i = 0;
+ info.profile.attributes.foreach_attribute(
+ [&](const AttributeIDRef &id, const AttributeMetaData &UNUSED(meta_data)) {
+ if (attributes.profile_point_attributes[i]) {
+ copy_profile_point_attribute_to_mesh(*info.profile.attributes.get_for_read(id),
+ info,
+ *attributes.profile_point_attributes[i]);
+ }
+ i++;
+ return true;
+ },
+ ATTR_DOMAIN_POINT);
+ }
+}
+
+template<typename T>
+static void copy_spline_data_to_mesh(Span<T> src, Span<int> offsets, MutableSpan<T> dst)
+{
+ for (const int i : IndexRange(src.size())) {
+ dst.slice(offsets[i], offsets[i + 1] - offsets[i]).fill(src[i]);
+ }
+}
+
+/**
+ * Since the offsets for each combination of curve and profile spline are stored for every mesh
+ * domain, and this just needs to fill the chunks corresponding to each combination, we can use
+ * the same function for all mesh domains.
+ */
+static void copy_spline_attribute_to_mesh(const GSpan src,
+ const ResultOffsets &offsets,
+ ResultAttributeData &dst_attribute)
+{
+ attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ switch (dst_attribute.domain) {
+ case ATTR_DOMAIN_POINT:
+ copy_spline_data_to_mesh(src.typed<T>(), offsets.vert, dst_attribute.data.typed<T>());
+ break;
+ case ATTR_DOMAIN_EDGE:
+ copy_spline_data_to_mesh(src.typed<T>(), offsets.edge, dst_attribute.data.typed<T>());
+ break;
+ case ATTR_DOMAIN_FACE:
+ copy_spline_data_to_mesh(src.typed<T>(), offsets.poly, dst_attribute.data.typed<T>());
+ break;
+ case ATTR_DOMAIN_CORNER:
+ copy_spline_data_to_mesh(src.typed<T>(), offsets.loop, dst_attribute.data.typed<T>());
+ break;
+ default:
+ BLI_assert_unreachable();
+ break;
+ }
+ });
+}
+
+static void copy_spline_domain_attributes_to_mesh(const CurveEval &curve,
+ const CurveEval &profile,
+ const ResultOffsets &offsets,
+ ResultAttributes &attributes)
+{
+ if (!attributes.curve_spline_attributes.is_empty()) {
+ int i = 0;
+ curve.attributes.foreach_attribute(
+ [&](const AttributeIDRef &id, const AttributeMetaData &UNUSED(meta_data)) {
+ if (attributes.curve_spline_attributes[i]) {
+ copy_spline_attribute_to_mesh(*curve.attributes.get_for_read(id),
+ offsets,
+ *attributes.curve_spline_attributes[i]);
+ }
+ i++;
+ return true;
+ },
+ ATTR_DOMAIN_CURVE);
+ }
+ if (!attributes.profile_spline_attributes.is_empty()) {
+ int i = 0;
+ profile.attributes.foreach_attribute(
+ [&](const AttributeIDRef &id, const AttributeMetaData &UNUSED(meta_data)) {
+ if (attributes.profile_spline_attributes[i]) {
+ copy_spline_attribute_to_mesh(*profile.attributes.get_for_read(id),
+ offsets,
+ *attributes.profile_spline_attributes[i]);
+ }
+ i++;
+ return true;
+ },
+ ATTR_DOMAIN_CURVE);
+ }
+}
+
/**
* \note Normal calculation is by far the slowest part of calculations relating to the result mesh.
* Although it would be a sensible decision to use the better topology information available while
@@ -294,30 +666,52 @@ static Mesh *curve_to_mesh_calculate(const CurveEval &curve, const CurveEval &pr
BKE_id_material_eval_ensure_default_slot(&mesh->id);
mesh->flag |= ME_AUTOSMOOTH;
mesh->smoothresh = DEG2RADF(180.0f);
- mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
- mesh->runtime.cd_dirty_poly |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(mesh);
+
+ ResultAttributes attributes = create_result_attributes(curve, profile, *mesh);
threading::parallel_for(curves.index_range(), 128, [&](IndexRange curves_range) {
for (const int i_spline : curves_range) {
+ const Spline &spline = *curves[i_spline];
+ if (spline.evaluated_points_size() == 0) {
+ continue;
+ }
const int spline_start_index = i_spline * profiles.size();
threading::parallel_for(profiles.index_range(), 128, [&](IndexRange profiles_range) {
for (const int i_profile : profiles_range) {
+ const Spline &profile = *profiles[i_profile];
const int i_mesh = spline_start_index + i_profile;
- spline_extrude_to_mesh_data(*curves[i_spline],
- *profiles[i_profile],
- offsets.vert[i_mesh],
- offsets.edge[i_mesh],
- offsets.loop[i_mesh],
- offsets.poly[i_mesh],
+ ResultInfo info{
+ spline,
+ profile,
+ offsets.vert[i_mesh],
+ offsets.edge[i_mesh],
+ offsets.loop[i_mesh],
+ offsets.poly[i_mesh],
+ spline.evaluated_points_size(),
+ spline.evaluated_edges_size(),
+ profile.evaluated_points_size(),
+ profile.evaluated_edges_size(),
+ };
+
+ spline_extrude_to_mesh_data(info,
{mesh->mvert, mesh->totvert},
{mesh->medge, mesh->totedge},
{mesh->mloop, mesh->totloop},
{mesh->mpoly, mesh->totpoly});
+
+ copy_point_domain_attributes_to_mesh(info, attributes);
}
});
}
});
+ copy_spline_domain_attributes_to_mesh(curve, profile, offsets, attributes);
+
+ for (OutputAttribute &output_attribute : attributes.attributes) {
+ output_attribute.save();
+ }
+
return mesh;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
index 5845eb357e0..1e2f652cd78 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
@@ -559,7 +559,7 @@ static Mesh *delete_mesh_selection(const Mesh &mesh_in,
mesh_in, *result, vertex_map, edge_map, selected_poly_indices, new_loop_starts);
BKE_mesh_calc_edges_loose(result);
/* Tag to recalculate normals later. */
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
return result;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_assign.cc b/source/blender/nodes/geometry/nodes/node_geo_material_assign.cc
index 9e99ae29b00..43818947272 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_material_assign.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_material_assign.cc
@@ -30,11 +30,11 @@ static void geo_node_material_assign_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Material>("Material").hide_label();
- b.add_input<decl::String>("Selection");
+ b.add_input<decl::Bool>("Selection").default_value(true).hide_value();
b.add_output<decl::Geometry>("Geometry");
}
-static void assign_material_to_faces(Mesh &mesh, const VArray<bool> &face_mask, Material *material)
+static void assign_material_to_faces(Mesh &mesh, const IndexMask selection, Material *material)
{
int new_material_index = -1;
for (const int i : IndexRange(mesh.totcol)) {
@@ -51,18 +51,16 @@ static void assign_material_to_faces(Mesh &mesh, const VArray<bool> &face_mask,
}
mesh.mpoly = (MPoly *)CustomData_duplicate_referenced_layer(&mesh.pdata, CD_MPOLY, mesh.totpoly);
- for (const int i : IndexRange(mesh.totpoly)) {
- if (face_mask[i]) {
- MPoly &poly = mesh.mpoly[i];
- poly.mat_nr = new_material_index;
- }
+ for (const int i : selection) {
+ MPoly &poly = mesh.mpoly[i];
+ poly.mat_nr = new_material_index;
}
}
static void geo_node_material_assign_exec(GeoNodeExecParams params)
{
Material *material = params.extract_input<Material *>("Material");
- const std::string mask_name = params.extract_input<std::string>("Selection");
+ const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
@@ -72,9 +70,15 @@ static void geo_node_material_assign_exec(GeoNodeExecParams params)
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
Mesh *mesh = mesh_component.get_for_write();
if (mesh != nullptr) {
- GVArray_Typed<bool> face_mask = mesh_component.attribute_get_for_read<bool>(
- mask_name, ATTR_DOMAIN_FACE, true);
- assign_material_to_faces(*mesh, face_mask, material);
+
+ GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_FACE};
+
+ fn::FieldEvaluator selection_evaluator{field_context, mesh->totpoly};
+ selection_evaluator.add(selection_field);
+ selection_evaluator.evaluate();
+ const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+
+ assign_material_to_faces(*mesh, selection, material);
}
}
@@ -87,8 +91,7 @@ void register_node_type_geo_material_assign()
{
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_MATERIAL_ASSIGN, "Material Assign", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_MATERIAL_ASSIGN, "Material Assign", NODE_CLASS_GEOMETRY, 0);
ntype.declare = blender::nodes::geo_node_material_assign_declare;
ntype.geometry_node_execute = blender::nodes::geo_node_material_assign_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
new file mode 100644
index 00000000000..22c24e34314
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
@@ -0,0 +1,131 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_geometry_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BLI_task.hh"
+
+#include "BKE_material.h"
+
+namespace blender::nodes {
+
+static void geo_node_material_selection_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Material>("Material").hide_label(true);
+ b.add_output<decl::Bool>("Selection");
+}
+
+static void select_mesh_by_material(const Mesh &mesh,
+ const Material *material,
+ const IndexMask mask,
+ const MutableSpan<bool> r_selection)
+{
+ BLI_assert(mesh.totpoly >= r_selection.size());
+ Vector<int> material_indices;
+ for (const int i : IndexRange(mesh.totcol)) {
+ if (mesh.mat[i] == material) {
+ material_indices.append(i);
+ }
+ }
+ threading::parallel_for(mask.index_range(), 1024, [&](IndexRange range) {
+ for (const int i : range) {
+ const int face_index = mask[i];
+ r_selection[i] = material_indices.contains(mesh.mpoly[face_index].mat_nr);
+ }
+ });
+}
+
+class MaterialSelectionFieldInput final : public fn::FieldInput {
+ Material *material_;
+
+ public:
+ MaterialSelectionFieldInput(Material *material)
+ : fn::FieldInput(CPPType::get<bool>(), "Material Selection"), material_(material)
+ {
+ }
+
+ const GVArray *get_varray_for_context(const fn::FieldContext &context,
+ IndexMask mask,
+ ResourceScope &scope) const final
+ {
+ if (const GeometryComponentFieldContext *geometry_context =
+ dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
+ const GeometryComponent &component = geometry_context->geometry_component();
+ const AttributeDomain domain = geometry_context->domain();
+ if (component.type() != GEO_COMPONENT_TYPE_MESH) {
+ return nullptr;
+ }
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ if (mesh == nullptr) {
+ return nullptr;
+ }
+
+ if (domain == ATTR_DOMAIN_FACE) {
+ Array<bool> selection(mask.min_array_size());
+ select_mesh_by_material(*mesh, material_, mask, selection);
+ return &scope.construct<fn::GVArray_For_ArrayContainer<Array<bool>>>(std::move(selection));
+ }
+
+ Array<bool> selection(mesh->totpoly);
+ select_mesh_by_material(*mesh, material_, IndexMask(mesh->totpoly), selection);
+ GVArrayPtr face_selection = std::make_unique<fn::GVArray_For_ArrayContainer<Array<bool>>>(
+ std::move(selection));
+ GVArrayPtr final_selection = mesh_component.attribute_try_adapt_domain(
+ std::move(face_selection), ATTR_DOMAIN_FACE, domain);
+ return scope.add_value(std::move(final_selection)).get();
+ }
+
+ return nullptr;
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 91619626;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const MaterialSelectionFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void geo_node_material_selection_exec(GeoNodeExecParams params)
+{
+ Material *material = params.extract_input<Material *>("Material");
+ Field<bool> material_field{std::make_shared<MaterialSelectionFieldInput>(material)};
+ params.set_output("Selection", std::move(material_field));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_material_selection()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_MATERIAL_SELECTION, "Material Selection", NODE_CLASS_GEOMETRY, 0);
+ ntype.declare = blender::nodes::geo_node_material_selection_declare;
+ ntype.geometry_node_execute = blender::nodes::geo_node_material_selection_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
index 7ea0465bb43..a1bc061f86e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
@@ -23,8 +23,8 @@ namespace blender::nodes {
static void geo_node_set_position_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::Vector>("Position").is_field();
- b.add_input<decl::Bool>("Selection").default_value(true).is_field();
+ b.add_input<decl::Vector>("Position");
+ b.add_input<decl::Bool>("Selection").default_value(true).hide_value().is_field();
b.add_output<decl::Geometry>("Geometry");
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
index d127f7dc0ba..4541bf3569f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
@@ -37,14 +37,13 @@ static void geo_node_subdivision_surface_layout(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
-#ifndef WITH_OPENSUBDIV
- UNUSED_VARS(ptr);
- uiItemL(layout, IFACE_("Disabled, built without OpenSubdiv"), ICON_ERROR);
-#else
+#ifdef WITH_OPENSUBDIV
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "uv_smooth", 0, nullptr, ICON_NONE);
uiItemR(layout, ptr, "boundary_smooth", 0, nullptr, ICON_NONE);
+#else
+ UNUSED_VARS(layout, ptr);
#endif
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
index d7423aa6d32..d5eb067cad0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
@@ -69,8 +69,7 @@ void transform_mesh(Mesh *mesh,
else {
const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale);
BKE_mesh_transform(mesh, matrix.values, false);
- mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
- mesh->runtime.cd_dirty_poly |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(mesh);
}
}
diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c
index 4296474c011..8dc0d2fb857 100644
--- a/source/blender/python/generic/idprop_py_api.c
+++ b/source/blender/python/generic/idprop_py_api.c
@@ -533,6 +533,7 @@ static IDProperty *idp_from_PySequence_Fast(const char *name, PyObject *ob)
for (i = 0; i < val.array.len; i++) {
item = ob_seq_fast_items[i];
if (((prop_data[i] = PyFloat_AsDouble(item)) == -1.0) && PyErr_Occurred()) {
+ IDP_FreeProperty(prop);
return NULL;
}
}
@@ -545,6 +546,7 @@ static IDProperty *idp_from_PySequence_Fast(const char *name, PyObject *ob)
for (i = 0; i < val.array.len; i++) {
item = ob_seq_fast_items[i];
if (((prop_data[i] = PyC_Long_AsI32(item)) == -1) && PyErr_Occurred()) {
+ IDP_FreeProperty(prop);
return NULL;
}
}
@@ -555,6 +557,7 @@ static IDProperty *idp_from_PySequence_Fast(const char *name, PyObject *ob)
for (i = 0; i < val.array.len; i++) {
item = ob_seq_fast_items[i];
if (BPy_IDProperty_Map_ValidateAndCreate(NULL, prop, item) == false) {
+ IDP_FreeProperty(prop);
return NULL;
}
}
diff --git a/source/blender/render/intern/render_result.c b/source/blender/render/intern/render_result.c
index c29ab342ed7..6cb6aabe885 100644
--- a/source/blender/render/intern/render_result.c
+++ b/source/blender/render/intern/render_result.c
@@ -250,6 +250,9 @@ RenderPass *render_layer_add_pass(RenderResult *rr,
BLI_addtail(&rl->passes, rpass);
+ /* The result contains non-allocated pass now, so tag it as such. */
+ rr->passes_allocated = false;
+
return rpass;
}
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 7ecbcad886d..189a231616e 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -472,6 +472,12 @@ int WM_operator_call_py(struct bContext *C,
struct ReportList *reports,
const bool is_undo);
+void WM_operator_name_call_ptr_with_depends_on_cursor(struct bContext *C,
+ wmOperatorType *ot,
+ short opcontext,
+ PointerRNA *properties,
+ const char *drawstr);
+
/* Used for keymap and macro items. */
void WM_operator_properties_alloc(struct PointerRNA **ptr,
struct IDProperty **properties,
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index c1730957432..df6dc3af3cb 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -184,6 +184,17 @@ enum {
OPTYPE_LOCK_BYPASS = (1 << 9),
/** Special type of undo which doesn't store itself multiple times. */
OPTYPE_UNDO_GROUPED = (1 << 10),
+
+ /**
+ * Depends on the cursor location, when activated from a menu wait for mouse press.
+ *
+ * In practice these operators often end up being accessed:
+ * - Directly from key bindings.
+ * - As tools in the toolbar.
+ *
+ * Even so, accessing from the menu should behave usefully.
+ */
+ OPTYPE_DEPENDS_ON_CURSOR = (1 << 11),
};
/** For #WM_cursor_grab_enable wrap axis. */
@@ -228,16 +239,16 @@ typedef enum eOperatorPropTags {
#define KM_CTRL 2
#define KM_ALT 4
#define KM_OSKEY 8
-/* means modifier should be pressed 2nd */
-#define KM_SHIFT2 16
-#define KM_CTRL2 32
-#define KM_ALT2 64
-#define KM_OSKEY2 128
+
+/* Used for key-map item creation function arguments (never stored in DNA). */
+#define KM_SHIFT_ANY 16
+#define KM_CTRL_ANY 32
+#define KM_ALT_ANY 64
+#define KM_OSKEY_ANY 128
/* KM_MOD_ flags for `wmKeyMapItem` and `wmEvent.alt/shift/oskey/ctrl`. */
/* note that KM_ANY and KM_NOTHING are used with these defines too */
-#define KM_MOD_FIRST 1
-#define KM_MOD_SECOND 2
+#define KM_MOD_HELD 1
/* type: defined in wm_event_types.c */
#define KM_TEXTINPUT -2
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index e11ef52eb84..0b7d5e5f1f4 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -266,8 +266,7 @@ IDTypeInfo IDType_ID_WM = {
.name = "WindowManager",
.name_plural = "window_managers",
.translation_context = BLT_I18NCONTEXT_ID_WINDOWMANAGER,
- .flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING | IDTYPE_FLAGS_NO_MAKELOCAL |
- IDTYPE_FLAGS_NO_ANIMDATA,
+ .flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING | IDTYPE_FLAGS_NO_ANIMDATA,
.init_data = NULL,
.copy_data = NULL,
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index 50d3a856cbe..9c020b16234 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -1146,5 +1146,31 @@ void wm_init_cursor_data(void)
BlenderCursor[WM_CURSOR_ZOOM_OUT] = &ZoomOutCursor;
END_CURSOR_BLOCK;
+ /********************** Area Pick Cursor ***********************/
+ BEGIN_CURSOR_BLOCK;
+
+ static char pick_area_bitmap[] = {
+ 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0xfe, 0x00, 0x10,
+ 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0xbf, 0x00, 0x81, 0x00, 0x81,
+ 0x00, 0x81, 0x00, 0x81, 0x00, 0x81, 0x00, 0x80, 0x00, 0xff,
+ };
+
+ static char pick_area_mask[] = {
+ 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0xff, 0x01, 0xff, 0x01, 0xff,
+ 0x01, 0x38, 0x00, 0xb8, 0x7f, 0xb8, 0xff, 0x80, 0xc1, 0x80, 0xc1,
+ 0x80, 0xc1, 0x80, 0xc1, 0x80, 0xc1, 0x80, 0xff, 0x00, 0xff,
+ };
+
+ static BCursor PickAreaCursor = {
+ pick_area_bitmap,
+ pick_area_mask,
+ 4,
+ 4,
+ false,
+ };
+
+ BlenderCursor[WM_CURSOR_PICK_AREA] = &PickAreaCursor;
+ END_CURSOR_BLOCK;
+
/********************** Put the cursors in the array ***********************/
}
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 83a9a6c6383..ae09786356a 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -1673,6 +1673,172 @@ int WM_operator_call_py(bContext *C,
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Operator Wait For Input
+ *
+ * Delay executing operators that depend on cursor location.
+ *
+ * See: #OPTYPE_DEPENDS_ON_CURSOR doc-string for more information.
+ * \{ */
+
+typedef struct uiOperatorWaitForInput {
+ ScrArea *area;
+ wmOperatorCallParams optype_params;
+ bContextStore *context;
+} uiOperatorWaitForInput;
+
+static void ui_handler_wait_for_input_remove(bContext *C, void *userdata)
+{
+ uiOperatorWaitForInput *opwait = userdata;
+ if (opwait->optype_params.opptr) {
+ if (opwait->optype_params.opptr->data) {
+ IDP_FreeProperty(opwait->optype_params.opptr->data);
+ }
+ MEM_freeN(opwait->optype_params.opptr);
+ }
+ if (opwait->context) {
+ CTX_store_free(opwait->context);
+ }
+
+ if (opwait->area != NULL) {
+ ED_area_status_text(opwait->area, NULL);
+ }
+ else {
+ ED_workspace_status_text(C, NULL);
+ }
+
+ MEM_freeN(opwait);
+}
+
+static int ui_handler_wait_for_input(bContext *C, const wmEvent *event, void *userdata)
+{
+ uiOperatorWaitForInput *opwait = userdata;
+ enum { CONTINUE = 0, EXECUTE, CANCEL } state = CONTINUE;
+ state = CONTINUE;
+
+ switch (event->type) {
+ case LEFTMOUSE: {
+ if (event->val == KM_PRESS) {
+ state = EXECUTE;
+ }
+ break;
+ }
+ /* Useful if the operator isn't convenient to access while the mouse button is held.
+ * If it takes numeric input for example. */
+ case EVT_SPACEKEY:
+ case EVT_RETKEY: {
+ if (event->val == KM_PRESS) {
+ state = EXECUTE;
+ }
+ break;
+ }
+ case RIGHTMOUSE: {
+ if (event->val == KM_PRESS) {
+ state = CANCEL;
+ }
+ break;
+ }
+ case EVT_ESCKEY: {
+ if (event->val == KM_PRESS) {
+ state = CANCEL;
+ }
+ break;
+ }
+ }
+
+ if (state != CONTINUE) {
+ wmWindow *win = CTX_wm_window(C);
+ WM_cursor_modal_restore(win);
+
+ if (state == EXECUTE) {
+ CTX_store_set(C, opwait->context);
+ WM_operator_name_call_ptr(C,
+ opwait->optype_params.optype,
+ opwait->optype_params.opcontext,
+ opwait->optype_params.opptr);
+ CTX_store_set(C, NULL);
+ }
+
+ WM_event_remove_ui_handler(&win->modalhandlers,
+ ui_handler_wait_for_input,
+ ui_handler_wait_for_input_remove,
+ opwait,
+ false);
+
+ ui_handler_wait_for_input_remove(C, opwait);
+
+ return WM_UI_HANDLER_BREAK;
+ }
+
+ return WM_UI_HANDLER_CONTINUE;
+}
+
+void WM_operator_name_call_ptr_with_depends_on_cursor(
+ bContext *C, wmOperatorType *ot, short opcontext, PointerRNA *properties, const char *drawstr)
+{
+ int flag = ot->flag;
+
+ LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &ot->macro) {
+ wmOperatorType *otm = WM_operatortype_find(macro->idname, 0);
+ if (otm != NULL) {
+ flag |= otm->flag;
+ }
+ }
+
+ if ((flag & OPTYPE_DEPENDS_ON_CURSOR) == 0) {
+ WM_operator_name_call_ptr(C, ot, opcontext, properties);
+ return;
+ }
+
+ wmWindow *win = CTX_wm_window(C);
+ ScrArea *area = CTX_wm_area(C);
+
+ {
+ char header_text[UI_MAX_DRAW_STR];
+ SNPRINTF(header_text,
+ "%s %s",
+ IFACE_("Input pending "),
+ (drawstr && drawstr[0]) ? drawstr : CTX_IFACE_(ot->translation_context, ot->name));
+ if (area != NULL) {
+ ED_area_status_text(area, header_text);
+ }
+ else {
+ ED_workspace_status_text(C, header_text);
+ }
+ }
+
+ WM_cursor_modal_set(win, WM_CURSOR_PICK_AREA);
+
+ uiOperatorWaitForInput *opwait = MEM_callocN(sizeof(*opwait), __func__);
+ opwait->optype_params.optype = ot;
+ opwait->optype_params.opcontext = opcontext;
+ opwait->optype_params.opptr = properties;
+
+ opwait->area = area;
+
+ if (properties) {
+ opwait->optype_params.opptr = MEM_mallocN(sizeof(*opwait->optype_params.opptr), __func__);
+ *opwait->optype_params.opptr = *properties;
+ if (properties->data != NULL) {
+ opwait->optype_params.opptr->data = IDP_CopyProperty(properties->data);
+ }
+ }
+
+ bContextStore *store = CTX_store_get(C);
+ if (store) {
+ opwait->context = CTX_store_copy(store);
+ }
+
+ WM_event_add_ui_handler(C,
+ &win->modalhandlers,
+ ui_handler_wait_for_input,
+ ui_handler_wait_for_input_remove,
+ opwait,
+ WM_HANDLER_BLOCKING);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Handler Types
*
* General API for different handler types.
@@ -4692,47 +4858,27 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
case EVT_LEFTSHIFTKEY:
case EVT_RIGHTSHIFTKEY:
if (event.val == KM_PRESS) {
- if (event_state->ctrl || event_state->alt || event_state->oskey) {
- keymodifier = (KM_MOD_FIRST | KM_MOD_SECOND);
- }
- else {
- keymodifier = KM_MOD_FIRST;
- }
+ keymodifier = KM_MOD_HELD;
}
event.shift = event_state->shift = keymodifier;
break;
case EVT_LEFTCTRLKEY:
case EVT_RIGHTCTRLKEY:
if (event.val == KM_PRESS) {
- if (event_state->shift || event_state->alt || event_state->oskey) {
- keymodifier = (KM_MOD_FIRST | KM_MOD_SECOND);
- }
- else {
- keymodifier = KM_MOD_FIRST;
- }
+ keymodifier = KM_MOD_HELD;
}
event.ctrl = event_state->ctrl = keymodifier;
break;
case EVT_LEFTALTKEY:
case EVT_RIGHTALTKEY:
if (event.val == KM_PRESS) {
- if (event_state->ctrl || event_state->shift || event_state->oskey) {
- keymodifier = (KM_MOD_FIRST | KM_MOD_SECOND);
- }
- else {
- keymodifier = KM_MOD_FIRST;
- }
+ keymodifier = KM_MOD_HELD;
}
event.alt = event_state->alt = keymodifier;
break;
case EVT_OSKEY:
if (event.val == KM_PRESS) {
- if (event_state->ctrl || event_state->alt || event_state->shift) {
- keymodifier = (KM_MOD_FIRST | KM_MOD_SECOND);
- }
- else {
- keymodifier = KM_MOD_FIRST;
- }
+ keymodifier = KM_MOD_HELD;
}
event.oskey = event_state->oskey = keymodifier;
break;
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 23c91dface9..2ce2bcc2f3c 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -1527,10 +1527,6 @@ static ImBuf *blend_file_thumb_from_screenshot(bContext *C, BlendThumbnail **thu
return BKE_main_thumbnail_to_imbuf(NULL, *thumb_pt);
}
- /* Redraw to remove menus that might be open. */
- WM_redraw_windows(C);
- WM_cursor_wait(true);
-
/* The window to capture should be a main window (without parent). */
wmWindow *win = CTX_wm_window(C);
while (win && win->parent) {
@@ -1563,7 +1559,6 @@ static ImBuf *blend_file_thumb_from_screenshot(bContext *C, BlendThumbnail **thu
IMB_freeImBuf(thumb_ibuf);
*thumb_pt = thumb;
}
- WM_cursor_wait(false);
/* Must be freed by caller. */
return ibuf;
@@ -1607,10 +1602,9 @@ static ImBuf *blend_file_thumb_from_camera(const bContext *C,
return NULL;
}
- if ((scene->camera == NULL) && (screen != NULL)) {
+ if (screen != NULL) {
area = BKE_screen_find_big_area(screen, SPACE_VIEW3D, 0);
- region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
- if (region) {
+ if (area) {
v3d = area->spacedata.first;
}
}
@@ -1629,13 +1623,14 @@ static ImBuf *blend_file_thumb_from_camera(const bContext *C,
if (scene->camera) {
ibuf = ED_view3d_draw_offscreen_imbuf_simple(depsgraph,
scene,
- NULL,
- OB_SOLID,
+ (v3d) ? &v3d->shading : NULL,
+ (v3d) ? v3d->shading.type : OB_SOLID,
scene->camera,
PREVIEW_RENDER_LARGE_HEIGHT * 2,
PREVIEW_RENDER_LARGE_HEIGHT * 2,
IB_rect,
- V3D_OFSDRAW_NONE,
+ (v3d) ? V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS :
+ V3D_OFSDRAW_NONE,
R_ALPHAPREMUL,
NULL,
NULL,
@@ -1758,17 +1753,41 @@ static bool wm_file_write(bContext *C,
/* Enforce full override check/generation on file save. */
BKE_lib_override_library_main_operations_create(bmain, true);
+ if (!G.background) {
+ /* Redraw to remove menus that might be open. */
+ WM_redraw_windows(C);
+ }
+
+ /* don't forget not to return without! */
+ WM_cursor_wait(true);
+
/* blend file thumbnail */
/* Save before exit_editmode, otherwise derivedmeshes for shared data corrupt T27765. */
/* Main now can store a '.blend' thumbnail, useful for background mode
* or thumbnail customization. */
main_thumb = thumb = bmain->blen_thumb;
- if (BLI_thread_is_main()) {
- if (U.file_preview_type == USER_FILE_PREVIEW_SCREENSHOT) {
- ibuf_thumb = blend_file_thumb_from_screenshot(C, &thumb);
+ if (BLI_thread_is_main() && U.file_preview_type != USER_FILE_PREVIEW_NONE) {
+
+ int file_preview_type = U.file_preview_type;
+
+ if (file_preview_type == USER_FILE_PREVIEW_AUTO) {
+ Scene *scene = CTX_data_scene(C);
+ bool do_render = (scene != NULL && scene->camera != NULL &&
+ (BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_VIEW3D, 0) != NULL));
+ file_preview_type = do_render ? USER_FILE_PREVIEW_CAMERA : USER_FILE_PREVIEW_SCREENSHOT;
}
- else if (U.file_preview_type == USER_FILE_PREVIEW_CAMERA) {
- ibuf_thumb = blend_file_thumb_from_camera(C, CTX_data_scene(C), CTX_wm_screen(C), &thumb);
+
+ switch (file_preview_type) {
+ case USER_FILE_PREVIEW_SCREENSHOT: {
+ ibuf_thumb = blend_file_thumb_from_screenshot(C, &thumb);
+ break;
+ }
+ case USER_FILE_PREVIEW_CAMERA: {
+ ibuf_thumb = blend_file_thumb_from_camera(C, CTX_data_scene(C), CTX_wm_screen(C), &thumb);
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
}
}
@@ -1778,9 +1797,6 @@ static bool wm_file_write(bContext *C,
BKE_packedfile_pack_all(bmain, reports, false);
}
- /* don't forget not to return without! */
- WM_cursor_wait(true);
-
ED_editors_flush_edits(bmain);
/* First time saving. */
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index 2416f5b50b3..29e34313be5 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -383,6 +383,12 @@ static void wm_append_loose_data_instantiate(WMLinkAppendData *lapp_data,
ViewLayer *view_layer,
const View3D *v3d)
{
+ if (scene == NULL) {
+ /* In some cases, like the asset drag&drop e.g., the caller code manages instantiation itself.
+ */
+ return;
+ }
+
LinkNode *itemlink;
Collection *active_collection = NULL;
const bool do_obdata = (lapp_data->flag & FILE_OBDATA_INSTANCE) != 0;
@@ -682,39 +688,21 @@ static void wm_append_do(WMLinkAppendData *lapp_data,
continue;
}
+ ID *local_appended_new_id = NULL;
switch (item->append_action) {
case WM_APPEND_ACT_COPY_LOCAL: {
BKE_lib_id_make_local(
- bmain, id, false, LIB_ID_MAKELOCAL_FULL_LIBRARY | LIB_ID_MAKELOCAL_FORCE_COPY);
- if (id->newid != NULL) {
- if (GS(id->newid->name) == ID_OB) {
- BKE_rigidbody_ensure_local_object(bmain, (Object *)id->newid);
- }
- if (set_fakeuser) {
- if (!ELEM(GS(id->name), ID_OB, ID_GR)) {
- /* Do not set fake user on objects nor collections (instancing). */
- id_fake_user_set(id->newid);
- }
- }
- }
+ bmain, id, LIB_ID_MAKELOCAL_FULL_LIBRARY | LIB_ID_MAKELOCAL_FORCE_COPY);
+ local_appended_new_id = id->newid;
break;
}
case WM_APPEND_ACT_MAKE_LOCAL:
BKE_lib_id_make_local(bmain,
id,
- false,
LIB_ID_MAKELOCAL_FULL_LIBRARY | LIB_ID_MAKELOCAL_FORCE_LOCAL |
LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING);
BLI_assert(id->newid == NULL);
- if (GS(id->name) == ID_OB) {
- BKE_rigidbody_ensure_local_object(bmain, (Object *)id);
- }
- if (set_fakeuser) {
- if (!ELEM(GS(id->name), ID_OB, ID_GR)) {
- /* Do not set fake user on objects nor collections (instancing). */
- id_fake_user_set(id);
- }
- }
+ local_appended_new_id = id;
break;
case WM_APPEND_ACT_KEEP_LINKED:
/* Nothing to do here. */
@@ -722,7 +710,7 @@ static void wm_append_do(WMLinkAppendData *lapp_data,
case WM_APPEND_ACT_REUSE_LOCAL:
/* We only need to set `newid` to ID found in previous loop, for proper remapping. */
ID_NEW_SET(id->newid, item->customdata);
- /* Do not set again fake user in case we reuse existing local ID. */
+ /* This is not a 'new' local appended id, do not set `local_appended_new_id` here. */
break;
case WM_APPEND_ACT_UNSET:
CLOG_ERROR(
@@ -731,6 +719,18 @@ static void wm_append_do(WMLinkAppendData *lapp_data,
default:
BLI_assert(0);
}
+
+ if (local_appended_new_id != NULL) {
+ if (GS(local_appended_new_id->name) == ID_OB) {
+ BKE_rigidbody_ensure_local_object(bmain, (Object *)local_appended_new_id);
+ }
+ if (set_fakeuser) {
+ if (!ELEM(GS(local_appended_new_id->name), ID_OB, ID_GR)) {
+ /* Do not set fake user on objects nor collections (instancing). */
+ id_fake_user_set(local_appended_new_id);
+ }
+ }
+ }
}
/* Remap IDs as needed. */
@@ -939,9 +939,8 @@ static bool wm_link_append_item_poll(ReportList *reports,
idcode = BKE_idtype_idcode_from_name(group);
- /* XXX For now, we do a nasty exception for workspace, forbid linking them.
- * Not nice, ultimately should be solved! */
- if (!BKE_idtype_idcode_is_linkable(idcode) && (do_append || idcode != ID_WS)) {
+ if (!BKE_idtype_idcode_is_linkable(idcode) ||
+ (!do_append && BKE_idtype_idcode_is_only_appendable(idcode))) {
if (reports) {
if (do_append) {
BKE_reportf(reports,
@@ -1281,6 +1280,10 @@ static ID *wm_file_link_append_datablock_ex(Main *bmain,
return id;
}
+/*
+ * NOTE: `scene` (and related `view_layer` and `v3d`) pointers may be NULL, in which case no
+ * instantiation of linked objects, collections etc. will be performed.
+ */
ID *WM_file_link_datablock(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
@@ -1293,6 +1296,10 @@ ID *WM_file_link_datablock(Main *bmain,
bmain, scene, view_layer, v3d, filepath, id_code, id_name, false);
}
+/*
+ * NOTE: `scene` (and related `view_layer` and `v3d`) pointers may be NULL, in which case no
+ * instantiation of appended objects, collections etc. will be performed.
+ */
ID *WM_file_append_datablock(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
diff --git a/source/blender/windowmanager/intern/wm_gesture_ops.c b/source/blender/windowmanager/intern/wm_gesture_ops.c
index 788e4214ac7..cc376d8f201 100644
--- a/source/blender/windowmanager/intern/wm_gesture_ops.c
+++ b/source/blender/windowmanager/intern/wm_gesture_ops.c
@@ -818,6 +818,8 @@ void WM_OT_lasso_gesture(wmOperatorType *ot)
ot->poll = WM_operator_winactive;
+ ot->flag = OPTYPE_DEPENDS_ON_CURSOR;
+
prop = RNA_def_property(ot->srna, "path", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_runtime(ot->srna, prop, &RNA_OperatorMousePath);
}
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index 25bcf1967ea..f955abaed53 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -460,8 +460,11 @@ bool WM_keymap_poll(bContext *C, wmKeyMap *keymap)
if (UNLIKELY(BLI_listbase_is_empty(&keymap->items))) {
/* Empty key-maps may be missing more there may be a typo in the name.
- * Warn early to avoid losing time investigating each case. */
- CLOG_WARN(WM_LOG_KEYMAPS, "empty keymap '%s'", keymap->idname);
+ * Warn early to avoid losing time investigating each case.
+ * When developing a customized Blender though you may want empty keymaps. */
+ if (!U.app_template[0]) {
+ CLOG_WARN(WM_LOG_KEYMAPS, "empty keymap '%s'", keymap->idname);
+ }
}
if (keymap->poll != NULL) {
@@ -481,13 +484,20 @@ static void keymap_event_set(
kmi->shift = kmi->ctrl = kmi->alt = kmi->oskey = KM_ANY;
}
else {
- kmi->shift = (modifier & KM_SHIFT) ? KM_MOD_FIRST :
- ((modifier & KM_SHIFT2) ? KM_MOD_SECOND : false);
- kmi->ctrl = (modifier & KM_CTRL) ? KM_MOD_FIRST :
- ((modifier & KM_CTRL2) ? KM_MOD_SECOND : false);
- kmi->alt = (modifier & KM_ALT) ? KM_MOD_FIRST : ((modifier & KM_ALT2) ? KM_MOD_SECOND : false);
- kmi->oskey = (modifier & KM_OSKEY) ? KM_MOD_FIRST :
- ((modifier & KM_OSKEY2) ? KM_MOD_SECOND : false);
+ /* Only one of the flags should be set. */
+ BLI_assert(((modifier & (KM_SHIFT | KM_SHIFT_ANY)) != (KM_SHIFT | KM_SHIFT_ANY)) &&
+ ((modifier & (KM_CTRL | KM_CTRL_ANY)) != (KM_CTRL | KM_CTRL_ANY)) &&
+ ((modifier & (KM_ALT | KM_ALT_ANY)) != (KM_ALT | KM_ALT_ANY)) &&
+ ((modifier & (KM_OSKEY | KM_OSKEY_ANY)) != (KM_OSKEY | KM_OSKEY_ANY)));
+
+ kmi->shift = ((modifier & KM_SHIFT) ? KM_MOD_HELD :
+ ((modifier & KM_SHIFT_ANY) ? KM_ANY : KM_NOTHING));
+ kmi->ctrl = ((modifier & KM_CTRL) ? KM_MOD_HELD :
+ ((modifier & KM_CTRL_ANY) ? KM_ANY : KM_NOTHING));
+ kmi->alt = ((modifier & KM_ALT) ? KM_MOD_HELD :
+ ((modifier & KM_ALT_ANY) ? KM_ANY : KM_NOTHING));
+ kmi->oskey = ((modifier & KM_OSKEY) ? KM_MOD_HELD :
+ ((modifier & KM_OSKEY_ANY) ? KM_ANY : KM_NOTHING));
}
}
@@ -1161,7 +1171,6 @@ int WM_keymap_item_raw_to_string(const short shift,
buf[0] = '\0';
- /* TODO: support order (KM_SHIFT vs. KM_SHIFT2) ? */
if (shift == KM_ANY && ctrl == KM_ANY && alt == KM_ANY && oskey == KM_ANY) {
/* Don't show anything for any mapping. */
}
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 0402b0d778a..887aed7ffc7 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -1197,7 +1197,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
#ifdef USE_WIN_ACTIVATE
else {
if (keymodifier & KM_SHIFT) {
- win->eventstate->shift = KM_MOD_FIRST;
+ win->eventstate->shift = KM_MOD_HELD;
}
}
#endif
@@ -1210,7 +1210,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
#ifdef USE_WIN_ACTIVATE
else {
if (keymodifier & KM_CTRL) {
- win->eventstate->ctrl = KM_MOD_FIRST;
+ win->eventstate->ctrl = KM_MOD_HELD;
}
}
#endif
@@ -1223,7 +1223,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
#ifdef USE_WIN_ACTIVATE
else {
if (keymodifier & KM_ALT) {
- win->eventstate->alt = KM_MOD_FIRST;
+ win->eventstate->alt = KM_MOD_HELD;
}
}
#endif
@@ -1236,7 +1236,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
#ifdef USE_WIN_ACTIVATE
else {
if (keymodifier & KM_OSKEY) {
- win->eventstate->oskey = KM_MOD_FIRST;
+ win->eventstate->oskey = KM_MOD_HELD;
}
}
#endif
diff --git a/source/blender/windowmanager/wm_cursors.h b/source/blender/windowmanager/wm_cursors.h
index 2842538ebf1..d1694454490 100644
--- a/source/blender/windowmanager/wm_cursors.h
+++ b/source/blender/windowmanager/wm_cursors.h
@@ -74,6 +74,8 @@ typedef enum WMCursorType {
WM_CURSOR_NONE,
WM_CURSOR_MUTE,
+ WM_CURSOR_PICK_AREA,
+
/* --- ALWAYS LAST ----- */
WM_CURSOR_NUM,
} WMCursorType;
diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt
index 79632e49c1f..a1b94abc317 100644
--- a/tests/python/CMakeLists.txt
+++ b/tests/python/CMakeLists.txt
@@ -766,7 +766,7 @@ foreach(geo_node_test ${geo_node_tests})
)
endforeach()
else()
- MESSAGE(STATUS "No directory named ${TEST_SRC_DIR}/modeling/geometry_nodes/${geo_node_test}/ found, disabling test.")
+ MESSAGE(STATUS "Directory named ${TEST_SRC_DIR}/modeling/geometry_nodes/${geo_node_test}/ Not Found, disabling test.")
endif()
endforeach()