diff options
author | Jacques Lucke <jacques@blender.org> | 2021-09-17 11:56:46 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2021-09-17 11:56:46 +0300 |
commit | dcf72a30e174cf2a4a7eeb7c482690b31cdef172 (patch) | |
tree | fd220ebf2b45802f82b2328e735d3ac1dfcd97ac | |
parent | 0bec1f5dadc0a52dcfe895b8fe04a431d52930ab (diff) | |
parent | 9dee0a10c81d9f4ce8d4fc85ed8722d899f34dde (diff) |
Merge branch 'master' into temp-field-visualization
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() |