diff options
Diffstat (limited to 'source/blender/blenkernel/intern')
82 files changed, 2930 insertions, 1072 deletions
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 842902b51ed..408a0b3065e 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -176,7 +176,7 @@ static void action_foreach_id(ID *id, LibraryForeachIDData *data) bAction *act = (bAction *)id; LISTBASE_FOREACH (FCurve *, fcu, &act->curves) { - BKE_fcurve_foreach_id(fcu, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_fcurve_foreach_id(fcu, data)); } LISTBASE_FOREACH (TimeMarker *, marker, &act->markers) { @@ -320,6 +320,7 @@ IDTypeInfo IDType_ID_AC = { .name_plural = "actions", .translation_context = BLT_I18NCONTEXT_ID_ACTION, .flags = IDTYPE_FLAGS_NO_ANIMDATA, + .asset_type_info = &AssetType_AC, .init_data = NULL, .copy_data = action_copy_data, @@ -337,8 +338,6 @@ IDTypeInfo IDType_ID_AC = { .blend_read_undo_preserve = NULL, .lib_override_apply_post = NULL, - - .asset_type_info = &AssetType_AC, }; /* ***************** Library data level operations on action ************** */ @@ -1574,6 +1573,30 @@ void calc_action_range(const bAction *act, float *start, float *end, short incl_ } } +/* Retrieve the intended playback frame range, using the manually set range if available, + * or falling back to scanning F-Curves for their first & last frames otherwise. */ +void BKE_action_get_frame_range(const struct bAction *act, float *r_start, float *r_end) +{ + if (act && (act->flag & ACT_FRAME_RANGE)) { + *r_start = act->frame_start; + *r_end = act->frame_end; + } + else { + calc_action_range(act, r_start, r_end, false); + } + + /* Ensure that action is at least 1 frame long (for NLA strips to have a valid length). */ + if (*r_start >= *r_end) { + *r_end = *r_start + 1.0f; + } +} + +/* Is the action configured as cyclic. */ +bool BKE_action_is_cyclic(const struct bAction *act) +{ + return act && (act->flag & ACT_FRAME_RANGE) && (act->flag & ACT_CYCLIC); +} + /* Return flags indicating which transforms the given object/posechannel has * - if 'curves' is provided, a list of links to these curves are also returned */ diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c index 23d2c4fe55f..21887d514d9 100644 --- a/source/blender/blenkernel/intern/anim_data.c +++ b/source/blender/blenkernel/intern/anim_data.c @@ -294,7 +294,7 @@ bool BKE_animdata_id_is_animated(const struct ID *id) void BKE_animdata_foreach_id(AnimData *adt, LibraryForeachIDData *data) { LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) { - BKE_fcurve_foreach_id(fcu, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_fcurve_foreach_id(fcu, data)); } BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, adt->action, IDWALK_CB_USER); diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c index 08a3b7d0bbb..d872dc67dcb 100644 --- a/source/blender/blenkernel/intern/appdir.c +++ b/source/blender/blenkernel/intern/appdir.c @@ -279,23 +279,31 @@ bool BKE_appdir_folder_caches(char *r_path, const size_t path_len) /** * Gets a good default directory for fonts. */ -bool BKE_appdir_font_folder_default( - /* This parameter can only be `const` on non-windows platforms. - * NOLINTNEXTLINE: readability-non-const-parameter. */ - char *dir) +bool BKE_appdir_font_folder_default(char *dir) { - bool success = false; + char test_dir[FILE_MAXDIR]; + test_dir[0] = '\0'; + #ifdef WIN32 wchar_t wpath[FILE_MAXDIR]; - success = SHGetSpecialFolderPathW(0, wpath, CSIDL_FONTS, 0); - if (success) { + if (SHGetSpecialFolderPathW(0, wpath, CSIDL_FONTS, 0)) { wcscat(wpath, L"\\"); - BLI_strncpy_wchar_as_utf8(dir, wpath, FILE_MAXDIR); + BLI_strncpy_wchar_as_utf8(test_dir, wpath, sizeof(test_dir)); + } +#elif defined(__APPLE__) + const char *home = BLI_getenv("HOME"); + if (home) { + BLI_path_join(test_dir, sizeof(test_dir), home, "Library", "Fonts", NULL); } +#else + STRNCPY(test_dir, "/usr/share/fonts"); #endif - /* TODO: Values for other platforms. */ - UNUSED_VARS(dir); - return success; + + if (test_dir[0] && BLI_exists(test_dir)) { + BLI_strncpy(dir, test_dir, FILE_MAXDIR); + return true; + } + return false; } /** \} */ diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index b64b050f4e7..7bb6d9c1452 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -161,30 +161,36 @@ static void armature_free_data(struct ID *id) static void armature_foreach_id_bone(Bone *bone, LibraryForeachIDData *data) { - IDP_foreach_property( - bone->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + IDP_foreach_property( + bone->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data)); LISTBASE_FOREACH (Bone *, curbone, &bone->childbase) { - armature_foreach_id_bone(curbone, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, armature_foreach_id_bone(curbone, data)); } } static void armature_foreach_id_editbone(EditBone *edit_bone, LibraryForeachIDData *data) { - IDP_foreach_property( - edit_bone->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + IDP_foreach_property(edit_bone->prop, + IDP_TYPE_FILTER_ID, + BKE_lib_query_idpropertiesForeachIDLink_callback, + data)); } static void armature_foreach_id(ID *id, LibraryForeachIDData *data) { bArmature *arm = (bArmature *)id; LISTBASE_FOREACH (Bone *, bone, &arm->bonebase) { - armature_foreach_id_bone(bone, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, armature_foreach_id_bone(bone, data)); } if (arm->edbo != NULL) { LISTBASE_FOREACH (EditBone *, edit_bone, arm->edbo) { - armature_foreach_id_editbone(edit_bone, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, armature_foreach_id_editbone(edit_bone, data)); } } } @@ -316,6 +322,7 @@ IDTypeInfo IDType_ID_AR = { .name_plural = "armatures", .translation_context = BLT_I18NCONTEXT_ID_ARMATURE, .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE, + .asset_type_info = NULL, .init_data = armature_init_data, .copy_data = armature_copy_data, diff --git a/source/blender/blenkernel/intern/asset.cc b/source/blender/blenkernel/intern/asset.cc index 7bea089b9bf..59e402b6680 100644 --- a/source/blender/blenkernel/intern/asset.cc +++ b/source/blender/blenkernel/intern/asset.cc @@ -21,14 +21,12 @@ #include <cstring> #include "DNA_ID.h" -#include "DNA_asset_types.h" #include "DNA_defaults.h" #include "BLI_listbase.h" #include "BLI_string.h" #include "BLI_string_ref.hh" #include "BLI_string_utils.h" -#include "BLI_utildefines.h" #include "BLI_uuid.h" #include "BKE_asset.h" diff --git a/source/blender/blenkernel/intern/asset_catalog.cc b/source/blender/blenkernel/intern/asset_catalog.cc index 33405c9aeae..9ef66d23aea 100644 --- a/source/blender/blenkernel/intern/asset_catalog.cc +++ b/source/blender/blenkernel/intern/asset_catalog.cc @@ -18,25 +18,20 @@ * \ingroup bke */ +#include <fstream> +#include <set> + #include "BKE_asset_catalog.hh" #include "BKE_asset_library.h" -#include "BKE_preferences.h" #include "BLI_fileops.h" #include "BLI_path_util.h" -#include "BLI_set.hh" -#include "BLI_string_ref.hh" - -#include "DNA_userdef_types.h" /* For S_ISREG() and S_ISDIR() on Windows. */ #ifdef WIN32 # include "BLI_winstuff.h" #endif -#include <fstream> -#include <set> - namespace blender::bke { const CatalogFilePath AssetCatalogService::DEFAULT_CATALOG_FILENAME = "blender_assets.cats.txt"; diff --git a/source/blender/blenkernel/intern/asset_catalog_test.cc b/source/blender/blenkernel/intern/asset_catalog_test.cc index 2cef34966f8..ba8f8716823 100644 --- a/source/blender/blenkernel/intern/asset_catalog_test.cc +++ b/source/blender/blenkernel/intern/asset_catalog_test.cc @@ -24,6 +24,7 @@ #include "BLI_fileops.h" #include "BLI_path_util.h" +#include "DNA_asset_types.h" #include "DNA_userdef_types.h" #include "testing/testing.h" @@ -930,6 +931,28 @@ TEST_F(AssetCatalogTest, update_catalog_path_simple_name) << "Changing the path should update the simplename of children."; } +TEST_F(AssetCatalogTest, update_catalog_path_longer_than_simplename) +{ + AssetCatalogService service(asset_library_root_); + service.load_from_disk(asset_library_root_ + "/" + + AssetCatalogService::DEFAULT_CATALOG_FILENAME); + const std::string new_path = + "this/is/a/very/long/path/that/exceeds/the/simple-name/length/of/assets"; + ASSERT_GT(new_path.length(), sizeof(AssetMetaData::catalog_simple_name)) + << "This test case should work with paths longer than AssetMetaData::catalog_simple_name"; + + service.update_catalog_path(UUID_POSES_RUZENA, new_path); + + const std::string new_simple_name = service.find_catalog(UUID_POSES_RUZENA)->simple_name; + EXPECT_LT(new_simple_name.length(), sizeof(AssetMetaData::catalog_simple_name)) + << "The new simple name should fit in the asset metadata."; + EXPECT_EQ("...very-long-path-that-exceeds-the-simple-name-length-of-assets", new_simple_name) + << "Changing the path should update the simplename."; + EXPECT_EQ("...long-path-that-exceeds-the-simple-name-length-of-assets-face", + service.find_catalog(UUID_POSES_RUZENA_FACE)->simple_name) + << "Changing the path should update the simplename of children."; +} + TEST_F(AssetCatalogTest, update_catalog_path_add_slashes) { AssetCatalogService service(asset_library_root_); diff --git a/source/blender/blenkernel/intern/asset_library.cc b/source/blender/blenkernel/intern/asset_library.cc index aae8a289d32..68e43852a21 100644 --- a/source/blender/blenkernel/intern/asset_library.cc +++ b/source/blender/blenkernel/intern/asset_library.cc @@ -18,9 +18,9 @@ * \ingroup bke */ -#include "BKE_asset_catalog.hh" +#include <memory> + #include "BKE_asset_library.hh" -#include "BKE_callbacks.h" #include "BKE_main.h" #include "BKE_preferences.h" @@ -29,12 +29,8 @@ #include "DNA_asset_types.h" #include "DNA_userdef_types.h" -#include "MEM_guardedalloc.h" - #include "asset_library_service.hh" -#include <memory> - bool blender::bke::AssetLibrary::save_catalogs_when_file_is_saved = true; /** diff --git a/source/blender/blenkernel/intern/asset_library_service.cc b/source/blender/blenkernel/intern/asset_library_service.cc index 7cf95ee4cc1..d202d6462cf 100644 --- a/source/blender/blenkernel/intern/asset_library_service.cc +++ b/source/blender/blenkernel/intern/asset_library_service.cc @@ -20,16 +20,12 @@ #include "asset_library_service.hh" -#include "BKE_asset_library.hh" #include "BKE_blender.h" -#include "BKE_callbacks.h" -#include "BLI_fileops.h" +#include "BLI_fileops.h" /* For PATH_MAX (at least on Windows). */ #include "BLI_path_util.h" #include "BLI_string_ref.hh" -#include "MEM_guardedalloc.h" - #include "CLG_log.h" static CLG_LogRef LOG = {"bke.asset_service"}; diff --git a/source/blender/blenkernel/intern/asset_library_service_test.cc b/source/blender/blenkernel/intern/asset_library_service_test.cc index e26ae05301e..ee910cab945 100644 --- a/source/blender/blenkernel/intern/asset_library_service_test.cc +++ b/source/blender/blenkernel/intern/asset_library_service_test.cc @@ -19,7 +19,7 @@ #include "asset_library_service.hh" -#include "BLI_fileops.h" +#include "BLI_fileops.h" /* For PATH_MAX (at least on Windows). */ #include "BLI_path_util.h" #include "BKE_appdir.h" diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index cd394a4ca42..3f2c1f13337 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -50,9 +50,7 @@ using blender::bke::AttributeIDRef; using blender::bke::OutputAttribute; using blender::fn::GMutableSpan; using blender::fn::GSpan; -using blender::fn::GVArray_For_GSpan; -using blender::fn::GVArray_For_SingleValue; -using blender::fn::GVMutableArray_For_GMutableSpan; +using blender::fn::GVMutableArrayImpl_For_GMutableSpan; namespace blender::bke { @@ -166,16 +164,18 @@ CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType> data_ static int attribute_domain_priority(const AttributeDomain domain) { switch (domain) { - case ATTR_DOMAIN_CURVE: + case ATTR_DOMAIN_INSTANCE: return 0; - case ATTR_DOMAIN_FACE: + case ATTR_DOMAIN_CURVE: return 1; - case ATTR_DOMAIN_EDGE: + case ATTR_DOMAIN_FACE: return 2; - case ATTR_DOMAIN_POINT: + case ATTR_DOMAIN_EDGE: return 3; - case ATTR_DOMAIN_CORNER: + case ATTR_DOMAIN_POINT: return 4; + case ATTR_DOMAIN_CORNER: + return 5; default: /* Domain not supported in nodes yet. */ BLI_assert_unreachable(); @@ -207,7 +207,7 @@ fn::GMutableSpan OutputAttribute::as_span() { if (!optional_span_varray_) { const bool materialize_old_values = !ignore_old_values_; - optional_span_varray_ = std::make_unique<fn::GVMutableArray_GSpan>(*varray_, + optional_span_varray_ = std::make_unique<fn::GVMutableArray_GSpan>(varray_, materialize_old_values); } fn::GVMutableArray_GSpan &span_varray = *optional_span_varray_; @@ -257,8 +257,8 @@ static bool add_builtin_type_custom_data_layer_from_init(CustomData &custom_data if (data == nullptr) { return false; } - const GVArray *varray = static_cast<const AttributeInitVArray &>(initializer).varray; - varray->materialize_to_uninitialized(IndexRange(varray->size()), data); + const GVArray &varray = static_cast<const AttributeInitVArray &>(initializer).varray; + varray.materialize_to_uninitialized(varray.index_range(), data); return true; } case AttributeInit::Type::MoveArray: { @@ -313,8 +313,8 @@ static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attr if (data == nullptr) { return false; } - const GVArray *varray = static_cast<const AttributeInitVArray &>(initializer).varray; - varray->materialize_to_uninitialized(IndexRange(varray->size()), data); + const GVArray &varray = static_cast<const AttributeInitVArray &>(initializer).varray; + varray.materialize_to_uninitialized(varray.index_range(), data); return true; } case AttributeInit::Type::MoveArray: { @@ -345,8 +345,7 @@ static bool custom_data_layer_matches_attribute_id(const CustomDataLayer &layer, return layer.name == attribute_id.name(); } -GVArrayPtr BuiltinCustomDataLayerProvider::try_get_for_read( - const GeometryComponent &component) const +GVArray BuiltinCustomDataLayerProvider::try_get_for_read(const GeometryComponent &component) const { const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); if (custom_data == nullptr) { @@ -511,7 +510,7 @@ ReadAttributeLookup CustomDataAttributeProvider::try_get_for_read( continue; } GSpan data{*type, layer.data, domain_size}; - return {std::make_unique<GVArray_For_GSpan>(data), domain_}; + return {GVArray::ForSpan(data), domain_}; } return {}; } @@ -541,7 +540,7 @@ WriteAttributeLookup CustomDataAttributeProvider::try_get_for_write( continue; } GMutableSpan data{*type, layer.data, domain_size}; - return {std::make_unique<GVMutableArray_For_GMutableSpan>(data), domain_}; + return {GVMutableArray::ForSpan(data), domain_}; } return {}; } @@ -751,25 +750,25 @@ std::optional<GSpan> CustomDataAttributes::get_for_read(const AttributeIDRef &at * value if the attribute doesn't exist. If no default value is provided, the default value for the * type will be used. */ -GVArrayPtr CustomDataAttributes::get_for_read(const AttributeIDRef &attribute_id, - const CustomDataType data_type, - const void *default_value) const +GVArray CustomDataAttributes::get_for_read(const AttributeIDRef &attribute_id, + const CustomDataType data_type, + const void *default_value) const { const CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type); std::optional<GSpan> attribute = this->get_for_read(attribute_id); if (!attribute) { const int domain_size = this->size_; - return std::make_unique<GVArray_For_SingleValue>( + return GVArray::ForSingle( *type, domain_size, (default_value == nullptr) ? type->default_value() : default_value); } if (attribute->type() == *type) { - return std::make_unique<GVArray_For_GSpan>(*attribute); + return GVArray::ForSpan(*attribute); } const blender::nodes::DataTypeConversions &conversions = blender::nodes::get_implicit_type_conversions(); - return conversions.try_convert(std::make_unique<GVArray_For_GSpan>(*attribute), *type); + return conversions.try_convert(GVArray::ForSpan(*attribute), *type); } std::optional<GMutableSpan> CustomDataAttributes::get_for_write(const AttributeIDRef &attribute_id) @@ -922,8 +921,8 @@ blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read( return {}; } -std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_adapt_domain( - std::unique_ptr<blender::fn::GVArray> varray, +blender::fn::GVArray GeometryComponent::attribute_try_adapt_domain_impl( + const blender::fn::GVArray &varray, const AttributeDomain from_domain, const AttributeDomain to_domain) const { @@ -1110,15 +1109,15 @@ std::optional<AttributeMetaData> GeometryComponent::attribute_get_meta_data( return result; } -static std::unique_ptr<blender::fn::GVArray> try_adapt_data_type( - std::unique_ptr<blender::fn::GVArray> varray, const blender::fn::CPPType &to_type) +static blender::fn::GVArray try_adapt_data_type(blender::fn::GVArray varray, + const blender::fn::CPPType &to_type) { const blender::nodes::DataTypeConversions &conversions = blender::nodes::get_implicit_type_conversions(); return conversions.try_convert(std::move(varray), to_type); } -std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_get_for_read( +blender::fn::GVArray GeometryComponent::attribute_try_get_for_read( const AttributeIDRef &attribute_id, const AttributeDomain domain, const CustomDataType data_type) const @@ -1128,7 +1127,7 @@ std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_get_for_r return {}; } - std::unique_ptr<blender::fn::GVArray> varray = std::move(attribute.varray); + blender::fn::GVArray varray = std::move(attribute.varray); if (!ELEM(domain, ATTR_DOMAIN_AUTO, attribute.domain)) { varray = this->attribute_try_adapt_domain(std::move(varray), attribute.domain, domain); if (!varray) { @@ -1138,7 +1137,7 @@ std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_get_for_r const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type); BLI_assert(cpp_type != nullptr); - if (varray->type() != *cpp_type) { + if (varray.type() != *cpp_type) { varray = try_adapt_data_type(std::move(varray), *cpp_type); if (!varray) { return {}; @@ -1148,7 +1147,7 @@ std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_get_for_r return varray; } -std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_try_get_for_read( +blender::fn::GVArray GeometryComponent::attribute_try_get_for_read( const AttributeIDRef &attribute_id, const AttributeDomain domain) const { if (!this->attribute_domain_supported(domain)) { @@ -1176,7 +1175,7 @@ blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read( } const blender::fn::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type); BLI_assert(type != nullptr); - if (attribute.varray->type() == *type) { + if (attribute.varray.type() == *type) { return attribute; } const blender::nodes::DataTypeConversions &conversions = @@ -1184,14 +1183,12 @@ blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read( return {conversions.try_convert(std::move(attribute.varray), *type), attribute.domain}; } -std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_get_for_read( - const AttributeIDRef &attribute_id, - const AttributeDomain domain, - const CustomDataType data_type, - const void *default_value) const +blender::fn::GVArray GeometryComponent::attribute_get_for_read(const AttributeIDRef &attribute_id, + const AttributeDomain domain, + const CustomDataType data_type, + const void *default_value) const { - std::unique_ptr<blender::bke::GVArray> varray = this->attribute_try_get_for_read( - attribute_id, domain, data_type); + blender::fn::GVArray varray = this->attribute_try_get_for_read(attribute_id, domain, data_type); if (varray) { return varray; } @@ -1200,11 +1197,11 @@ std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_get_for_read default_value = type->default_value(); } const int domain_size = this->attribute_domain_size(domain); - return std::make_unique<blender::fn::GVArray_For_SingleValue>(*type, domain_size, default_value); + return blender::fn::GVArray::ForSingle(*type, domain_size, default_value); } class GVMutableAttribute_For_OutputAttribute - : public blender::fn::GVMutableArray_For_GMutableSpan { + : public blender::fn::GVMutableArrayImpl_For_GMutableSpan { public: GeometryComponent *component; std::string attribute_name; @@ -1213,7 +1210,7 @@ class GVMutableAttribute_For_OutputAttribute GVMutableAttribute_For_OutputAttribute(GMutableSpan data, GeometryComponent &component, const AttributeIDRef &attribute_id) - : blender::fn::GVMutableArray_For_GMutableSpan(data), component(&component) + : blender::fn::GVMutableArrayImpl_For_GMutableSpan(data), component(&component) { if (attribute_id.is_named()) { this->attribute_name = attribute_id.name(); @@ -1239,7 +1236,8 @@ static void save_output_attribute(OutputAttribute &output_attribute) using namespace blender::bke; GVMutableAttribute_For_OutputAttribute &varray = - dynamic_cast<GVMutableAttribute_For_OutputAttribute &>(output_attribute.varray()); + dynamic_cast<GVMutableAttribute_For_OutputAttribute &>( + *output_attribute.varray().get_implementation()); GeometryComponent &component = *varray.component; AttributeIDRef attribute_id; @@ -1267,7 +1265,7 @@ static void save_output_attribute(OutputAttribute &output_attribute) BUFFER_FOR_CPP_TYPE_VALUE(varray.type(), buffer); for (const int i : IndexRange(varray.size())) { varray.get(i, buffer); - write_attribute.varray->set_by_relocate(i, buffer); + write_attribute.varray.set_by_relocate(i, buffer); } if (write_attribute.tag_modified_fn) { write_attribute.tag_modified_fn(); @@ -1310,9 +1308,9 @@ static OutputAttribute create_output_attribute(GeometryComponent &component, if (!attribute) { if (default_value) { const int64_t domain_size = component.attribute_domain_size(domain); - const GVArray_For_SingleValueRef default_varray{*cpp_type, domain_size, default_value}; - component.attribute_try_create_builtin(attribute_name, - AttributeInitVArray(&default_varray)); + component.attribute_try_create_builtin( + attribute_name, + AttributeInitVArray(GVArray::ForSingleRef(*cpp_type, domain_size, default_value))); } else { component.attribute_try_create_builtin(attribute_name, AttributeInitDefault()); @@ -1327,9 +1325,8 @@ static OutputAttribute create_output_attribute(GeometryComponent &component, /* Builtin attribute is on different domain. */ return {}; } - - GVMutableArrayPtr varray = std::move(attribute.varray); - if (varray->type() == *cpp_type) { + GVMutableArray varray = std::move(attribute.varray); + if (varray.type() == *cpp_type) { /* Builtin attribute matches exactly. */ return OutputAttribute(std::move(varray), domain, @@ -1349,9 +1346,11 @@ static OutputAttribute create_output_attribute(GeometryComponent &component, WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_id); if (!attribute) { if (default_value) { - const GVArray_For_SingleValueRef default_varray{*cpp_type, domain_size, default_value}; component.attribute_try_create( - attribute_id, domain, data_type, AttributeInitVArray(&default_varray)); + attribute_id, + domain, + data_type, + AttributeInitVArray(GVArray::ForSingleRef(*cpp_type, domain_size, default_value))); } else { component.attribute_try_create(attribute_id, domain, data_type, AttributeInitDefault()); @@ -1363,7 +1362,7 @@ static OutputAttribute create_output_attribute(GeometryComponent &component, return {}; } } - if (attribute.domain == domain && attribute.varray->type() == *cpp_type) { + if (attribute.domain == domain && attribute.varray.type() == *cpp_type) { /* Existing generic attribute matches exactly. */ return OutputAttribute(std::move(attribute.varray), @@ -1382,11 +1381,11 @@ static OutputAttribute create_output_attribute(GeometryComponent &component, } else { /* Fill the temporary array with values from the existing attribute. */ - GVArrayPtr old_varray = component.attribute_get_for_read( + GVArray old_varray = component.attribute_get_for_read( attribute_id, domain, data_type, default_value); - old_varray->materialize_to_uninitialized(IndexRange(domain_size), data); + old_varray.materialize_to_uninitialized(IndexRange(domain_size), data); } - GVMutableArrayPtr varray = std::make_unique<GVMutableAttribute_For_OutputAttribute>( + GVMutableArray varray = GVMutableArray::For<GVMutableAttribute_For_OutputAttribute>( GMutableSpan{*cpp_type, data, domain_size}, component, attribute_id); return OutputAttribute(std::move(varray), domain, save_output_attribute, true); @@ -1410,21 +1409,21 @@ OutputAttribute GeometryComponent::attribute_try_get_for_output_only( namespace blender::bke { -const GVArray *AttributeFieldInput::get_varray_for_context(const fn::FieldContext &context, - IndexMask UNUSED(mask), - ResourceScope &scope) const +GVArray AttributeFieldInput::get_varray_for_context(const fn::FieldContext &context, + IndexMask UNUSED(mask), + ResourceScope &UNUSED(scope)) const { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { const GeometryComponent &component = geometry_context->geometry_component(); 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); + GVArray attribute = component.attribute_try_get_for_read(name_, domain, data_type); if (attribute) { - return scope.add(std::move(attribute)); + return attribute; } } - return nullptr; + return {}; } std::string AttributeFieldInput::socket_inspection_name() const @@ -1451,31 +1450,32 @@ static StringRef get_random_id_attribute_name(const AttributeDomain domain) { switch (domain) { case ATTR_DOMAIN_POINT: + case ATTR_DOMAIN_INSTANCE: return "id"; default: return ""; } } -const GVArray *IDAttributeFieldInput::get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &scope) const +GVArray IDAttributeFieldInput::get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &scope) const { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { const GeometryComponent &component = geometry_context->geometry_component(); const AttributeDomain domain = geometry_context->domain(); const StringRef name = get_random_id_attribute_name(domain); - GVArrayPtr attribute = component.attribute_try_get_for_read(name, domain, CD_PROP_INT32); + GVArray attribute = component.attribute_try_get_for_read(name, domain, CD_PROP_INT32); if (attribute) { - BLI_assert(attribute->size() == component.attribute_domain_size(domain)); - return scope.add(std::move(attribute)); + BLI_assert(attribute.size() == component.attribute_domain_size(domain)); + return attribute; } /* Use the index as the fallback if no random ID attribute exists. */ return fn::IndexFieldInput::get_index_varray(mask, scope); } - return nullptr; + return {}; } std::string IDAttributeFieldInput::socket_inspection_name() const @@ -1495,19 +1495,20 @@ bool IDAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const return dynamic_cast<const IDAttributeFieldInput *>(&other) != nullptr; } -const GVArray *AnonymousAttributeFieldInput::get_varray_for_context( - const fn::FieldContext &context, IndexMask UNUSED(mask), ResourceScope &scope) const +GVArray AnonymousAttributeFieldInput::get_varray_for_context(const fn::FieldContext &context, + IndexMask UNUSED(mask), + ResourceScope &UNUSED(scope)) const { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { const GeometryComponent &component = geometry_context->geometry_component(); 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( + GVArray attribute = component.attribute_try_get_for_read( anonymous_id_.get(), domain, data_type); - return scope.add(std::move(attribute)); + return attribute; } - return nullptr; + return {}; } std::string AnonymousAttributeFieldInput::socket_inspection_name() const diff --git a/source/blender/blenkernel/intern/attribute_access_intern.hh b/source/blender/blenkernel/intern/attribute_access_intern.hh index 140498bdb01..b77d7010efa 100644 --- a/source/blender/blenkernel/intern/attribute_access_intern.hh +++ b/source/blender/blenkernel/intern/attribute_access_intern.hh @@ -24,9 +24,6 @@ namespace blender::bke { -using fn::GVArrayPtr; -using fn::GVMutableArrayPtr; - /** * Utility to group together multiple functions that are used to access custom data on geometry * components in a generic way. @@ -86,7 +83,7 @@ class BuiltinAttributeProvider { { } - virtual GVArrayPtr try_get_for_read(const GeometryComponent &component) const = 0; + virtual GVArray try_get_for_read(const GeometryComponent &component) const = 0; virtual WriteAttributeLookup try_get_for_write(GeometryComponent &component) const = 0; virtual bool try_delete(GeometryComponent &component) const = 0; virtual bool try_create(GeometryComponent &UNUSED(component), @@ -188,8 +185,8 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider { */ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider { private: - using AsReadAttribute = GVArrayPtr (*)(const void *data, const int domain_size); - using AsWriteAttribute = GVMutableArrayPtr (*)(void *data, const int domain_size); + using AsReadAttribute = GVArray (*)(const void *data, const int domain_size); + using AsWriteAttribute = GVMutableArray (*)(void *data, const int domain_size); const AttributeDomain domain_; const CustomDataType attribute_type_; const CustomDataType stored_type_; @@ -232,8 +229,8 @@ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider { * if the stored type is the same as the attribute type. */ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { - using AsReadAttribute = GVArrayPtr (*)(const void *data, const int domain_size); - using AsWriteAttribute = GVMutableArrayPtr (*)(void *data, const int domain_size); + using AsReadAttribute = GVArray (*)(const void *data, const int domain_size); + using AsWriteAttribute = GVMutableArray (*)(void *data, const int domain_size); using UpdateOnRead = void (*)(const GeometryComponent &component); using UpdateOnWrite = void (*)(GeometryComponent &component); const CustomDataType stored_type_; @@ -266,7 +263,7 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { { } - GVArrayPtr try_get_for_read(const GeometryComponent &component) const final; + GVArray try_get_for_read(const GeometryComponent &component) const final; WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final; bool try_delete(GeometryComponent &component) const final; bool try_create(GeometryComponent &component, const AttributeInit &initializer) const final; diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index 97f8bddc043..fb65a9bec7e 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -90,7 +90,6 @@ void BKE_blender_free(void) IMB_exit(); BKE_cachefiles_exit(); - BKE_images_exit(); DEG_free_node_types(); BKE_brush_system_exit(); diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c index 9c9f898afef..f8b943d3479 100644 --- a/source/blender/blenkernel/intern/blender_copybuffer.c +++ b/source/blender/blenkernel/intern/blender_copybuffer.c @@ -57,20 +57,26 @@ /** \name Copy/Paste `.blend`, partial saves. * \{ */ -void BKE_copybuffer_begin(Main *bmain_src) +/** Initialize a copy operation. */ +void BKE_copybuffer_copy_begin(Main *bmain_src) { BKE_blendfile_write_partial_begin(bmain_src); } -void BKE_copybuffer_tag_ID(ID *id) +/** Mark an ID to be copied. Should only be called after a call to #BKE_copybuffer_copy_begin. */ +void BKE_copybuffer_copy_tag_ID(ID *id) { BKE_blendfile_write_partial_tag_ID(id, true); } /** - * \return Success. + * Finalize a copy operation into given .blend file 'buffer'. + * + * \param filename: Full path to the .blend file used as copy/paste buffer. + * + * \return true on success, false otherwise. */ -bool BKE_copybuffer_save(Main *bmain_src, const char *filename, ReportList *reports) +bool BKE_copybuffer_copy_end(Main *bmain_src, const char *filename, ReportList *reports) { const int write_flags = 0; const eBLO_WritePathRemap remap_mode = BLO_WRITE_PATH_REMAP_RELATIVE; @@ -82,6 +88,16 @@ bool BKE_copybuffer_save(Main *bmain_src, const char *filename, ReportList *repo return retval; } +/** + * Paste datablocks from the given .blend file 'buffer' (i.e. append them). + * + * Unlike #BKE_copybuffer_paste, it does not perform any instantiation of collections/objects/etc. + * + * \param libname: Full path to the .blend file used as copy/paste buffer. + * \param id_types_mask: Only directly link IDs of those types from the given .blend file buffer. + * + * \return true on success, false otherwise. + */ bool BKE_copybuffer_read(Main *bmain_dst, const char *libname, ReportList *reports, @@ -116,12 +132,22 @@ bool BKE_copybuffer_read(Main *bmain_dst, } /** - * \return Number of IDs directly pasted from the buffer - * (does not includes indirectly pulled out ones). + * Paste datablocks from the given .blend file 'buffer' (i.e. append them). + * + * Similar to #BKE_copybuffer_read, but also handles instantiation of collections/objects/etc. + * + * \param libname: Full path to the .blend file used as copy/paste buffer. + * \param flag: A combination of #eBLOLibLinkFlags and ##eFileSel_Params_Flag to control + * link/append behavior. + * \note: Ignores #FILE_LINK flag, since it always appends IDs. + * \param id_types_mask: Only directly link IDs of those types from the given .blend file buffer. + * + * \return Number of IDs directly pasted from the buffer (does not includes indirectly linked + * ones). */ int BKE_copybuffer_paste(bContext *C, const char *libname, - const short flag, + const int flag, ReportList *reports, const uint64_t id_types_mask) { diff --git a/source/blender/blenkernel/intern/blendfile_link_append.c b/source/blender/blenkernel/intern/blendfile_link_append.c new file mode 100644 index 00000000000..36f03990953 --- /dev/null +++ b/source/blender/blenkernel/intern/blendfile_link_append.c @@ -0,0 +1,1566 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup bke + * + * High level `.blend` file link/append code, + * including linking/appending several IDs from different libraries, handling instanciations of + * collections/objects/obdata in current scene. + */ + +#include <stdlib.h> +#include <string.h> + +#include "CLG_log.h" + +#include "MEM_guardedalloc.h" + +#include "DNA_ID.h" +#include "DNA_collection_types.h" +#include "DNA_key_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" + +#include "BLI_bitmap.h" +#include "BLI_blenlib.h" +#include "BLI_ghash.h" +#include "BLI_linklist.h" +#include "BLI_math.h" +#include "BLI_memarena.h" +#include "BLI_utildefines.h" + +#include "BLT_translation.h" + +#include "BKE_idtype.h" +#include "BKE_key.h" +#include "BKE_layer.h" +#include "BKE_lib_id.h" +#include "BKE_lib_override.h" +#include "BKE_lib_query.h" +#include "BKE_lib_remap.h" +#include "BKE_main.h" +#include "BKE_material.h" +#include "BKE_object.h" +#include "BKE_report.h" +#include "BKE_rigidbody.h" +#include "BKE_scene.h" + +#include "BKE_blendfile_link_append.h" + +#include "BLO_readfile.h" +#include "BLO_writefile.h" + +static CLG_LogRef LOG = {"bke.blendfile_link_append"}; + +/* -------------------------------------------------------------------- */ +/** \name Link/append context implementation and public management API. + * \{ */ + +typedef struct BlendfileLinkAppendContextItem { + /** Name of the ID (without the heading two-chars IDcode). */ + char *name; + /** All libs (from BlendfileLinkAppendContext.libraries) to try to load this ID from. */ + BLI_bitmap *libraries; + /** ID type. */ + short idcode; + + /** Type of action to perform on this item, and general status tag information. + * NOTE: Mostly used by append post-linking processing. */ + char action; + char tag; + + /** Newly linked ID (NULL until it has been successfully linked). */ + ID *new_id; + /** Library ID from which the #new_id has been linked (NULL until it has been successfully + * linked). */ + Library *source_library; + /** Opaque user data pointer. */ + void *userdata; +} BlendfileLinkAppendContextItem; + +/* A blendfile library entry in the `libraries` list of #BlendfileLinkAppendContext. */ +typedef struct BlendfileLinkAppendContextLibrary { + char *path; /* Absolute .blend file path. */ + BlendHandle *blo_handle; /* Blend file handle, if any. */ + bool blo_handle_is_owned; /* Whether the blend file handle is owned, or borrowed. */ + /* The blendfile report associated with the `blo_handle`, if owned. */ + BlendFileReadReport bf_reports; +} BlendfileLinkAppendContextLibrary; + +typedef struct BlendfileLinkAppendContext { + /** List of library paths to search IDs in. */ + LinkNodePair libraries; + /** List of all ID to try to link from #libraries. */ + LinkNodePair items; + int num_libraries; + int num_items; + /** Linking/appending parameters. Including bmain, scene, viewlayer and view3d. */ + LibraryLink_Params *params; + + /** Allows to easily find an existing items from an ID pointer. */ + GHash *new_id_to_item; + + /** Runtime info used by append code to manage re-use of already appended matching IDs. */ + GHash *library_weak_reference_mapping; + + /** Embedded blendfile and its size, if needed. */ + const void *blendfile_mem; + size_t blendfile_memsize; + + /** Internal 'private' data */ + MemArena *memarena; +} BlendfileLinkAppendContext; + +typedef struct BlendfileLinkAppendContextCallBack { + BlendfileLinkAppendContext *lapp_context; + BlendfileLinkAppendContextItem *item; + ReportList *reports; + +} BlendfileLinkAppendContextCallBack; + +/* Actions to apply to an item (i.e. linked ID). */ +enum { + LINK_APPEND_ACT_UNSET = 0, + LINK_APPEND_ACT_KEEP_LINKED, + LINK_APPEND_ACT_REUSE_LOCAL, + LINK_APPEND_ACT_MAKE_LOCAL, + LINK_APPEND_ACT_COPY_LOCAL, +}; + +/* Various status info about an item (i.e. linked ID). */ +enum { + /* An indirectly linked ID. */ + LINK_APPEND_TAG_INDIRECT = 1 << 0, +}; + +static BlendHandle *link_append_context_library_blohandle_ensure( + BlendfileLinkAppendContext *lapp_context, + BlendfileLinkAppendContextLibrary *lib_context, + ReportList *reports) +{ + if (reports != NULL) { + lib_context->bf_reports.reports = reports; + } + + char *libname = lib_context->path; + BlendHandle *blo_handle = lib_context->blo_handle; + if (blo_handle == NULL) { + if (STREQ(libname, BLO_EMBEDDED_STARTUP_BLEND)) { + blo_handle = BLO_blendhandle_from_memory(lapp_context->blendfile_mem, + (int)lapp_context->blendfile_memsize, + &lib_context->bf_reports); + } + else { + blo_handle = BLO_blendhandle_from_file(libname, &lib_context->bf_reports); + } + lib_context->blo_handle = blo_handle; + lib_context->blo_handle_is_owned = true; + } + + return blo_handle; +} + +static void link_append_context_library_blohandle_release( + BlendfileLinkAppendContext *UNUSED(lapp_context), + BlendfileLinkAppendContextLibrary *lib_context) +{ + if (lib_context->blo_handle_is_owned && lib_context->blo_handle != NULL) { + BLO_blendhandle_close(lib_context->blo_handle); + lib_context->blo_handle = NULL; + } +} + +/** Allocate and initialize a new context to link/append datablocks. + * + * \param flag a combination of #eFileSel_Params_Flag from DNA_space_types.h & #eBLOLibLinkFlags + * from BLO_readfile.h + */ +BlendfileLinkAppendContext *BKE_blendfile_link_append_context_new(LibraryLink_Params *params) +{ + MemArena *ma = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + BlendfileLinkAppendContext *lapp_context = BLI_memarena_calloc(ma, sizeof(*lapp_context)); + + lapp_context->params = params; + lapp_context->memarena = ma; + + return lapp_context; +} + +/** Free a link/append context. */ +void BKE_blendfile_link_append_context_free(BlendfileLinkAppendContext *lapp_context) +{ + if (lapp_context->new_id_to_item != NULL) { + BLI_ghash_free(lapp_context->new_id_to_item, NULL, NULL); + } + + for (LinkNode *liblink = lapp_context->libraries.list; liblink != NULL; + liblink = liblink->next) { + BlendfileLinkAppendContextLibrary *lib_context = liblink->link; + link_append_context_library_blohandle_release(lapp_context, lib_context); + } + + BLI_assert(lapp_context->library_weak_reference_mapping == NULL); + + BLI_memarena_free(lapp_context->memarena); +} + +/** Set or clear flags in given \a lapp_context. + * + * \param do_set Set the given \a flag if true, clear it otherwise. + */ +void BKE_blendfile_link_append_context_flag_set(BlendfileLinkAppendContext *lapp_context, + const int flag, + const bool do_set) +{ + if (do_set) { + lapp_context->params->flag |= flag; + } + else { + lapp_context->params->flag &= ~flag; + } +} + +/** Store reference to a Blender's embedded memfile into the context. + * + * \note This is required since embedded startup blender file is handled in `ED` module, which + * cannot be linked in BKE code. + */ +void BKE_blendfile_link_append_context_embedded_blendfile_set( + BlendfileLinkAppendContext *lapp_context, const void *blendfile_mem, int blendfile_memsize) +{ + BLI_assert_msg(lapp_context->blendfile_mem == NULL, + "Please explicitely clear reference to an embedded blender memfile before " + "setting a new one"); + lapp_context->blendfile_mem = blendfile_mem; + lapp_context->blendfile_memsize = (size_t)blendfile_memsize; +} + +/** Clear reference to Blender's embedded startup file into the context. */ +void BKE_blendfile_link_append_context_embedded_blendfile_clear( + BlendfileLinkAppendContext *lapp_context) +{ + lapp_context->blendfile_mem = NULL; + lapp_context->blendfile_memsize = 0; +} + +/** Add a new source library to search for items to be linked to the given link/append context. + * + * \param libname: the absolute path to the library blend file. + * \param blo_handle: the blend file handle of the library, NULL is not available. Note that this + * is only borrowed for linking purpose, no releasing or other management will + * be performed by #BKE_blendfile_link_append code on it. + * + * \note *Never* call BKE_blendfile_link_append_context_library_add() after having added some + * items. */ +void BKE_blendfile_link_append_context_library_add(BlendfileLinkAppendContext *lapp_context, + const char *libname, + BlendHandle *blo_handle) +{ + BLI_assert(lapp_context->items.list == NULL); + + BlendfileLinkAppendContextLibrary *lib_context = BLI_memarena_calloc(lapp_context->memarena, + sizeof(*lib_context)); + + size_t len = strlen(libname) + 1; + char *libpath = BLI_memarena_alloc(lapp_context->memarena, len); + BLI_strncpy(libpath, libname, len); + + lib_context->path = libpath; + lib_context->blo_handle = blo_handle; + lib_context->blo_handle_is_owned = (blo_handle == NULL); + + BLI_linklist_append_arena(&lapp_context->libraries, lib_context, lapp_context->memarena); + lapp_context->num_libraries++; +} + +/** Add a new item (datablock name and idcode) to be searched and linked/appended from libraries + * associated to the given context. + * + * \param userdata: an opaque user-data pointer stored in generated link/append item. */ +BlendfileLinkAppendContextItem *BKE_blendfile_link_append_context_item_add( + BlendfileLinkAppendContext *lapp_context, + const char *idname, + const short idcode, + void *userdata) +{ + BlendfileLinkAppendContextItem *item = BLI_memarena_calloc(lapp_context->memarena, + sizeof(*item)); + size_t len = strlen(idname) + 1; + + item->name = BLI_memarena_alloc(lapp_context->memarena, len); + BLI_strncpy(item->name, idname, len); + item->idcode = idcode; + item->libraries = BLI_BITMAP_NEW_MEMARENA(lapp_context->memarena, lapp_context->num_libraries); + + item->new_id = NULL; + item->action = LINK_APPEND_ACT_UNSET; + item->userdata = userdata; + + BLI_linklist_append_arena(&lapp_context->items, item, lapp_context->memarena); + lapp_context->num_items++; + + return item; +} + +/** Enable search of the given \a item into the library stored at given index in the link/append + * context. */ +void BKE_blendfile_link_append_context_item_library_index_enable( + BlendfileLinkAppendContext *UNUSED(lapp_context), + BlendfileLinkAppendContextItem *item, + const int library_index) +{ + BLI_BITMAP_ENABLE(item->libraries, library_index); +} + +/** Check if given link/append context is empty (has no items to process) or not. */ +bool BKE_blendfile_link_append_context_is_empty(struct BlendfileLinkAppendContext *lapp_context) +{ + return lapp_context->num_items == 0; +} + +void *BKE_blendfile_link_append_context_item_userdata_get( + BlendfileLinkAppendContext *UNUSED(lapp_context), BlendfileLinkAppendContextItem *item) +{ + return item->userdata; +} + +ID *BKE_blendfile_link_append_context_item_newid_get( + BlendfileLinkAppendContext *UNUSED(lapp_context), BlendfileLinkAppendContextItem *item) +{ + return item->new_id; +} + +short BKE_blendfile_link_append_context_item_idcode_get( + struct BlendfileLinkAppendContext *UNUSED(lapp_context), + struct BlendfileLinkAppendContextItem *item) +{ + return item->idcode; +} + +/** Iterate over all (or a subset) of the items listed in given #BlendfileLinkAppendContext, and + * call the `callback_function` on them. + * + * \param flag: Control which type of items to process (see + * #eBlendfileLinkAppendForeachItemFlag enum flags). + * \param userdata: An opaque void pointer passed to the `callback_function`. + */ +void BKE_blendfile_link_append_context_item_foreach( + struct BlendfileLinkAppendContext *lapp_context, + BKE_BlendfileLinkAppendContexteItemFunction callback_function, + const eBlendfileLinkAppendForeachItemFlag flag, + void *userdata) +{ + for (LinkNode *itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + + if ((flag & BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_DIRECT) == 0 && + (item->tag & LINK_APPEND_TAG_INDIRECT) == 0) { + continue; + } + if ((flag & BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_INDIRECT) == 0 && + (item->tag & LINK_APPEND_TAG_INDIRECT) != 0) { + continue; + } + + if (!callback_function(lapp_context, item, userdata)) { + break; + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Library link/append helper functions. + * + * \{ */ + +/* Struct gathering all required data to handle instantiation of loose data-blocks. */ +typedef struct LooseDataInstantiateContext { + BlendfileLinkAppendContext *lapp_context; + + /* The collection in which to add loose collections/objects. */ + Collection *active_collection; +} LooseDataInstantiateContext; + +static bool object_in_any_scene(Main *bmain, Object *ob) +{ + LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) { + if (BKE_scene_object_find(sce, ob)) { + return true; + } + } + + return false; +} + +static bool object_in_any_collection(Main *bmain, Object *ob) +{ + LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { + if (BKE_collection_has_object(collection, ob)) { + return true; + } + } + + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + if (scene->master_collection != NULL && + BKE_collection_has_object(scene->master_collection, ob)) { + return true; + } + } + + return false; +} + +static ID *loose_data_instantiate_process_check(LooseDataInstantiateContext *instantiate_context, + BlendfileLinkAppendContextItem *item) +{ + BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context; + /* In linking case, we always want to handle instantiation. */ + if (lapp_context->params->flag & FILE_LINK) { + return item->new_id; + } + + /* We consider that if we either kept it linked, or re-used already local data, instantiation + * status of those should not be modified. */ + if (!ELEM(item->action, LINK_APPEND_ACT_COPY_LOCAL, LINK_APPEND_ACT_MAKE_LOCAL)) { + return NULL; + } + + ID *id = item->new_id; + if (id == NULL) { + return NULL; + } + + if (item->action == LINK_APPEND_ACT_COPY_LOCAL) { + BLI_assert(ID_IS_LINKED(id)); + id = id->newid; + if (id == NULL) { + return NULL; + } + + BLI_assert(!ID_IS_LINKED(id)); + return id; + } + + BLI_assert(!ID_IS_LINKED(id)); + return id; +} + +static void loose_data_instantiate_ensure_active_collection( + LooseDataInstantiateContext *instantiate_context) +{ + + BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context; + Main *bmain = instantiate_context->lapp_context->params->bmain; + Scene *scene = instantiate_context->lapp_context->params->context.scene; + ViewLayer *view_layer = instantiate_context->lapp_context->params->context.view_layer; + + /* Find or add collection as needed. */ + if (instantiate_context->active_collection == NULL) { + if (lapp_context->params->flag & FILE_ACTIVE_COLLECTION) { + LayerCollection *lc = BKE_layer_collection_get_active(view_layer); + instantiate_context->active_collection = lc->collection; + } + else { + if (lapp_context->params->flag & FILE_LINK) { + instantiate_context->active_collection = BKE_collection_add( + bmain, scene->master_collection, DATA_("Linked Data")); + } + else { + instantiate_context->active_collection = BKE_collection_add( + bmain, scene->master_collection, DATA_("Appended Data")); + } + } + } +} + +static void loose_data_instantiate_object_base_instance_init(Main *bmain, + Collection *collection, + Object *ob, + ViewLayer *view_layer, + const View3D *v3d, + const int flag, + bool set_active) +{ + /* Auto-select and appending. */ + if ((flag & FILE_AUTOSELECT) && ((flag & FILE_LINK) == 0)) { + /* While in general the object should not be manipulated, + * when the user requests the object to be selected, ensure it's visible and selectable. */ + ob->visibility_flag &= ~(OB_HIDE_VIEWPORT | OB_HIDE_SELECT); + } + + BKE_collection_object_add(bmain, collection, ob); + + Base *base = BKE_view_layer_base_find(view_layer, ob); + + if (v3d != NULL) { + base->local_view_bits |= v3d->local_view_uuid; + } + + if (flag & FILE_AUTOSELECT) { + /* All objects that use #FILE_AUTOSELECT must be selectable (unless linking data). */ + BLI_assert((base->flag & BASE_SELECTABLE) || (flag & FILE_LINK)); + if (base->flag & BASE_SELECTABLE) { + base->flag |= BASE_SELECTED; + } + } + + if (set_active) { + view_layer->basact = base; + } + + BKE_scene_object_base_flag_sync_from_base(base); +} + +/* Tag obdata that actually need to be instantiated (those referenced by an object do not, since + * the object will be instantiated instaed if needed. */ +static void loose_data_instantiate_obdata_preprocess( + LooseDataInstantiateContext *instantiate_context) +{ + BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context; + LinkNode *itemlink; + + /* First pass on obdata to enable their instantiation by default, then do a second pass on + * objects to clear it for any obdata already in use. */ + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = loose_data_instantiate_process_check(instantiate_context, item); + if (id == NULL) { + continue; + } + const ID_Type idcode = GS(id->name); + if (!OB_DATA_SUPPORT_ID(idcode)) { + continue; + } + + id->tag |= LIB_TAG_DOIT; + } + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = item->new_id; + if (id == NULL || GS(id->name) != ID_OB) { + continue; + } + + Object *ob = (Object *)id; + Object *new_ob = (Object *)id->newid; + if (ob->data != NULL) { + ((ID *)(ob->data))->tag &= ~LIB_TAG_DOIT; + } + if (new_ob != NULL && new_ob->data != NULL) { + ((ID *)(new_ob->data))->tag &= ~LIB_TAG_DOIT; + } + } +} + +static void loose_data_instantiate_collection_process( + LooseDataInstantiateContext *instantiate_context) +{ + BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context; + Main *bmain = lapp_context->params->bmain; + Scene *scene = lapp_context->params->context.scene; + ViewLayer *view_layer = lapp_context->params->context.view_layer; + const View3D *v3d = lapp_context->params->context.v3d; + + /* NOTE: For collections we only view_layer-instantiate duplicated collections that have + * non-instantiated objects in them. */ + LinkNode *itemlink; + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = loose_data_instantiate_process_check(instantiate_context, item); + if (id == NULL || GS(id->name) != ID_GR) { + continue; + } + + /* We do not want to force instantiation of indirectly appended collections. Users can now + * easily instantiate collections (and their objects) as needed by themselves. See T67032. */ + /* We need to check that objects in that collections are already instantiated in a scene. + * Otherwise, it's better to add the collection to the scene's active collection, than to + * instantiate its objects in active scene's collection directly. See T61141. + * + * NOTE: We only check object directly into that collection, not recursively into its + * children. + */ + Collection *collection = (Collection *)id; + /* We always add collections directly selected by the user. */ + bool do_add_collection = (item->tag & LINK_APPEND_TAG_INDIRECT) == 0; + if (!do_add_collection) { + LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) { + Object *ob = coll_ob->ob; + if (!object_in_any_scene(bmain, ob)) { + do_add_collection = true; + break; + } + } + } + if (!do_add_collection) { + continue; + } + + loose_data_instantiate_ensure_active_collection(instantiate_context); + Collection *active_collection = instantiate_context->active_collection; + + /* In case user requested instantiation of collections as empties, we do so for the one they + * explicitly selected (originally directly linked IDs) only. */ + if ((lapp_context->params->flag & BLO_LIBLINK_COLLECTION_INSTANCE) != 0 && + (item->tag & LINK_APPEND_TAG_INDIRECT) == 0) { + /* BKE_object_add(...) messes with the selection. */ + Object *ob = BKE_object_add_only_object(bmain, OB_EMPTY, collection->id.name + 2); + ob->type = OB_EMPTY; + ob->empty_drawsize = U.collection_instance_empty_size; + + const bool set_selected = (lapp_context->params->flag & FILE_AUTOSELECT) != 0; + /* TODO: why is it OK to make this active here but not in other situations? + * See other callers of #object_base_instance_init */ + const bool set_active = set_selected; + loose_data_instantiate_object_base_instance_init( + bmain, active_collection, ob, view_layer, v3d, lapp_context->params->flag, set_active); + + /* Assign the collection. */ + ob->instance_collection = collection; + id_us_plus(&collection->id); + ob->transflag |= OB_DUPLICOLLECTION; + copy_v3_v3(ob->loc, scene->cursor.location); + } + else { + /* Add collection as child of active collection. */ + BKE_collection_child_add(bmain, active_collection, collection); + + if ((lapp_context->params->flag & FILE_AUTOSELECT) != 0) { + LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) { + Object *ob = coll_ob->ob; + Base *base = BKE_view_layer_base_find(view_layer, ob); + if (base) { + base->flag |= BASE_SELECTED; + BKE_scene_object_base_flag_sync_from_base(base); + } + } + } + } + } +} + +static void loose_data_instantiate_object_process(LooseDataInstantiateContext *instantiate_context) +{ + BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context; + Main *bmain = lapp_context->params->bmain; + ViewLayer *view_layer = lapp_context->params->context.view_layer; + const View3D *v3d = lapp_context->params->context.v3d; + + /* Do NOT make base active here! screws up GUI stuff, + * if you want it do it at the editor level. */ + const bool object_set_active = false; + + /* NOTE: For objects we only view_layer-instantiate duplicated objects that are not yet used + * anywhere. */ + LinkNode *itemlink; + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = loose_data_instantiate_process_check(instantiate_context, item); + if (id == NULL || GS(id->name) != ID_OB) { + continue; + } + + Object *ob = (Object *)id; + + if (object_in_any_collection(bmain, ob)) { + continue; + } + + loose_data_instantiate_ensure_active_collection(instantiate_context); + Collection *active_collection = instantiate_context->active_collection; + + CLAMP_MIN(ob->id.us, 0); + ob->mode = OB_MODE_OBJECT; + + loose_data_instantiate_object_base_instance_init(bmain, + active_collection, + ob, + view_layer, + v3d, + lapp_context->params->flag, + object_set_active); + } +} + +static void loose_data_instantiate_obdata_process(LooseDataInstantiateContext *instantiate_context) +{ + BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context; + Main *bmain = lapp_context->params->bmain; + Scene *scene = lapp_context->params->context.scene; + ViewLayer *view_layer = lapp_context->params->context.view_layer; + const View3D *v3d = lapp_context->params->context.v3d; + + /* Do NOT make base active here! screws up GUI stuff, + * if you want it do it at the editor level. */ + const bool object_set_active = false; + + LinkNode *itemlink; + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = loose_data_instantiate_process_check(instantiate_context, item); + if (id == NULL) { + continue; + } + const ID_Type idcode = GS(id->name); + if (!OB_DATA_SUPPORT_ID(idcode)) { + continue; + } + if ((id->tag & LIB_TAG_DOIT) == 0) { + continue; + } + + loose_data_instantiate_ensure_active_collection(instantiate_context); + Collection *active_collection = instantiate_context->active_collection; + + const int type = BKE_object_obdata_to_type(id); + BLI_assert(type != -1); + Object *ob = BKE_object_add_only_object(bmain, type, id->name + 2); + ob->data = id; + id_us_plus(id); + BKE_object_materials_test(bmain, ob, ob->data); + + loose_data_instantiate_object_base_instance_init(bmain, + active_collection, + ob, + view_layer, + v3d, + lapp_context->params->flag, + object_set_active); + + copy_v3_v3(ob->loc, scene->cursor.location); + + id->tag &= ~LIB_TAG_DOIT; + } +} + +static void loose_data_instantiate_object_rigidbody_postprocess( + LooseDataInstantiateContext *instantiate_context) +{ + BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context; + Main *bmain = lapp_context->params->bmain; + + LinkNode *itemlink; + /* Add rigid body objects and constraints to current RB world(s). */ + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = loose_data_instantiate_process_check(instantiate_context, item); + if (id == NULL || GS(id->name) != ID_OB) { + continue; + } + BKE_rigidbody_ensure_local_object(bmain, (Object *)id); + } +} + +static void loose_data_instantiate(LooseDataInstantiateContext *instantiate_context) +{ + if (instantiate_context->lapp_context->params->context.scene == NULL) { + /* In some cases, like the asset drag&drop e.g., the caller code manages instantiation itself. + */ + return; + } + + BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context; + const bool do_obdata = (lapp_context->params->flag & BLO_LIBLINK_OBDATA_INSTANCE) != 0; + + /* First pass on obdata to enable their instantiation by default, then do a second pass on + * objects to clear it for any obdata already in use. */ + if (do_obdata) { + loose_data_instantiate_obdata_preprocess(instantiate_context); + } + + /* First do collections, then objects, then obdata. */ + loose_data_instantiate_collection_process(instantiate_context); + loose_data_instantiate_object_process(instantiate_context); + if (do_obdata) { + loose_data_instantiate_obdata_process(instantiate_context); + } + + loose_data_instantiate_object_rigidbody_postprocess(instantiate_context); +} + +static void new_id_to_item_mapping_add(BlendfileLinkAppendContext *lapp_context, + ID *id, + BlendfileLinkAppendContextItem *item) +{ + BLI_ghash_insert(lapp_context->new_id_to_item, id, item); + + /* This ensures that if a liboverride reference is also linked/used by some other appended + * data, it gets a local copy instead of being made directly local, so that the liboverride + * references remain valid (i.e. linked data). */ + if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + id->override_library->reference->tag |= LIB_TAG_PRE_EXISTING; + } +} + +/* Generate a mapping between newly linked IDs and their items, and tag linked IDs used as + * liboverride references as already existing. */ +static void new_id_to_item_mapping_create(BlendfileLinkAppendContext *lapp_context) +{ + lapp_context->new_id_to_item = BLI_ghash_new( + BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); + for (LinkNode *itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = item->new_id; + if (id == NULL) { + continue; + } + + new_id_to_item_mapping_add(lapp_context, id, item); + } +} + +static int foreach_libblock_link_append_callback(LibraryIDLinkCallbackData *cb_data) +{ + /* NOTE: It is important to also skip liboverride references here, as those should never be made + * local. */ + if (cb_data->cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_INTERNAL | IDWALK_CB_LOOPBACK | + IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) { + return IDWALK_RET_NOP; + } + + BlendfileLinkAppendContextCallBack *data = cb_data->user_data; + ID *id = *cb_data->id_pointer; + + if (id == NULL) { + return IDWALK_RET_NOP; + } + + if (!BKE_idtype_idcode_is_linkable(GS(id->name))) { + /* While we do not want to add non-linkable ID (shape keys...) to the list of linked items, + * unfortunately they can use fully linkable valid IDs too, like actions. Those need to be + * processed, so we need to recursively deal with them here. */ + /* NOTE: Since we are by-passing checks in `BKE_library_foreach_ID_link` by manually calling it + * recursively, we need to take care of potential recursion cases ourselves (e.g.animdata of + * shapekey referencing the shapekey itself). */ + if (id != cb_data->id_self) { + BKE_library_foreach_ID_link( + cb_data->bmain, id, foreach_libblock_link_append_callback, data, IDWALK_NOP); + } + return IDWALK_RET_NOP; + } + + /* In linking case, we always consider all linked IDs, even indirectly ones, for instantiation, + * so we need to add them all to the items list. + * + * In appending case, when `do_recursive` is false, we only make local IDs from same + * library(-ies) as the initially directly linked ones. + * + * NOTE: Since in append case, linked IDs are also fully skipped during instantiation step (see + * #append_loose_data_instantiate_process_check), we can avoid adding them to the items list + * completely. */ + const bool do_link = (data->lapp_context->params->flag & FILE_LINK) != 0; + const bool do_recursive = (data->lapp_context->params->flag & BLO_LIBLINK_APPEND_RECURSIVE) != + 0 || + do_link; + if (!do_recursive && cb_data->id_owner->lib != id->lib) { + return IDWALK_RET_NOP; + } + + BlendfileLinkAppendContextItem *item = BLI_ghash_lookup(data->lapp_context->new_id_to_item, id); + if (item == NULL) { + item = BKE_blendfile_link_append_context_item_add( + data->lapp_context, id->name, GS(id->name), NULL); + item->new_id = id; + item->source_library = id->lib; + /* Since we did not have an item for that ID yet, we know user did not selected it explicitly, + * it was rather linked indirectly. This info is important for instantiation of collections. */ + item->tag |= LINK_APPEND_TAG_INDIRECT; + /* In linking case we already know what we want to do with those items. */ + if (do_link) { + item->action = LINK_APPEND_ACT_KEEP_LINKED; + } + new_id_to_item_mapping_add(data->lapp_context, id, item); + } + + /* NOTE: currently there is no need to do anything else here, but in the future this would be + * the place to add specific per-usage decisions on how to append an ID. */ + + return IDWALK_RET_NOP; +} + +/** \} */ + +/** \name Library link/append code. + * \{ */ + +/* Perform append operation, using modern ID usage looper to detect which ID should be kept linked, + * made local, duplicated as local, re-used from local etc. + * + * TODO: Expose somehow this logic to the two other parts of code performing actual append + * (i.e. copy/paste and `bpy` link/append API). + * Then we can heavily simplify #BKE_library_make_local(). */ +void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *reports) +{ + Main *bmain = lapp_context->params->bmain; + + BLI_assert((lapp_context->params->flag & FILE_LINK) == 0); + + const bool set_fakeuser = (lapp_context->params->flag & BLO_LIBLINK_APPEND_SET_FAKEUSER) != 0; + const bool do_reuse_local_id = (lapp_context->params->flag & + BLO_LIBLINK_APPEND_LOCAL_ID_REUSE) != 0; + + const int make_local_common_flags = LIB_ID_MAKELOCAL_FULL_LIBRARY | + ((lapp_context->params->flag & + BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR) != 0 ? + LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR : + 0); + + LinkNode *itemlink; + + new_id_to_item_mapping_create(lapp_context); + lapp_context->library_weak_reference_mapping = BKE_main_library_weak_reference_create(bmain); + + /* NOTE: Since we append items for IDs not already listed (i.e. implicitly linked indirect + * dependencies), this list will grow and we will process those IDs later, leading to a flatten + * recursive processing of all the linked dependencies. */ + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = item->new_id; + if (id == NULL) { + continue; + } + BLI_assert(item->userdata == NULL); + + /* Linked IDs should never be marked as needing post-processing (instantiation of loose + * objects etc.). + * NOTE: This is dev test check, can be removed once we get rid of instantiation code in BLO + * completely.*/ + BLI_assert((id->tag & LIB_TAG_DOIT) == 0); + + ID *existing_local_id = BKE_idtype_idcode_append_is_reusable(GS(id->name)) ? + BKE_main_library_weak_reference_search_item( + lapp_context->library_weak_reference_mapping, + id->lib->filepath, + id->name) : + NULL; + + if (item->action != LINK_APPEND_ACT_UNSET) { + /* Already set, pass. */ + } + if (GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) { + CLOG_INFO(&LOG, 3, "Appended ID '%s' is proxified, keeping it linked...", id->name); + item->action = LINK_APPEND_ACT_KEEP_LINKED; + } + else if (do_reuse_local_id && existing_local_id != NULL) { + CLOG_INFO(&LOG, 3, "Appended ID '%s' as a matching local one, re-using it...", id->name); + item->action = LINK_APPEND_ACT_REUSE_LOCAL; + item->userdata = existing_local_id; + } + else if (id->tag & LIB_TAG_PRE_EXISTING) { + CLOG_INFO(&LOG, 3, "Appended ID '%s' was already linked, need to copy it...", id->name); + item->action = LINK_APPEND_ACT_COPY_LOCAL; + } + else { + CLOG_INFO(&LOG, 3, "Appended ID '%s' will be made local...", id->name); + item->action = LINK_APPEND_ACT_MAKE_LOCAL; + } + + /* Only check dependencies if we are not keeping linked data, nor re-using existing local data. + */ + if (!ELEM(item->action, LINK_APPEND_ACT_KEEP_LINKED, LINK_APPEND_ACT_REUSE_LOCAL)) { + BlendfileLinkAppendContextCallBack cb_data = { + .lapp_context = lapp_context, .item = item, .reports = reports}; + BKE_library_foreach_ID_link( + bmain, id, foreach_libblock_link_append_callback, &cb_data, IDWALK_NOP); + } + + /* If we found a matching existing local id but are not re-using it, we need to properly clear + * its weak reference to linked data. */ + if (existing_local_id != NULL && + !ELEM(item->action, LINK_APPEND_ACT_KEEP_LINKED, LINK_APPEND_ACT_REUSE_LOCAL)) { + BKE_main_library_weak_reference_remove_item(lapp_context->library_weak_reference_mapping, + id->lib->filepath, + id->name, + existing_local_id); + } + } + + /* Effectively perform required operation on every linked ID. */ + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = item->new_id; + if (id == NULL) { + continue; + } + + ID *local_appended_new_id = NULL; + char lib_filepath[FILE_MAX]; + BLI_strncpy(lib_filepath, id->lib->filepath, sizeof(lib_filepath)); + char lib_id_name[MAX_ID_NAME]; + BLI_strncpy(lib_id_name, id->name, sizeof(lib_id_name)); + + switch (item->action) { + case LINK_APPEND_ACT_COPY_LOCAL: + BKE_lib_id_make_local(bmain, id, make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_COPY); + local_appended_new_id = id->newid; + break; + case LINK_APPEND_ACT_MAKE_LOCAL: + BKE_lib_id_make_local(bmain, + id, + make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_LOCAL | + LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING); + BLI_assert(id->newid == NULL); + local_appended_new_id = id; + break; + case LINK_APPEND_ACT_KEEP_LINKED: + /* Nothing to do here. */ + break; + case LINK_APPEND_ACT_REUSE_LOCAL: + /* We only need to set `newid` to ID found in previous loop, for proper remapping. */ + ID_NEW_SET(id, item->userdata); + /* This is not a 'new' local appended id, do not set `local_appended_new_id` here. */ + break; + case LINK_APPEND_ACT_UNSET: + CLOG_ERROR( + &LOG, "Unexpected unset append action for '%s' ID, assuming 'keep link'", id->name); + break; + default: + BLI_assert(0); + } + + if (local_appended_new_id != NULL) { + if (BKE_idtype_idcode_append_is_reusable(GS(local_appended_new_id->name))) { + BKE_main_library_weak_reference_add_item(lapp_context->library_weak_reference_mapping, + lib_filepath, + lib_id_name, + 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); + } + } + } + } + + BKE_main_library_weak_reference_destroy(lapp_context->library_weak_reference_mapping); + lapp_context->library_weak_reference_mapping = NULL; + + /* Remap IDs as needed. */ + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + + if (item->action == LINK_APPEND_ACT_KEEP_LINKED) { + continue; + } + + ID *id = item->new_id; + if (id == NULL) { + continue; + } + if (ELEM(item->action, LINK_APPEND_ACT_COPY_LOCAL, LINK_APPEND_ACT_REUSE_LOCAL)) { + BLI_assert(ID_IS_LINKED(id)); + id = id->newid; + if (id == NULL) { + continue; + } + } + + BLI_assert(!ID_IS_LINKED(id)); + + BKE_libblock_relink_to_newid(bmain, id, 0); + } + + /* Remove linked IDs when a local existing data has been reused instead. */ + BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + + if (item->action != LINK_APPEND_ACT_REUSE_LOCAL) { + continue; + } + + ID *id = item->new_id; + if (id == NULL) { + continue; + } + BLI_assert(ID_IS_LINKED(id)); + BLI_assert(id->newid != NULL); + + id->tag |= LIB_TAG_DOIT; + item->new_id = id->newid; + } + BKE_id_multi_tagged_delete(bmain); + + /* Instantiate newly created (duplicated) IDs as needed. */ + LooseDataInstantiateContext instantiate_context = {.lapp_context = lapp_context, + .active_collection = NULL}; + loose_data_instantiate(&instantiate_context); + + /* Attempt to deal with object proxies. + * + * NOTE: Copied from `BKE_library_make_local`, but this is not really working (as in, not + * producing any useful result in any known use case), neither here nor in + * `BKE_library_make_local` currently. + * Proxies are end of life anyway, so not worth spending time on this. */ + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + + if (item->action != LINK_APPEND_ACT_COPY_LOCAL) { + continue; + } + + ID *id = item->new_id; + if (id == NULL) { + continue; + } + BLI_assert(ID_IS_LINKED(id)); + + /* Attempt to re-link copied proxy objects. This allows appending of an entire scene + * from another blend file into this one, even when that blend file contains proxified + * armatures that have local references. Since the proxified object needs to be linked + * (not local), this will only work when the "Localize all" checkbox is disabled. + * TL;DR: this is a dirty hack on top of an already weak feature (proxies). */ + if (GS(id->name) == ID_OB && ((Object *)id)->proxy != NULL) { + Object *ob = (Object *)id; + Object *ob_new = (Object *)id->newid; + bool is_local = false, is_lib = false; + + /* Proxies only work when the proxified object is linked-in from a library. */ + if (!ID_IS_LINKED(ob->proxy)) { + CLOG_WARN(&LOG, + "Proxy object %s will lose its link to %s, because the " + "proxified object is local", + id->newid->name, + ob->proxy->id.name); + continue; + } + + BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib); + + /* We can only switch the proxy'ing to a made-local proxy if it is no longer + * referred to from a library. Not checking for local use; if new local proxy + * was not used locally would be a nasty bug! */ + if (is_local || is_lib) { + CLOG_WARN(&LOG, + "Made-local proxy object %s will lose its link to %s, " + "because the linked-in proxy is referenced (is_local=%i, is_lib=%i)", + id->newid->name, + ob->proxy->id.name, + is_local, + is_lib); + } + else { + /* we can switch the proxy'ing from the linked-in to the made-local proxy. + * BKE_object_make_proxy() shouldn't be used here, as it allocates memory that + * was already allocated by object_make_local() (which called BKE_object_copy). */ + ob_new->proxy = ob->proxy; + ob_new->proxy_group = ob->proxy_group; + ob_new->proxy_from = ob->proxy_from; + ob_new->proxy->proxy_from = ob_new; + ob->proxy = ob->proxy_from = ob->proxy_group = NULL; + } + } + } + + BKE_main_id_newptr_and_tag_clear(bmain); +} + +void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *reports) +{ + Main *mainl; + Library *lib; + + LinkNode *liblink, *itemlink; + int lib_idx, item_idx; + + BLI_assert(lapp_context->num_items && lapp_context->num_libraries); + + for (lib_idx = 0, liblink = lapp_context->libraries.list; liblink; + lib_idx++, liblink = liblink->next) { + BlendfileLinkAppendContextLibrary *lib_context = liblink->link; + char *libname = lib_context->path; + BlendHandle *blo_handle = link_append_context_library_blohandle_ensure( + lapp_context, lib_context, reports); + + if (blo_handle == NULL) { + /* Unlikely since we just browsed it, but possible + * Error reports will have been made by BLO_blendhandle_from_file() */ + continue; + } + + /* here appending/linking starts */ + + /* NOTE: This is temporary hotfix until whole code using link/append features has been moved to + * use new BKE code. */ + /* Do not handle instantiation in linking process anymore, we do it here in + * #loose_data_instantiate instead. */ + lapp_context->params->flag &= ~BLO_LIBLINK_NEEDS_ID_TAG_DOIT; + + mainl = BLO_library_link_begin(&blo_handle, libname, lapp_context->params); + lib = mainl->curlib; + BLI_assert(lib); + UNUSED_VARS_NDEBUG(lib); + + if (mainl->versionfile < 250) { + BKE_reportf(reports, + RPT_WARNING, + "Linking or appending from a very old .blend file format (%d.%d), no animation " + "conversion will " + "be done! You may want to re-save your lib file with current Blender", + mainl->versionfile, + mainl->subversionfile); + } + + /* For each lib file, we try to link all items belonging to that lib, + * and tag those successful to not try to load them again with the other libs. */ + for (item_idx = 0, itemlink = lapp_context->items.list; itemlink; + item_idx++, itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *new_id; + + if (!BLI_BITMAP_TEST(item->libraries, lib_idx)) { + continue; + } + + new_id = BLO_library_link_named_part( + mainl, &blo_handle, item->idcode, item->name, lapp_context->params); + + if (new_id) { + /* If the link is successful, clear item's libs 'todo' flags. + * This avoids trying to link same item with other libraries to come. */ + BLI_bitmap_set_all(item->libraries, false, lapp_context->num_libraries); + item->new_id = new_id; + item->source_library = new_id->lib; + } + } + + BLO_library_link_end(mainl, &blo_handle, lapp_context->params); + link_append_context_library_blohandle_release(lapp_context, lib_context); + } + + /* Instantiate newly linked IDs as needed, if no append is scheduled. */ + if ((lapp_context->params->flag & FILE_LINK) != 0 && + lapp_context->params->context.scene != NULL) { + new_id_to_item_mapping_create(lapp_context); + /* NOTE: Since we append items for IDs not already listed (i.e. implicitly linked indirect + * dependencies), this list will grow and we will process those IDs later, leading to a flatten + * recursive processing of all the linked dependencies. */ + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = item->new_id; + if (id == NULL) { + continue; + } + BLI_assert(item->userdata == NULL); + + /* Linked IDs should never be marked as needing post-processing (instantiation of loose + * objects etc.). + * NOTE: This is dev test check, can be removed once we get rid of instantiation code in BLO + * completely.*/ + BLI_assert((id->tag & LIB_TAG_DOIT) == 0); + + BlendfileLinkAppendContextCallBack cb_data = { + .lapp_context = lapp_context, .item = item, .reports = reports}; + BKE_library_foreach_ID_link(lapp_context->params->bmain, + id, + foreach_libblock_link_append_callback, + &cb_data, + IDWALK_NOP); + } + + LooseDataInstantiateContext instantiate_context = {.lapp_context = lapp_context, + .active_collection = NULL}; + loose_data_instantiate(&instantiate_context); + } +} + +/** \} */ + +/** \name Library relocating code. + * \{ */ + +static void blendfile_library_relocate_remap(Main *bmain, + ID *old_id, + ID *new_id, + ReportList *reports, + const bool do_reload, + const short remap_flags) +{ + BLI_assert(old_id); + if (do_reload) { + /* Since we asked for placeholders in case of missing IDs, + * we expect to always get a valid one. */ + BLI_assert(new_id); + } + if (new_id) { + CLOG_INFO(&LOG, + 4, + "Before remap of %s, old_id users: %d, new_id users: %d", + old_id->name, + old_id->us, + new_id->us); + BKE_libblock_remap_locked(bmain, old_id, new_id, remap_flags); + + if (old_id->flag & LIB_FAKEUSER) { + id_fake_user_clear(old_id); + id_fake_user_set(new_id); + } + + CLOG_INFO(&LOG, + 4, + "After remap of %s, old_id users: %d, new_id users: %d", + old_id->name, + old_id->us, + new_id->us); + + /* In some cases, new_id might become direct link, remove parent of library in this case. */ + if (new_id->lib->parent && (new_id->tag & LIB_TAG_INDIRECT) == 0) { + if (do_reload) { + BLI_assert_unreachable(); /* Should not happen in 'pure' reload case... */ + } + new_id->lib->parent = NULL; + } + } + + if (old_id->us > 0 && new_id && old_id->lib == new_id->lib) { + /* Note that this *should* not happen - but better be safe than sorry in this area, + * at least until we are 100% sure this cannot ever happen. + * Also, we can safely assume names were unique so far, + * so just replacing '.' by '~' should work, + * but this does not totally rules out the possibility of name collision. */ + size_t len = strlen(old_id->name); + size_t dot_pos; + bool has_num = false; + + for (dot_pos = len; dot_pos--;) { + char c = old_id->name[dot_pos]; + if (c == '.') { + break; + } + if (c < '0' || c > '9') { + has_num = false; + break; + } + has_num = true; + } + + if (has_num) { + old_id->name[dot_pos] = '~'; + } + else { + len = MIN2(len, MAX_ID_NAME - 7); + BLI_strncpy(&old_id->name[len], "~000", 7); + } + + id_sort_by_name(which_libbase(bmain, GS(old_id->name)), old_id, NULL); + + BKE_reportf( + reports, + RPT_WARNING, + "Lib Reload: Replacing all references to old data-block '%s' by reloaded one failed, " + "old one (%d remaining users) had to be kept and was renamed to '%s'", + new_id->name, + old_id->us, + old_id->name); + } +} + +void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context, + ReportList *reports, + Library *library, + const bool do_reload) +{ + ListBase *lbarray[INDEX_ID_MAX]; + int lba_idx; + + LinkNode *itemlink; + int item_idx; + + Main *bmain = lapp_context->params->bmain; + + /* Remove all IDs to be reloaded from Main. */ + lba_idx = set_listbasepointers(bmain, lbarray); + while (lba_idx--) { + ID *id = lbarray[lba_idx]->first; + const short idcode = id ? GS(id->name) : 0; + + if (!id || !BKE_idtype_idcode_is_linkable(idcode)) { + /* No need to reload non-linkable datatypes, + * those will get relinked with their 'users ID'. */ + continue; + } + + for (; id; id = id->next) { + if (id->lib == library) { + BlendfileLinkAppendContextItem *item; + + /* We remove it from current Main, and add it to items to link... */ + /* Note that non-linkable IDs (like e.g. shapekeys) are also explicitly linked here... */ + BLI_remlink(lbarray[lba_idx], id); + /* Usual special code for ShapeKeys snowflakes... */ + Key *old_key = BKE_key_from_id(id); + if (old_key != NULL) { + BLI_remlink(which_libbase(bmain, GS(old_key->id.name)), &old_key->id); + } + + item = BKE_blendfile_link_append_context_item_add(lapp_context, id->name + 2, idcode, id); + BLI_bitmap_set_all(item->libraries, true, (size_t)lapp_context->num_libraries); + + CLOG_INFO(&LOG, 4, "Datablock to seek for: %s", id->name); + } + } + } + + if (lapp_context->num_items == 0) { + /* Early out in case there is nothing to do. */ + return; + } + + BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true); + + /* We do not want any instantiation here! */ + BKE_blendfile_link(lapp_context, reports); + + BKE_main_lock(bmain); + + /* We add back old id to bmain. + * We need to do this in a first, separated loop, otherwise some of those may not be handled by + * ID remapping, which means they would still reference old data to be deleted... */ + for (item_idx = 0, itemlink = lapp_context->items.list; itemlink; + item_idx++, itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *old_id = item->userdata; + + BLI_assert(old_id); + BLI_addtail(which_libbase(bmain, GS(old_id->name)), old_id); + + /* Usual special code for ShapeKeys snowflakes... */ + Key *old_key = BKE_key_from_id(old_id); + if (old_key != NULL) { + BLI_addtail(which_libbase(bmain, GS(old_key->id.name)), &old_key->id); + } + } + + /* Since our (old) reloaded IDs were removed from main, the user count done for them in linking + * code is wrong, we need to redo it here after adding them back to main. */ + BKE_main_id_refcount_recompute(bmain, false); + + /* Note that in reload case, we also want to replace indirect usages. */ + const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE | + ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE | + (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE); + for (item_idx = 0, itemlink = lapp_context->items.list; itemlink; + item_idx++, itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *old_id = item->userdata; + ID *new_id = item->new_id; + + blendfile_library_relocate_remap(bmain, old_id, new_id, reports, do_reload, remap_flags); + if (new_id == NULL) { + continue; + } + /* Usual special code for ShapeKeys snowflakes... */ + Key **old_key_p = BKE_key_from_id_p(old_id); + if (old_key_p == NULL) { + continue; + } + Key *old_key = *old_key_p; + Key *new_key = BKE_key_from_id(new_id); + if (old_key != NULL) { + *old_key_p = NULL; + id_us_min(&old_key->id); + blendfile_library_relocate_remap( + bmain, &old_key->id, &new_key->id, reports, do_reload, remap_flags); + *old_key_p = old_key; + id_us_plus_no_lib(&old_key->id); + } + } + + BKE_main_unlock(bmain); + + for (item_idx = 0, itemlink = lapp_context->items.list; itemlink; + item_idx++, itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *old_id = item->userdata; + + if (old_id->us == 0) { + BKE_id_free(bmain, old_id); + } + } + + /* Some datablocks can get reloaded/replaced 'silently' because they are not linkable + * (shape keys e.g.), so we need another loop here to clear old ones if possible. */ + lba_idx = set_listbasepointers(bmain, lbarray); + while (lba_idx--) { + ID *id, *id_next; + for (id = lbarray[lba_idx]->first; id; id = id_next) { + id_next = id->next; + /* XXX That check may be a bit to generic/permissive? */ + if (id->lib && (id->flag & LIB_TAG_PRE_EXISTING) && id->us == 0) { + BKE_id_free(bmain, id); + } + } + } + + /* Get rid of no more used libraries... */ + BKE_main_id_tag_idcode(bmain, ID_LI, LIB_TAG_DOIT, true); + lba_idx = set_listbasepointers(bmain, lbarray); + while (lba_idx--) { + ID *id; + for (id = lbarray[lba_idx]->first; id; id = id->next) { + if (id->lib) { + id->lib->id.tag &= ~LIB_TAG_DOIT; + } + } + } + Library *lib, *lib_next; + for (lib = which_libbase(bmain, ID_LI)->first; lib; lib = lib_next) { + lib_next = lib->id.next; + if (lib->id.tag & LIB_TAG_DOIT) { + id_us_clear_real(&lib->id); + if (lib->id.us == 0) { + BKE_id_free(bmain, (ID *)lib); + } + } + } + + /* Update overrides of reloaded linked data-blocks. */ + ID *id; + FOREACH_MAIN_ID_BEGIN (bmain, id) { + if (ID_IS_LINKED(id) || !ID_IS_OVERRIDE_LIBRARY_REAL(id) || + (id->tag & LIB_TAG_PRE_EXISTING) == 0) { + continue; + } + if ((id->override_library->reference->tag & LIB_TAG_PRE_EXISTING) == 0) { + BKE_lib_override_library_update(bmain, id); + } + } + FOREACH_MAIN_ID_END; + + /* Resync overrides if needed. */ + if (!USER_EXPERIMENTAL_TEST(&U, no_override_auto_resync)) { + BKE_lib_override_library_main_resync(bmain, + lapp_context->params->context.scene, + lapp_context->params->context.view_layer, + &(struct BlendFileReadReport){ + .reports = reports, + }); + /* We need to rebuild some of the deleted override rules (for UI feedback purpose). */ + BKE_lib_override_library_main_operations_create(bmain, true); + } + + BKE_main_collection_sync(bmain); +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 7d217d6907d..eeee2dc2615 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -213,8 +213,9 @@ static void brush_foreach_id(ID *id, LibraryForeachIDData *data) if (brush->gpencil_settings) { BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, brush->gpencil_settings->material, IDWALK_CB_USER); } - BKE_texture_mtex_foreach_id(data, &brush->mtex); - BKE_texture_mtex_foreach_id(data, &brush->mask_mtex); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_texture_mtex_foreach_id(data, &brush->mtex)); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, + BKE_texture_mtex_foreach_id(data, &brush->mask_mtex)); } static void brush_blend_write(BlendWriter *writer, ID *id, const void *id_address) @@ -413,6 +414,7 @@ IDTypeInfo IDType_ID_BR = { .name_plural = "brushes", .translation_context = BLT_I18NCONTEXT_ID_BRUSH, .flags = IDTYPE_FLAGS_NO_ANIMDATA, + .asset_type_info = NULL, .init_data = brush_init_data, .copy_data = brush_copy_data, @@ -2474,7 +2476,7 @@ float BKE_brush_curve_strength(const Brush *br, float p, const float len) } /* Uses the brush curve control to find a strength value between 0 and 1 */ -float BKE_brush_curve_strength_clamped(Brush *br, float p, const float len) +float BKE_brush_curve_strength_clamped(const Brush *br, float p, const float len) { float strength = BKE_brush_curve_strength(br, p, len); diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index e642bbc9e06..3330b33cdd7 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -134,6 +134,7 @@ IDTypeInfo IDType_ID_CF = { .name_plural = "cache_files", .translation_context = BLT_I18NCONTEXT_ID_CACHEFILE, .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE, + .asset_type_info = NULL, .init_data = cache_file_init_data, .copy_data = cache_file_copy_data, diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index d355de73170..c0ab4a64d4a 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -182,6 +182,7 @@ IDTypeInfo IDType_ID_CA = { .name_plural = "cameras", .translation_context = BLT_I18NCONTEXT_ID_CAMERA, .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE, + .asset_type_info = NULL, .init_data = camera_init_data, .copy_data = camera_copy_data, diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 2dca5dcb75d..c025556430b 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -375,6 +375,7 @@ IDTypeInfo IDType_ID_GR = { .name_plural = "collections", .translation_context = BLT_I18NCONTEXT_ID_COLLECTION, .flags = IDTYPE_FLAGS_NO_ANIMDATA, + .asset_type_info = NULL, .init_data = collection_init_data, .copy_data = collection_copy_data, @@ -716,7 +717,7 @@ Collection *BKE_collection_duplicate(Main *bmain, collection_new->id.tag &= ~LIB_TAG_NEW; /* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW. */ - BKE_libblock_relink_to_newid(&collection_new->id); + BKE_libblock_relink_to_newid(bmain, &collection_new->id, 0); #ifndef NDEBUG /* Call to `BKE_libblock_relink_to_newid` above is supposed to have cleared all those flags. */ diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 7ddbaa0e9ee..3455baa9292 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -2010,7 +2010,7 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar /* We must get compatible eulers from the beginning because * some of them can be modified below (see bug T21875). * Additionally, since this constraint is based on euler rotation math, it doesn't work well - * with shear. The Y axis is chosen as the main axis when we orthoganalize the matrix because + * with shear. The Y axis is chosen as the main axis when we orthogonalize the matrix because * constraints are used most commonly on bones. */ float mat[4][4]; copy_m4_m4(mat, ct->matrix); diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index aae9ac383a4..8f5e0f8f3d0 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -312,6 +312,7 @@ IDTypeInfo IDType_ID_CU = { .name_plural = "curves", .translation_context = BLT_I18NCONTEXT_ID_CURVE, .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE, + .asset_type_info = NULL, .init_data = curve_init_data, .copy_data = curve_copy_data, diff --git a/source/blender/blenkernel/intern/curve_eval.cc b/source/blender/blenkernel/intern/curve_eval.cc index ff0478f2543..163f8b02b85 100644 --- a/source/blender/blenkernel/intern/curve_eval.cc +++ b/source/blender/blenkernel/intern/curve_eval.cc @@ -109,6 +109,24 @@ void CurveEval::bounds_min_max(float3 &min, float3 &max, const bool use_evaluate } } +float CurveEval::total_length() const +{ + float length = 0.0f; + for (const SplinePtr &spline : this->splines()) { + length += spline->length(); + } + return length; +} + +int CurveEval::total_control_point_size() const +{ + int count = 0; + for (const SplinePtr &spline : this->splines()) { + count += spline->size(); + } + return count; +} + /** * Return the start indices for each of the curve spline's control points, if they were part * of a flattened array. This can be used to facilitate parallelism by avoiding the need to diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc index 1ef205c6903..03525e32a52 100644 --- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc +++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc @@ -32,8 +32,6 @@ using blender::fn::GMutableSpan; using blender::fn::GSpan; -using blender::fn::GVArray_Typed; -using blender::fn::GVArrayPtr; namespace blender::bke { @@ -76,7 +74,7 @@ static void vert_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(); - GVArray_Typed<float> radii = spline.interpolate_to_evaluated(spline.radii()); + VArray<float> radii = spline.interpolate_to_evaluated(spline.radii()); for (const int i : IndexRange(eval_size)) { float4x4 point_matrix = float4x4::from_normalized_axis_data( positions[i], normals[i], tangents[i]); @@ -227,7 +225,7 @@ static void spline_extrude_to_mesh_data(const ResultInfo &info, Span<float3> normals = spline.evaluated_normals(); Span<float3> profile_positions = profile.evaluated_positions(); - GVArray_Typed<float> radii = spline.interpolate_to_evaluated(spline.radii()); + VArray<float> radii = spline.interpolate_to_evaluated(spline.radii()); 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]); @@ -495,8 +493,8 @@ 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(); + GVArray 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); @@ -561,8 +559,8 @@ 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(); + GVArray 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); diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 2ef7ef91160..05f1e9b286f 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -763,7 +763,7 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface) copy_v3_v3(bData->dim, dim); min_dim = max_fff(td[0], td[1], td[2]) / 1000.0f; - /* deactivate zero axises */ + /* deactivate zero axes */ for (i = 0; i < 3; i++) { if (td[i] < min_dim) { td[i] = 1.0f; @@ -784,7 +784,7 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface) dim_factor = (float)pow((double)volume / ((double)sData->total_points / 10000.0), 1.0 / (double)axis); - /* define final grid size using dim_factor, use min 3 for active axises */ + /* define final grid size using dim_factor, use min 3 for active axes */ for (i = 0; i < 3; i++) { grid->dim[i] = (int)floor(td[i] / dim_factor); CLAMP(grid->dim[i], (dim[i] >= min_dim) ? 3 : 1, 100); diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 1564eb3aa7b..bbf61c51bfb 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -205,12 +205,16 @@ void BKE_fcurve_foreach_id(FCurve *fcu, LibraryForeachIDData *data) FMod_Python *fcm_py = (FMod_Python *)fcm->data; BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, fcm_py->script, IDWALK_CB_NOP); - IDP_foreach_property(fcm_py->prop, - IDP_TYPE_FILTER_ID, - BKE_lib_query_idpropertiesForeachIDLink_callback, - data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + IDP_foreach_property(fcm_py->prop, + IDP_TYPE_FILTER_ID, + BKE_lib_query_idpropertiesForeachIDLink_callback, + data)); break; } + default: + break; } } } diff --git a/source/blender/blenkernel/intern/fcurve_driver.c b/source/blender/blenkernel/intern/fcurve_driver.c index d1bf523acef..3ac64dbf84b 100644 --- a/source/blender/blenkernel/intern/fcurve_driver.c +++ b/source/blender/blenkernel/intern/fcurve_driver.c @@ -326,7 +326,7 @@ static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar) float(*mat[2])[4]; - /* NOTE: for now, these are all just worldspace */ + /* NOTE: for now, these are all just world-space. */ for (int i = 0; i < 2; i++) { /* Get pointer to loc values to store in. */ DriverTarget *dtar = &dvar->targets[i]; @@ -422,7 +422,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar) } } else { - /* Convert to worldspace. */ + /* Convert to world-space. */ copy_v3_v3(tmp_loc, pchan->pose_head); mul_m4_v3(ob->obmat, tmp_loc); } diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index 6b7594dcf36..9d26a1528f3 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -5090,7 +5090,7 @@ void BKE_fluid_modifier_copy(const struct FluidModifierData *fmd, copy_v4_v4(tfds->gridlines_range_color, fds->gridlines_range_color); tfds->gridlines_cell_filter = fds->gridlines_cell_filter; - /* -- Deprecated / unsed options (below)-- */ + /* -- Deprecated / unused options (below)-- */ /* pointcache options */ BKE_ptcache_free_list(&(tfds->ptcaches[0])); diff --git a/source/blender/blenkernel/intern/geometry_component_curve.cc b/source/blender/blenkernel/intern/geometry_component_curve.cc index 961265f3a16..598c61fd877 100644 --- a/source/blender/blenkernel/intern/geometry_component_curve.cc +++ b/source/blender/blenkernel/intern/geometry_component_curve.cc @@ -28,10 +28,8 @@ using blender::fn::GMutableSpan; using blender::fn::GSpan; -using blender::fn::GVArray_For_GSpan; +using blender::fn::GVArray; using blender::fn::GVArray_GSpan; -using blender::fn::GVArrayPtr; -using blender::fn::GVMutableArray_For_GMutableSpan; /* -------------------------------------------------------------------- */ /** \name Geometry Component Implementation @@ -253,15 +251,15 @@ void adapt_curve_domain_point_to_spline_impl(const CurveEval &curve, } } -static GVArrayPtr adapt_curve_domain_point_to_spline(const CurveEval &curve, GVArrayPtr varray) +static GVArray adapt_curve_domain_point_to_spline(const CurveEval &curve, GVArray varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(curve.splines().size()); - adapt_curve_domain_point_to_spline_impl<T>(curve, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_curve_domain_point_to_spline_impl<T>(curve, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -272,29 +270,29 @@ static GVArrayPtr adapt_curve_domain_point_to_spline(const CurveEval &curve, GVA * attributes. The goal is to avoid copying the spline value for every one of its control points * unless it is necessary (in that case the materialize functions will be called). */ -template<typename T> class VArray_For_SplineToPoint final : public VArray<T> { - GVArrayPtr original_varray_; +template<typename T> class VArray_For_SplineToPoint final : public VArrayImpl<T> { + GVArray original_varray_; /* Store existing data materialized if it was not already a span. This is expected * to be worth it because a single spline's value will likely be accessed many times. */ - fn::GVArray_Span<T> original_data_; + VArray_Span<T> original_data_; Array<int> offsets_; public: - VArray_For_SplineToPoint(GVArrayPtr original_varray, Array<int> offsets) - : VArray<T>(offsets.last()), + VArray_For_SplineToPoint(GVArray original_varray, Array<int> offsets) + : VArrayImpl<T>(offsets.last()), original_varray_(std::move(original_varray)), - original_data_(*original_varray_), + original_data_(original_varray_.typed<T>()), offsets_(std::move(offsets)) { } - T get_impl(const int64_t index) const final + T get(const int64_t index) const final { const PointIndices indices = lookup_point_indices(offsets_, index); return original_data_[indices.spline_index]; } - void materialize_impl(const IndexMask mask, MutableSpan<T> r_span) const final + void materialize(const IndexMask mask, MutableSpan<T> r_span) const final { const int total_size = offsets_.last(); if (mask.is_range() && mask.as_range() == IndexRange(total_size)) { @@ -315,7 +313,7 @@ template<typename T> class VArray_For_SplineToPoint final : public VArray<T> { } } - void materialize_to_uninitialized_impl(const IndexMask mask, MutableSpan<T> r_span) const final + void materialize_to_uninitialized(const IndexMask mask, MutableSpan<T> r_span) const final { T *dst = r_span.data(); const int total_size = offsets_.last(); @@ -338,29 +336,29 @@ template<typename T> class VArray_For_SplineToPoint final : public VArray<T> { } }; -static GVArrayPtr adapt_curve_domain_spline_to_point(const CurveEval &curve, GVArrayPtr varray) +static GVArray adapt_curve_domain_spline_to_point(const CurveEval &curve, GVArray varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); Array<int> offsets = curve.control_point_offsets(); - new_varray = std::make_unique<fn::GVArray_For_EmbeddedVArray<T, VArray_For_SplineToPoint<T>>>( - offsets.last(), std::move(varray), std::move(offsets)); + new_varray = VArray<T>::template For<VArray_For_SplineToPoint<T>>(std::move(varray), + std::move(offsets)); }); return new_varray; } } // namespace blender::bke -GVArrayPtr CurveComponent::attribute_try_adapt_domain(GVArrayPtr varray, - const AttributeDomain from_domain, - const AttributeDomain to_domain) const +GVArray CurveComponent::attribute_try_adapt_domain_impl(const GVArray &varray, + const AttributeDomain from_domain, + const AttributeDomain to_domain) const { if (!varray) { return {}; } - if (varray->size() == 0) { + if (varray.is_empty()) { return {}; } if (from_domain == to_domain) { @@ -402,8 +400,8 @@ static const CurveEval *get_curve_from_component_for_read(const GeometryComponen namespace blender::bke { class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider { - using AsReadAttribute = GVArrayPtr (*)(const CurveEval &data); - using AsWriteAttribute = GVMutableArrayPtr (*)(CurveEval &data); + using AsReadAttribute = GVArray (*)(const CurveEval &data); + using AsWriteAttribute = GVMutableArray (*)(CurveEval &data); const AsReadAttribute as_read_attribute_; const AsWriteAttribute as_write_attribute_; @@ -424,7 +422,7 @@ class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider { { } - GVArrayPtr try_get_for_read(const GeometryComponent &component) const final + GVArray try_get_for_read(const GeometryComponent &component) const final { const CurveEval *curve = get_curve_from_component_for_read(component); if (curve == nullptr) { @@ -483,19 +481,15 @@ static void set_spline_resolution(SplinePtr &spline, const int resolution) } } -static GVArrayPtr make_resolution_read_attribute(const CurveEval &curve) +static GVArray make_resolution_read_attribute(const CurveEval &curve) { - return std::make_unique<fn::GVArray_For_DerivedSpan<SplinePtr, int, get_spline_resolution>>( - curve.splines()); + return VArray<int>::ForDerivedSpan<SplinePtr, get_spline_resolution>(curve.splines()); } -static GVMutableArrayPtr make_resolution_write_attribute(CurveEval &curve) +static GVMutableArray make_resolution_write_attribute(CurveEval &curve) { - return std::make_unique<fn::GVMutableArray_For_DerivedSpan<SplinePtr, - int, - get_spline_resolution, - set_spline_resolution>>( - curve.splines()); + return VMutableArray<int>:: + ForDerivedSpan<SplinePtr, get_spline_resolution, set_spline_resolution>(curve.splines()); } static bool get_cyclic_value(const SplinePtr &spline) @@ -511,16 +505,14 @@ static void set_cyclic_value(SplinePtr &spline, const bool value) } } -static GVArrayPtr make_cyclic_read_attribute(const CurveEval &curve) +static GVArray make_cyclic_read_attribute(const CurveEval &curve) { - return std::make_unique<fn::GVArray_For_DerivedSpan<SplinePtr, bool, get_cyclic_value>>( - curve.splines()); + return VArray<bool>::ForDerivedSpan<SplinePtr, get_cyclic_value>(curve.splines()); } -static GVMutableArrayPtr make_cyclic_write_attribute(CurveEval &curve) +static GVMutableArray make_cyclic_write_attribute(CurveEval &curve) { - return std::make_unique< - fn::GVMutableArray_For_DerivedSpan<SplinePtr, bool, get_cyclic_value, set_cyclic_value>>( + return VMutableArray<bool>::ForDerivedSpan<SplinePtr, get_cyclic_value, set_cyclic_value>( curve.splines()); } @@ -625,9 +617,9 @@ static void point_attribute_materialize_to_uninitialized(Span<Span<T>> data, } } -static GVArrayPtr varray_from_initializer(const AttributeInit &initializer, - const CustomDataType data_type, - const Span<SplinePtr> splines) +static GVArray varray_from_initializer(const AttributeInit &initializer, + const CustomDataType data_type, + const Span<SplinePtr> splines) { switch (initializer.type) { case AttributeInit::Type::Default: @@ -636,16 +628,15 @@ static GVArrayPtr varray_from_initializer(const AttributeInit &initializer, BLI_assert_unreachable(); return {}; case AttributeInit::Type::VArray: - return static_cast<const AttributeInitVArray &>(initializer).varray->shallow_copy(); + return static_cast<const AttributeInitVArray &>(initializer).varray; case AttributeInit::Type::MoveArray: int total_size = 0; for (const SplinePtr &spline : splines) { total_size += spline->size(); } - return std::make_unique<fn::GVArray_For_GSpan>( - GSpan(*bke::custom_data_type_to_cpp_type(data_type), - static_cast<const AttributeInitMove &>(initializer).data, - total_size)); + return GVArray::ForSpan(GSpan(*bke::custom_data_type_to_cpp_type(data_type), + static_cast<const AttributeInitMove &>(initializer).data, + total_size)); } BLI_assert_unreachable(); return {}; @@ -693,11 +684,11 @@ static bool create_point_attribute(GeometryComponent &component, /* We just created the attribute, it should exist. */ BLI_assert(write_attribute); - GVArrayPtr source_varray = varray_from_initializer(initializer, data_type, splines); + GVArray source_varray = varray_from_initializer(initializer, data_type, splines); /* TODO: When we can call a variant of #set_all with a virtual array argument, * this theoretically unnecessary materialize step could be removed. */ - GVArray_GSpan source_varray_span{*source_varray}; - write_attribute.varray->set_all(source_varray_span.data()); + GVArray_GSpan source_varray_span{source_varray}; + write_attribute.varray.set_all(source_varray_span.data()); if (initializer.type == AttributeInit::Type::MoveArray) { MEM_freeN(static_cast<const AttributeInitMove &>(initializer).data); @@ -725,29 +716,29 @@ static bool remove_point_attribute(GeometryComponent &component, /** * Virtual array for any control point data accessed with spans and an offset array. */ -template<typename T> class VArray_For_SplinePoints : public VArray<T> { +template<typename T> class VArray_For_SplinePoints : public VArrayImpl<T> { private: const Array<Span<T>> data_; Array<int> offsets_; public: VArray_For_SplinePoints(Array<Span<T>> data, Array<int> offsets) - : VArray<T>(offsets.last()), data_(std::move(data)), offsets_(std::move(offsets)) + : VArrayImpl<T>(offsets.last()), data_(std::move(data)), offsets_(std::move(offsets)) { } - T get_impl(const int64_t index) const final + T get(const int64_t index) const final { const PointIndices indices = lookup_point_indices(offsets_, index); return data_[indices.spline_index][indices.point_index]; } - void materialize_impl(const IndexMask mask, MutableSpan<T> r_span) const final + void materialize(const IndexMask mask, MutableSpan<T> r_span) const final { point_attribute_materialize(data_.as_span(), offsets_, mask, r_span); } - void materialize_to_uninitialized_impl(const IndexMask mask, MutableSpan<T> r_span) const final + void materialize_to_uninitialized(const IndexMask mask, MutableSpan<T> r_span) const final { point_attribute_materialize_to_uninitialized(data_.as_span(), offsets_, mask, r_span); } @@ -756,30 +747,30 @@ template<typename T> class VArray_For_SplinePoints : public VArray<T> { /** * Mutable virtual array for any control point data accessed with spans and an offset array. */ -template<typename T> class VMutableArray_For_SplinePoints final : public VMutableArray<T> { +template<typename T> class VMutableArray_For_SplinePoints final : public VMutableArrayImpl<T> { private: Array<MutableSpan<T>> data_; Array<int> offsets_; public: VMutableArray_For_SplinePoints(Array<MutableSpan<T>> data, Array<int> offsets) - : VMutableArray<T>(offsets.last()), data_(std::move(data)), offsets_(std::move(offsets)) + : VMutableArrayImpl<T>(offsets.last()), data_(std::move(data)), offsets_(std::move(offsets)) { } - T get_impl(const int64_t index) const final + T get(const int64_t index) const final { const PointIndices indices = lookup_point_indices(offsets_, index); return data_[indices.spline_index][indices.point_index]; } - void set_impl(const int64_t index, T value) final + void set(const int64_t index, T value) final { const PointIndices indices = lookup_point_indices(offsets_, index); data_[indices.spline_index][indices.point_index] = value; } - void set_all_impl(Span<T> src) final + void set_all(Span<T> src) final { for (const int spline_index : data_.index_range()) { const int offset = offsets_[spline_index]; @@ -788,30 +779,28 @@ template<typename T> class VMutableArray_For_SplinePoints final : public VMutabl } } - void materialize_impl(const IndexMask mask, MutableSpan<T> r_span) const final + void materialize(const IndexMask mask, MutableSpan<T> r_span) const final { point_attribute_materialize({(Span<T> *)data_.data(), data_.size()}, offsets_, mask, r_span); } - void materialize_to_uninitialized_impl(const IndexMask mask, MutableSpan<T> r_span) const final + void materialize_to_uninitialized(const IndexMask mask, MutableSpan<T> r_span) const final { point_attribute_materialize_to_uninitialized( {(Span<T> *)data_.data(), data_.size()}, offsets_, mask, r_span); } }; -template<typename T> GVArrayPtr point_data_gvarray(Array<Span<T>> spans, Array<int> offsets) +template<typename T> VArray<T> point_data_varray(Array<Span<T>> spans, Array<int> offsets) { - return std::make_unique<fn::GVArray_For_EmbeddedVArray<T, VArray_For_SplinePoints<T>>>( - offsets.last(), std::move(spans), std::move(offsets)); + return VArray<T>::template For<VArray_For_SplinePoints<T>>(std::move(spans), std::move(offsets)); } template<typename T> -GVMutableArrayPtr point_data_gvarray(Array<MutableSpan<T>> spans, Array<int> offsets) +VMutableArray<T> point_data_varray(Array<MutableSpan<T>> spans, Array<int> offsets) { - return std::make_unique< - fn::GVMutableArray_For_EmbeddedVMutableArray<T, VMutableArray_For_SplinePoints<T>>>( - offsets.last(), std::move(spans), std::move(offsets)); + return VMutableArray<T>::template For<VMutableArray_For_SplinePoints<T>>(std::move(spans), + std::move(offsets)); } /** @@ -822,24 +811,24 @@ GVMutableArrayPtr point_data_gvarray(Array<MutableSpan<T>> spans, Array<int> off * \note There is no need to check the handle type to avoid changing auto handles, since * retrieving write access to the position data will mark them for recomputation anyway. */ -class VMutableArray_For_SplinePosition final : public VMutableArray<float3> { +class VMutableArray_For_SplinePosition final : public VMutableArrayImpl<float3> { private: MutableSpan<SplinePtr> splines_; Array<int> offsets_; public: VMutableArray_For_SplinePosition(MutableSpan<SplinePtr> splines, Array<int> offsets) - : VMutableArray<float3>(offsets.last()), splines_(splines), offsets_(std::move(offsets)) + : VMutableArrayImpl<float3>(offsets.last()), splines_(splines), offsets_(std::move(offsets)) { } - float3 get_impl(const int64_t index) const final + float3 get(const int64_t index) const final { const PointIndices indices = lookup_point_indices(offsets_, index); return splines_[indices.spline_index]->positions()[indices.point_index]; } - void set_impl(const int64_t index, float3 value) final + void set(const int64_t index, float3 value) final { const PointIndices indices = lookup_point_indices(offsets_, index); Spline &spline = *splines_[indices.spline_index]; @@ -854,7 +843,7 @@ class VMutableArray_For_SplinePosition final : public VMutableArray<float3> { } } - void set_all_impl(Span<float3> src) final + void set_all(Span<float3> src) final { for (const int spline_index : splines_.index_range()) { Spline &spline = *splines_[spline_index]; @@ -887,21 +876,20 @@ class VMutableArray_For_SplinePosition final : public VMutableArray<float3> { return spans; } - void materialize_impl(const IndexMask mask, MutableSpan<float3> r_span) const final + void materialize(const IndexMask mask, MutableSpan<float3> r_span) const final { Array<Span<float3>> spans = this->get_position_spans(); point_attribute_materialize(spans.as_span(), offsets_, mask, r_span); } - void materialize_to_uninitialized_impl(const IndexMask mask, - MutableSpan<float3> r_span) const final + void materialize_to_uninitialized(const IndexMask mask, MutableSpan<float3> r_span) const final { Array<Span<float3>> spans = this->get_position_spans(); point_attribute_materialize_to_uninitialized(spans.as_span(), offsets_, mask, r_span); } }; -class VArray_For_BezierHandle final : public VArray<float3> { +class VArray_For_BezierHandle final : public VArrayImpl<float3> { private: Span<SplinePtr> splines_; Array<int> offsets_; @@ -909,7 +897,7 @@ class VArray_For_BezierHandle final : public VArray<float3> { public: VArray_For_BezierHandle(Span<SplinePtr> splines, Array<int> offsets, const bool is_right) - : VArray<float3>(offsets.last()), + : VArrayImpl<float3>(offsets.last()), splines_(std::move(splines)), offsets_(std::move(offsets)), is_right_(is_right) @@ -931,7 +919,7 @@ class VArray_For_BezierHandle final : public VArray<float3> { return float3(0); } - float3 get_impl(const int64_t index) const final + float3 get(const int64_t index) const final { return get_internal(index, splines_, offsets_, is_right_); } @@ -978,19 +966,18 @@ class VArray_For_BezierHandle final : public VArray<float3> { point_attribute_materialize_to_uninitialized(spans.as_span(), offsets, mask, r_span); } - void materialize_impl(const IndexMask mask, MutableSpan<float3> r_span) const final + void materialize(const IndexMask mask, MutableSpan<float3> r_span) const final { materialize_internal(mask, splines_, offsets_, is_right_, r_span); } - void materialize_to_uninitialized_impl(const IndexMask mask, - MutableSpan<float3> r_span) const final + void materialize_to_uninitialized(const IndexMask mask, MutableSpan<float3> r_span) const final { materialize_to_uninitialized_internal(mask, splines_, offsets_, is_right_, r_span); } }; -class VMutableArray_For_BezierHandles final : public VMutableArray<float3> { +class VMutableArray_For_BezierHandles final : public VMutableArrayImpl<float3> { private: MutableSpan<SplinePtr> splines_; Array<int> offsets_; @@ -1000,19 +987,19 @@ class VMutableArray_For_BezierHandles final : public VMutableArray<float3> { VMutableArray_For_BezierHandles(MutableSpan<SplinePtr> splines, Array<int> offsets, const bool is_right) - : VMutableArray<float3>(offsets.last()), + : VMutableArrayImpl<float3>(offsets.last()), splines_(splines), offsets_(std::move(offsets)), is_right_(is_right) { } - float3 get_impl(const int64_t index) const final + float3 get(const int64_t index) const final { return VArray_For_BezierHandle::get_internal(index, splines_, offsets_, is_right_); } - void set_impl(const int64_t index, float3 value) final + void set(const int64_t index, float3 value) final { const PointIndices indices = lookup_point_indices(offsets_, index); Spline &spline = *splines_[indices.spline_index]; @@ -1028,7 +1015,7 @@ class VMutableArray_For_BezierHandles final : public VMutableArray<float3> { } } - void set_all_impl(Span<float3> src) final + void set_all(Span<float3> src) final { for (const int spline_index : splines_.index_range()) { Spline &spline = *splines_[spline_index]; @@ -1051,13 +1038,12 @@ class VMutableArray_For_BezierHandles final : public VMutableArray<float3> { } } - void materialize_impl(const IndexMask mask, MutableSpan<float3> r_span) const final + void materialize(const IndexMask mask, MutableSpan<float3> r_span) const final { VArray_For_BezierHandle::materialize_internal(mask, splines_, offsets_, is_right_, r_span); } - void materialize_to_uninitialized_impl(const IndexMask mask, - MutableSpan<float3> r_span) const final + void materialize_to_uninitialized(const IndexMask mask, MutableSpan<float3> r_span) const final { VArray_For_BezierHandle::materialize_to_uninitialized_internal( mask, splines_, offsets_, is_right_, r_span); @@ -1099,7 +1085,7 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu { } - GVArrayPtr try_get_for_read(const GeometryComponent &component) const override + GVArray try_get_for_read(const GeometryComponent &component) const override { const CurveEval *curve = get_curve_from_component_for_read(component); if (curve == nullptr) { @@ -1112,7 +1098,7 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu Span<SplinePtr> splines = curve->splines(); if (splines.size() == 1) { - return std::make_unique<fn::GVArray_For_GSpan>(get_span_(*splines.first())); + return GVArray::ForSpan(get_span_(*splines.first())); } Array<int> offsets = curve->control_point_offsets(); @@ -1121,7 +1107,7 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu spans[i] = get_span_(*splines[i]); } - return point_data_gvarray(spans, offsets); + return point_data_varray(spans, offsets); } WriteAttributeLookup try_get_for_write(GeometryComponent &component) const override @@ -1146,8 +1132,7 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu MutableSpan<SplinePtr> splines = curve->splines(); if (splines.size() == 1) { - return {std::make_unique<fn::GVMutableArray_For_GMutableSpan>( - get_mutable_span_(*splines.first())), + return {GVMutableArray::ForSpan(get_mutable_span_(*splines.first())), domain_, std::move(tag_modified_fn)}; } @@ -1158,7 +1143,7 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu spans[i] = get_mutable_span_(*splines[i]); } - return {point_data_gvarray(spans, offsets), domain_, tag_modified_fn}; + return {point_data_varray(spans, offsets), domain_, tag_modified_fn}; } bool try_delete(GeometryComponent &component) const final @@ -1250,10 +1235,8 @@ class PositionAttributeProvider final : public BuiltinPointAttributeProvider<flo }; Array<int> offsets = curve->control_point_offsets(); - return {std::make_unique< - fn::GVMutableArray_For_EmbeddedVMutableArray<float3, - VMutableArray_For_SplinePosition>>( - offsets.last(), curve->splines(), std::move(offsets)), + return {VMutableArray<float3>::For<VMutableArray_For_SplinePosition>(curve->splines(), + std::move(offsets)), domain_, tag_modified_fn}; } @@ -1275,7 +1258,7 @@ class BezierHandleAttributeProvider : public BuiltinAttributeProvider { { } - GVArrayPtr try_get_for_read(const GeometryComponent &component) const override + GVArray try_get_for_read(const GeometryComponent &component) const override { const CurveEval *curve = get_curve_from_component_for_read(component); if (curve == nullptr) { @@ -1287,8 +1270,8 @@ class BezierHandleAttributeProvider : public BuiltinAttributeProvider { } Array<int> offsets = curve->control_point_offsets(); - return std::make_unique<fn::GVArray_For_EmbeddedVArray<float3, VArray_For_BezierHandle>>( - offsets.last(), curve->splines(), std::move(offsets), is_right_); + return VArray<float3>::For<VArray_For_BezierHandle>( + curve->splines(), std::move(offsets), is_right_); } WriteAttributeLookup try_get_for_write(GeometryComponent &component) const override @@ -1305,12 +1288,10 @@ class BezierHandleAttributeProvider : public BuiltinAttributeProvider { auto tag_modified_fn = [curve]() { curve->mark_cache_invalid(); }; Array<int> offsets = curve->control_point_offsets(); - return { - std::make_unique< - fn::GVMutableArray_For_EmbeddedVMutableArray<float3, VMutableArray_For_BezierHandles>>( - offsets.last(), curve->splines(), std::move(offsets), is_right_), - domain_, - tag_modified_fn}; + return {VMutableArray<float3>::For<VMutableArray_For_BezierHandles>( + curve->splines(), std::move(offsets), is_right_), + domain_, + tag_modified_fn}; } bool try_delete(GeometryComponent &UNUSED(component)) const final @@ -1389,7 +1370,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider { /* First check for the simpler situation when we can return a simpler span virtual array. */ if (spans.size() == 1) { - return {std::make_unique<GVArray_For_GSpan>(spans.first()), ATTR_DOMAIN_POINT}; + return {GVArray::ForSpan(spans.first()), ATTR_DOMAIN_POINT}; } ReadAttributeLookup attribute = {}; @@ -1401,7 +1382,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider { data[i] = spans[i].typed<T>(); BLI_assert(data[i].data() != nullptr); } - attribute = {point_data_gvarray(data, offsets), ATTR_DOMAIN_POINT}; + attribute = {point_data_varray(data, offsets), ATTR_DOMAIN_POINT}; }); return attribute; } @@ -1442,7 +1423,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider { /* First check for the simpler situation when we can return a simpler span virtual array. */ if (spans.size() == 1) { - return {std::make_unique<GVMutableArray_For_GMutableSpan>(spans.first()), ATTR_DOMAIN_POINT}; + return {GVMutableArray::ForSpan(spans.first()), ATTR_DOMAIN_POINT}; } WriteAttributeLookup attribute = {}; @@ -1454,7 +1435,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider { data[i] = spans[i].typed<T>(); BLI_assert(data[i].data() != nullptr); } - attribute = {point_data_gvarray(data, offsets), ATTR_DOMAIN_POINT}; + attribute = {point_data_varray(data, offsets), ATTR_DOMAIN_POINT}; }); return attribute; } diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc index 5fe77000519..9a30c86c1e5 100644 --- a/source/blender/blenkernel/intern/geometry_component_instances.cc +++ b/source/blender/blenkernel/intern/geometry_component_instances.cc @@ -363,12 +363,22 @@ blender::Span<int> InstancesComponent::almost_unique_ids() const int InstancesComponent::attribute_domain_size(const AttributeDomain domain) const { - if (domain != ATTR_DOMAIN_POINT) { + if (domain != ATTR_DOMAIN_INSTANCE) { return 0; } return this->instances_amount(); } +blender::bke::CustomDataAttributes &InstancesComponent::attributes() +{ + return this->attributes_; +} + +const blender::bke::CustomDataAttributes &InstancesComponent::attributes() const +{ + return this->attributes_; +} + namespace blender::bke { static float3 get_transform_position(const float4x4 &transform) @@ -385,29 +395,26 @@ class InstancePositionAttributeProvider final : public BuiltinAttributeProvider public: InstancePositionAttributeProvider() : BuiltinAttributeProvider( - "position", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, NonCreatable, Writable, NonDeletable) + "position", ATTR_DOMAIN_INSTANCE, CD_PROP_FLOAT3, NonCreatable, Writable, NonDeletable) { } - GVArrayPtr try_get_for_read(const GeometryComponent &component) const final + GVArray try_get_for_read(const GeometryComponent &component) const final { const InstancesComponent &instances_component = static_cast<const InstancesComponent &>( component); Span<float4x4> transforms = instances_component.instance_transforms(); - return std::make_unique<fn::GVArray_For_DerivedSpan<float4x4, float3, get_transform_position>>( - transforms); + return VArray<float3>::ForDerivedSpan<float4x4, get_transform_position>(transforms); } WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final { InstancesComponent &instances_component = static_cast<InstancesComponent &>(component); MutableSpan<float4x4> transforms = instances_component.instance_transforms(); - return { - std::make_unique<fn::GVMutableArray_For_DerivedSpan<float4x4, - float3, - get_transform_position, - set_transform_position>>(transforms), - domain_}; + return {VMutableArray<float3>::ForDerivedSpan<float4x4, + get_transform_position, + set_transform_position>(transforms), + domain_}; } bool try_delete(GeometryComponent &UNUSED(component)) const final @@ -431,17 +438,17 @@ class InstanceIDAttributeProvider final : public BuiltinAttributeProvider { public: InstanceIDAttributeProvider() : BuiltinAttributeProvider( - "id", ATTR_DOMAIN_POINT, CD_PROP_INT32, Creatable, Writable, Deletable) + "id", ATTR_DOMAIN_INSTANCE, CD_PROP_INT32, Creatable, Writable, Deletable) { } - GVArrayPtr try_get_for_read(const GeometryComponent &component) const final + GVArray try_get_for_read(const GeometryComponent &component) const final { const InstancesComponent &instances = static_cast<const InstancesComponent &>(component); if (instances.instance_ids().is_empty()) { return {}; } - return std::make_unique<fn::GVArray_For_Span<int>>(instances.instance_ids()); + return VArray<int>::ForSpan(instances.instance_ids()); } WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final @@ -450,8 +457,7 @@ class InstanceIDAttributeProvider final : public BuiltinAttributeProvider { if (instances.instance_ids().is_empty()) { return {}; } - return {std::make_unique<fn::GVMutableArray_For_MutableSpan<int>>(instances.instance_ids()), - domain_}; + return {VMutableArray<int>::ForSpan(instances.instance_ids()), domain_}; } bool try_delete(GeometryComponent &component) const final @@ -477,8 +483,8 @@ class InstanceIDAttributeProvider final : public BuiltinAttributeProvider { break; } case AttributeInit::Type::VArray: { - const GVArray *varray = static_cast<const AttributeInitVArray &>(initializer).varray; - varray->materialize_to_uninitialized(IndexRange(varray->size()), ids.data()); + const GVArray &varray = static_cast<const AttributeInitVArray &>(initializer).varray; + varray.materialize_to_uninitialized(varray.index_range(), ids.data()); break; } case AttributeInit::Type::MoveArray: { @@ -503,7 +509,21 @@ static ComponentAttributeProviders create_attribute_providers_for_instances() static InstancePositionAttributeProvider position; static InstanceIDAttributeProvider id; - return ComponentAttributeProviders({&position, &id}, {}); + static CustomDataAccessInfo instance_custom_data_access = { + [](GeometryComponent &component) -> CustomData * { + InstancesComponent &inst = static_cast<InstancesComponent &>(component); + return &inst.attributes().data; + }, + [](const GeometryComponent &component) -> const CustomData * { + const InstancesComponent &inst = static_cast<const InstancesComponent &>(component); + return &inst.attributes().data; + }, + nullptr}; + + static CustomDataAttributeProvider instance_custom_data(ATTR_DOMAIN_INSTANCE, + instance_custom_data_access); + + return ComponentAttributeProviders({&position, &id}, {&instance_custom_data}); } } // namespace blender::bke diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index 0456316151c..a258a66cdf3 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -32,8 +32,6 @@ /* Can't include BKE_object_deform.h right now, due to an enum forward declaration. */ extern "C" MDeformVert *BKE_object_defgroup_data_create(ID *id); -using blender::fn::GVArray; - /* -------------------------------------------------------------------- */ /** \name Geometry Component Implementation * \{ */ @@ -203,17 +201,17 @@ void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_corner_to_point(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_corner_to_point(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { /* We compute all interpolated values at once, because for this interpolation, one has to * iterate over all loops anyway. */ Array<T> values(mesh.totvert); - adapt_mesh_domain_corner_to_point_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_corner_to_point_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -239,14 +237,14 @@ static void adapt_mesh_domain_point_to_corner_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_point_to_corner(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_point_to_corner(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); 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)); + adapt_mesh_domain_point_to_corner_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); }); return new_varray; } @@ -295,15 +293,15 @@ void adapt_mesh_domain_corner_to_face_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_corner_to_face(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_corner_to_face(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totpoly); - adapt_mesh_domain_corner_to_face_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_corner_to_face_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -368,15 +366,15 @@ void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_corner_to_edge(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_corner_to_edge(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totedge); - adapt_mesh_domain_corner_to_edge_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_corner_to_edge_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -424,15 +422,15 @@ void adapt_mesh_domain_face_to_point_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_face_to_point(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_face_to_point(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totvert); - adapt_mesh_domain_face_to_point_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_face_to_point_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -453,15 +451,15 @@ void adapt_mesh_domain_face_to_corner_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_face_to_corner(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_face_to_corner(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totloop); - adapt_mesh_domain_face_to_corner_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_face_to_corner_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -507,15 +505,15 @@ void adapt_mesh_domain_face_to_edge_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_face_to_edge(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_face_to_edge(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totedge); - adapt_mesh_domain_face_to_edge_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_face_to_edge_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -567,15 +565,15 @@ void adapt_mesh_domain_point_to_face_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_point_to_face(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_point_to_face(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totpoly); - adapt_mesh_domain_point_to_face_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_point_to_face_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -617,15 +615,15 @@ void adapt_mesh_domain_point_to_edge_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_point_to_edge(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_point_to_edge(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totedge); - adapt_mesh_domain_point_to_edge_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_point_to_edge_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -678,15 +676,15 @@ void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_edge_to_corner(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_edge_to_corner(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totloop); - adapt_mesh_domain_edge_to_corner_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_edge_to_corner_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -728,15 +726,15 @@ void adapt_mesh_domain_edge_to_point_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_edge_to_point(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_edge_to_point(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totvert); - adapt_mesh_domain_edge_to_point_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_edge_to_point_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -788,15 +786,15 @@ void adapt_mesh_domain_edge_to_face_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_edge_to_face(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_edge_to_face(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totpoly); - adapt_mesh_domain_edge_to_face_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_edge_to_face_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -804,15 +802,15 @@ static GVArrayPtr adapt_mesh_domain_edge_to_face(const Mesh &mesh, GVArrayPtr va } // namespace blender::bke -blender::fn::GVArrayPtr MeshComponent::attribute_try_adapt_domain( - blender::fn::GVArrayPtr varray, +blender::fn::GVArray MeshComponent::attribute_try_adapt_domain_impl( + const blender::fn::GVArray &varray, const AttributeDomain from_domain, const AttributeDomain to_domain) const { if (!varray) { return {}; } - if (varray->size() == 0) { + if (varray.size() == 0) { return {}; } if (from_domain == to_domain) { @@ -823,11 +821,11 @@ blender::fn::GVArrayPtr MeshComponent::attribute_try_adapt_domain( case ATTR_DOMAIN_CORNER: { switch (to_domain) { case ATTR_DOMAIN_POINT: - return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, varray); case ATTR_DOMAIN_FACE: - return blender::bke::adapt_mesh_domain_corner_to_face(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_corner_to_face(*mesh_, varray); case ATTR_DOMAIN_EDGE: - return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, varray); default: break; } @@ -836,11 +834,11 @@ blender::fn::GVArrayPtr MeshComponent::attribute_try_adapt_domain( case ATTR_DOMAIN_POINT: { switch (to_domain) { case ATTR_DOMAIN_CORNER: - return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, varray); case ATTR_DOMAIN_FACE: - return blender::bke::adapt_mesh_domain_point_to_face(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_point_to_face(*mesh_, varray); case ATTR_DOMAIN_EDGE: - return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, varray); default: break; } @@ -849,11 +847,11 @@ blender::fn::GVArrayPtr MeshComponent::attribute_try_adapt_domain( case ATTR_DOMAIN_FACE: { switch (to_domain) { case ATTR_DOMAIN_POINT: - return blender::bke::adapt_mesh_domain_face_to_point(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_face_to_point(*mesh_, varray); case ATTR_DOMAIN_CORNER: - return blender::bke::adapt_mesh_domain_face_to_corner(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_face_to_corner(*mesh_, varray); case ATTR_DOMAIN_EDGE: - return blender::bke::adapt_mesh_domain_face_to_edge(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_face_to_edge(*mesh_, varray); default: break; } @@ -862,11 +860,11 @@ blender::fn::GVArrayPtr MeshComponent::attribute_try_adapt_domain( case ATTR_DOMAIN_EDGE: { switch (to_domain) { case ATTR_DOMAIN_CORNER: - return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, varray); case ATTR_DOMAIN_POINT: - return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, varray); case ATTR_DOMAIN_FACE: - return blender::bke::adapt_mesh_domain_edge_to_face(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_edge_to_face(*mesh_, varray); default: break; } @@ -896,9 +894,9 @@ static const Mesh *get_mesh_from_component_for_read(const GeometryComponent &com namespace blender::bke { template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)> -static GVArrayPtr make_derived_read_attribute(const void *data, const int domain_size) +static GVArray make_derived_read_attribute(const void *data, const int domain_size) { - return std::make_unique<fn::GVArray_For_DerivedSpan<StructT, ElemT, GetFunc>>( + return VArray<ElemT>::template ForDerivedSpan<StructT, GetFunc>( Span<StructT>((const StructT *)data, domain_size)); } @@ -906,23 +904,22 @@ template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &), void (*SetFunc)(StructT &, ElemT)> -static GVMutableArrayPtr make_derived_write_attribute(void *data, const int domain_size) +static GVMutableArray make_derived_write_attribute(void *data, const int domain_size) { - return std::make_unique<fn::GVMutableArray_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>>( + return VMutableArray<ElemT>::template ForDerivedSpan<StructT, GetFunc, SetFunc>( MutableSpan<StructT>((StructT *)data, domain_size)); } template<typename T> -static GVArrayPtr make_array_read_attribute(const void *data, const int domain_size) +static GVArray make_array_read_attribute(const void *data, const int domain_size) { - return std::make_unique<fn::GVArray_For_Span<T>>(Span<T>((const T *)data, domain_size)); + return VArray<T>::ForSpan(Span<T>((const T *)data, domain_size)); } template<typename T> -static GVMutableArrayPtr make_array_write_attribute(void *data, const int domain_size) +static GVMutableArray make_array_write_attribute(void *data, const int domain_size) { - return std::make_unique<fn::GVMutableArray_For_MutableSpan<T>>( - MutableSpan<T>((T *)data, domain_size)); + return VMutableArray<T>::ForSpan(MutableSpan<T>((T *)data, domain_size)); } static float3 get_vertex_position(const MVert &vert) @@ -999,23 +996,23 @@ static void set_crease(MEdge &edge, float value) edge.crease = round_fl_to_uchar_clamp(value * 255.0f); } -class VMutableArray_For_VertexWeights final : public VMutableArray<float> { +class VMutableArray_For_VertexWeights final : public VMutableArrayImpl<float> { private: MDeformVert *dverts_; const int dvert_index_; public: VMutableArray_For_VertexWeights(MDeformVert *dverts, const int totvert, const int dvert_index) - : VMutableArray<float>(totvert), dverts_(dverts), dvert_index_(dvert_index) + : VMutableArrayImpl<float>(totvert), dverts_(dverts), dvert_index_(dvert_index) { } - float get_impl(const int64_t index) const override + float get(const int64_t index) const override { return get_internal(dverts_, dvert_index_, index); } - void set_impl(const int64_t index, const float value) override + void set(const int64_t index, const float value) override { MDeformWeight *weight = BKE_defvert_ensure_index(&dverts_[index], dvert_index_); weight->weight = value; @@ -1036,18 +1033,18 @@ class VMutableArray_For_VertexWeights final : public VMutableArray<float> { } }; -class VArray_For_VertexWeights final : public VArray<float> { +class VArray_For_VertexWeights final : public VArrayImpl<float> { private: const MDeformVert *dverts_; const int dvert_index_; public: VArray_For_VertexWeights(const MDeformVert *dverts, const int totvert, const int dvert_index) - : VArray<float>(totvert), dverts_(dverts), dvert_index_(dvert_index) + : VArrayImpl<float>(totvert), dverts_(dverts), dvert_index_(dvert_index) { } - float get_impl(const int64_t index) const override + float get(const int64_t index) const override { return VMutableArray_For_VertexWeights::get_internal(dverts_, dvert_index_, index); } @@ -1078,12 +1075,10 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { } if (mesh->dvert == nullptr) { static const float default_value = 0.0f; - return {std::make_unique<fn::GVArray_For_SingleValueRef>( - CPPType::get<float>(), mesh->totvert, &default_value), - ATTR_DOMAIN_POINT}; + return {VArray<float>::ForSingle(default_value, mesh->totvert), ATTR_DOMAIN_POINT}; } - return {std::make_unique<fn::GVArray_For_EmbeddedVArray<float, VArray_For_VertexWeights>>( - mesh->totvert, mesh->dvert, mesh->totvert, vertex_group_index), + return {VArray<float>::For<VArray_For_VertexWeights>( + mesh->dvert, mesh->totvert, vertex_group_index), ATTR_DOMAIN_POINT}; } @@ -1114,11 +1109,9 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { mesh->dvert = (MDeformVert *)CustomData_duplicate_referenced_layer( &mesh->vdata, CD_MDEFORMVERT, mesh->totvert); } - return { - std::make_unique< - fn::GVMutableArray_For_EmbeddedVMutableArray<float, VMutableArray_For_VertexWeights>>( - mesh->totvert, mesh->dvert, mesh->totvert, vertex_group_index), - ATTR_DOMAIN_POINT}; + return {VMutableArray<float>::For<VMutableArray_For_VertexWeights>( + mesh->dvert, mesh->totvert, vertex_group_index), + ATTR_DOMAIN_POINT}; } bool try_delete(GeometryComponent &component, const AttributeIDRef &attribute_id) const final @@ -1187,7 +1180,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider { { } - GVArrayPtr try_get_for_read(const GeometryComponent &component) const final + GVArray try_get_for_read(const GeometryComponent &component) const final { const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); const Mesh *mesh = mesh_component.get_for_read(); @@ -1200,8 +1193,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider { CustomData_has_layer(&mesh->pdata, CD_NORMAL)) { const void *data = CustomData_get_layer(&mesh->pdata, CD_NORMAL); - return std::make_unique<fn::GVArray_For_Span<float3>>( - Span<float3>((const float3 *)data, mesh->totpoly)); + return VArray<float3>::ForSpan(Span<float3>((const float3 *)data, mesh->totpoly)); } Array<float3> normals(mesh->totpoly); @@ -1210,7 +1202,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider { BKE_mesh_calc_poly_normal(poly, &mesh->mloop[poly->loopstart], mesh->mvert, normals[i]); } - return std::make_unique<fn::GVArray_For_ArrayContainer<Array<float3>>>(std::move(normals)); + return VArray<float3>::ForContainer(std::move(normals)); } WriteAttributeLookup try_get_for_write(GeometryComponent &UNUSED(component)) const final diff --git a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc index dfb65a9078d..c6a1c61a96d 100644 --- a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc +++ b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc @@ -141,16 +141,15 @@ int PointCloudComponent::attribute_domain_size(const AttributeDomain domain) con namespace blender::bke { template<typename T> -static GVArrayPtr make_array_read_attribute(const void *data, const int domain_size) +static GVArray make_array_read_attribute(const void *data, const int domain_size) { - return std::make_unique<fn::GVArray_For_Span<T>>(Span<T>((const T *)data, domain_size)); + return VArray<T>::ForSpan(Span<T>((const T *)data, domain_size)); } template<typename T> -static GVMutableArrayPtr make_array_write_attribute(void *data, const int domain_size) +static GVMutableArray make_array_write_attribute(void *data, const int domain_size) { - return std::make_unique<fn::GVMutableArray_For_MutableSpan<T>>( - MutableSpan<T>((T *)data, domain_size)); + return VMutableArray<T>::ForSpan(MutableSpan<T>((T *)data, domain_size)); } /** diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index cd1bafe445a..c250c14f1d7 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -610,24 +610,32 @@ bool BKE_object_has_geometry_set_instances(const Object *ob) if (geometry_set == nullptr) { return false; } - if (geometry_set->has_instances()) { - return true; - } - const bool has_mesh = geometry_set->has_mesh(); - const bool has_pointcloud = geometry_set->has_pointcloud(); - const bool has_volume = geometry_set->has_volume(); - const bool has_curve = geometry_set->has_curve(); - if (ob->type == OB_MESH) { - return has_pointcloud || has_volume || has_curve; - } - if (ob->type == OB_POINTCLOUD) { - return has_mesh || has_volume || has_curve; - } - if (ob->type == OB_VOLUME) { - return has_mesh || has_pointcloud || has_curve; - } - if (ELEM(ob->type, OB_CURVE, OB_FONT)) { - return has_mesh || has_pointcloud || has_volume; + for (const GeometryComponent *component : geometry_set->get_components_for_read()) { + if (component->is_empty()) { + continue; + } + const GeometryComponentType type = component->type(); + bool is_instance = false; + switch (type) { + case GEO_COMPONENT_TYPE_MESH: + is_instance = ob->type != OB_MESH; + break; + case GEO_COMPONENT_TYPE_POINT_CLOUD: + is_instance = ob->type != OB_POINTCLOUD; + break; + case GEO_COMPONENT_TYPE_INSTANCES: + is_instance = true; + break; + case GEO_COMPONENT_TYPE_VOLUME: + is_instance = ob->type != OB_VOLUME; + break; + case GEO_COMPONENT_TYPE_CURVE: + is_instance = !ELEM(ob->type, OB_CURVE, OB_FONT); + break; + } + if (is_instance) { + return true; + } } return false; } diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc index 8a7840acd73..c73da7d9659 100644 --- a/source/blender/blenkernel/intern/geometry_set_instances.cc +++ b/source/blender/blenkernel/intern/geometry_set_instances.cc @@ -89,8 +89,7 @@ GeometrySet object_get_evaluated_geometry_set(const Object &object) static void geometry_set_collect_recursive_collection_instance( const Collection &collection, const float4x4 &transform, Vector<GeometryInstanceGroup> &r_sets) { - float4x4 offset_matrix; - unit_m4(offset_matrix.values); + float4x4 offset_matrix = float4x4::identity(); sub_v3_v3(offset_matrix.values[3], collection.instance_offset); const float4x4 instance_transform = transform * offset_matrix; geometry_set_collect_recursive_collection(collection, instance_transform, r_sets); @@ -183,10 +182,7 @@ static void geometry_set_collect_recursive(const GeometrySet &geometry_set, void geometry_set_gather_instances(const GeometrySet &geometry_set, Vector<GeometryInstanceGroup> &r_instance_groups) { - float4x4 unit_transform; - unit_m4(unit_transform.values); - - geometry_set_collect_recursive(geometry_set, unit_transform, r_instance_groups); + geometry_set_collect_recursive(geometry_set, float4x4::identity(), r_instance_groups); } void geometry_set_gather_instances_attribute_info(Span<GeometryInstanceGroup> set_groups, @@ -364,12 +360,12 @@ static void join_attributes(Span<GeometryInstanceGroup> set_groups, result.attribute_try_create( entry.key, domain_output, data_type_output, AttributeInitDefault()); WriteAttributeLookup write_attribute = result.attribute_try_get_for_write(attribute_id); - if (!write_attribute || &write_attribute.varray->type() != cpp_type || + if (!write_attribute || &write_attribute.varray.type() != cpp_type || write_attribute.domain != domain_output) { continue; } - fn::GVMutableArray_GSpan dst_span{*write_attribute.varray}; + fn::GVMutableArray_GSpan dst_span{write_attribute.varray}; int offset = 0; for (const GeometryInstanceGroup &set_group : set_groups) { @@ -381,11 +377,11 @@ static void join_attributes(Span<GeometryInstanceGroup> set_groups, if (domain_size == 0) { continue; /* Domain size is 0, so no need to increment the offset. */ } - GVArrayPtr source_attribute = component.attribute_try_get_for_read( + GVArray source_attribute = component.attribute_try_get_for_read( attribute_id, domain_output, data_type_output); if (source_attribute) { - fn::GVArray_GSpan src_span{*source_attribute}; + fn::GVArray_GSpan src_span{source_attribute}; const void *src_buffer = src_span.data(); for (const int UNUSED(i) : set_group.transforms.index_range()) { void *dst_buffer = dst_span[offset]; diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index bea65030c06..04c5b09ed27 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -320,6 +320,7 @@ IDTypeInfo IDType_ID_GD = { .name_plural = "grease_pencils", .translation_context = BLT_I18NCONTEXT_ID_GPENCIL, .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE, + .asset_type_info = NULL, .init_data = NULL, .copy_data = greasepencil_copy_data, diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc index debdf44b0bb..fffc13c49a8 100644 --- a/source/blender/blenkernel/intern/gpencil_geom.cc +++ b/source/blender/blenkernel/intern/gpencil_geom.cc @@ -3122,8 +3122,9 @@ bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd, bGPDstroke *gps, bGPDstroke *next_stroke, int tag_flags, - bool select, - int limit) + const bool select, + const bool flat_cap, + const int limit) { tGPDeleteIsland *islands = (tGPDeleteIsland *)MEM_callocN( sizeof(tGPDeleteIsland) * (gps->totpoints + 1) / 2, "gp_point_islands"); @@ -3171,6 +3172,9 @@ bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd, for (idx = 0; idx < num_islands; idx++) { tGPDeleteIsland *island = &islands[idx]; new_stroke = BKE_gpencil_stroke_duplicate(gps, false, true); + if (flat_cap) { + new_stroke->caps[1 - (idx % 2)] = GP_STROKE_CAP_FLAT; + } /* if cyclic and first stroke, save to join later */ if ((is_cyclic) && (gps_first == nullptr)) { diff --git a/source/blender/blenkernel/intern/hair.c b/source/blender/blenkernel/intern/hair.c index 7433ee7ac29..9b4a1ba5b38 100644 --- a/source/blender/blenkernel/intern/hair.c +++ b/source/blender/blenkernel/intern/hair.c @@ -182,6 +182,7 @@ IDTypeInfo IDType_ID_HA = { .name_plural = "hairs", .translation_context = BLT_I18NCONTEXT_ID_HAIR, .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE, + .asset_type_info = NULL, .init_data = hair_init_data, .copy_data = hair_copy_data, diff --git a/source/blender/blenkernel/intern/icons.cc b/source/blender/blenkernel/intern/icons.cc index 208e911298a..b9ccbedfa81 100644 --- a/source/blender/blenkernel/intern/icons.cc +++ b/source/blender/blenkernel/intern/icons.cc @@ -35,6 +35,7 @@ #include "DNA_gpencil_types.h" #include "DNA_light_types.h" #include "DNA_material_types.h" +#include "DNA_node_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" @@ -375,6 +376,7 @@ PreviewImage **BKE_previewimg_id_get_p(const ID *id) ID_PRV_CASE(ID_SCE, Scene); ID_PRV_CASE(ID_SCR, bScreen); ID_PRV_CASE(ID_AC, bAction); + ID_PRV_CASE(ID_NT, bNodeTree); #undef ID_PRV_CASE default: break; diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 0530d537daf..99700634288 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -112,12 +112,26 @@ #include "DNA_view3d_types.h" static CLG_LogRef LOG = {"bke.image"}; -static ThreadMutex *image_mutex; static void image_init(Image *ima, short source, short type); static void image_free_packedfiles(Image *ima); static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src); +/* Reset runtime image fields when datablock is being initialized. */ +static void image_runtime_reset(struct Image *image) +{ + memset(&image->runtime, 0, sizeof(image->runtime)); + image->runtime.cache_mutex = MEM_mallocN(sizeof(ThreadMutex), "image runtime cache_mutex"); + BLI_mutex_init(image->runtime.cache_mutex); +} + +/* Reset runtime image fields when datablock is being copied. */ +static void image_runtime_reset_on_copy(struct Image *image) +{ + image->runtime.cache_mutex = MEM_mallocN(sizeof(ThreadMutex), "image runtime cache_mutex"); + BLI_mutex_init(image->runtime.cache_mutex); +} + static void image_init_data(ID *id) { Image *image = (Image *)id; @@ -167,6 +181,8 @@ static void image_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c else { image_dst->preview = NULL; } + + image_runtime_reset_on_copy(image_dst); } static void image_free_data(ID *id) @@ -194,6 +210,9 @@ static void image_free_data(ID *id) BLI_freelistN(&image->tiles); BLI_freelistN(&image->gpu_refresh_areas); + + BLI_mutex_end(image->runtime.cache_mutex); + MEM_freeN(image->runtime.cache_mutex); } static void image_foreach_cache(ID *id, @@ -325,6 +344,8 @@ static void image_blend_read_data(BlendDataReader *reader, ID *id) ima->lastused = 0; ima->gpuflag = 0; BLI_listbase_clear(&ima->gpu_refresh_areas); + + image_runtime_reset(ima); } static void image_blend_read_lib(BlendLibReader *UNUSED(reader), ID *id) @@ -348,6 +369,7 @@ IDTypeInfo IDType_ID_IM = { .name_plural = "images", .translation_context = BLT_I18NCONTEXT_ID_IMAGE, .flags = IDTYPE_FLAGS_NO_ANIMDATA | IDTYPE_FLAGS_APPEND_IS_REUSABLE, + .asset_type_info = NULL, .init_data = image_init_data, .copy_data = image_copy_data, @@ -452,16 +474,6 @@ static struct ImBuf *imagecache_get(Image *image, int index, bool *r_is_cached_e return NULL; } -void BKE_images_init(void) -{ - image_mutex = BLI_mutex_alloc(); -} - -void BKE_images_exit(void) -{ - BLI_mutex_free(image_mutex); -} - /* ***************** ALLOC & FREE, DATA MANAGING *************** */ static void image_free_cached_frames(Image *image) @@ -514,7 +526,7 @@ static void image_free_anims(Image *ima) void BKE_image_free_buffers_ex(Image *ima, bool do_lock) { if (do_lock) { - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(ima->runtime.cache_mutex); } image_free_cached_frames(ima); @@ -528,7 +540,7 @@ void BKE_image_free_buffers_ex(Image *ima, bool do_lock) BKE_image_free_gputextures(ima); if (do_lock) { - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(ima->runtime.cache_mutex); } } @@ -567,6 +579,8 @@ static void image_init(Image *ima, short source, short type) } } + image_runtime_reset(ima); + BKE_color_managed_colorspace_settings_init(&ima->colorspace_settings); ima->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Image Stereo Format"); } @@ -640,7 +654,9 @@ void BKE_image_merge(Main *bmain, Image *dest, Image *source) { /* sanity check */ if (dest && source && dest != source) { - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(source->runtime.cache_mutex); + BLI_mutex_lock(dest->runtime.cache_mutex); + if (source->cache != NULL) { struct MovieCacheIter *iter; iter = IMB_moviecacheIter_new(source->cache); @@ -652,7 +668,9 @@ void BKE_image_merge(Main *bmain, Image *dest, Image *source) } IMB_moviecacheIter_free(iter); } - BLI_mutex_unlock(image_mutex); + + BLI_mutex_unlock(dest->runtime.cache_mutex); + BLI_mutex_unlock(source->runtime.cache_mutex); BKE_id_free(bmain, source); } @@ -1243,7 +1261,8 @@ static uintptr_t image_mem_size(Image *image) return 0; } - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(image->runtime.cache_mutex); + if (image->cache != NULL) { struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache); @@ -1277,7 +1296,8 @@ static uintptr_t image_mem_size(Image *image) } IMB_moviecacheIter_free(iter); } - BLI_mutex_unlock(image_mutex); + + BLI_mutex_unlock(image->runtime.cache_mutex); return size; } @@ -1361,11 +1381,11 @@ static bool imagecache_check_free_anim(ImBuf *ibuf, void *UNUSED(userkey), void /* except_frame is weak, only works for seqs without offset... */ void BKE_image_free_anim_ibufs(Image *ima, int except_frame) { - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(ima->runtime.cache_mutex); if (ima->cache != NULL) { IMB_moviecache_cleanup(ima->cache, imagecache_check_free_anim, &except_frame); } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(ima->runtime.cache_mutex); } void BKE_image_all_free_anim_ibufs(Main *bmain, int cfra) @@ -3284,7 +3304,7 @@ void BKE_image_ensure_viewer_views(const RenderData *rd, Image *ima, ImageUser * } if (do_reset) { - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(ima->runtime.cache_mutex); image_free_cached_frames(ima); BKE_image_free_views(ima); @@ -3292,7 +3312,7 @@ void BKE_image_ensure_viewer_views(const RenderData *rd, Image *ima, ImageUser * /* add new views */ image_viewer_create_views(rd, ima); - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(ima->runtime.cache_mutex); } BLI_thread_unlock(LOCK_DRAW_IMAGE); @@ -3556,7 +3576,7 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) return; } - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(ima->runtime.cache_mutex); switch (signal) { case IMA_SIGNAL_FREE: @@ -3676,7 +3696,7 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) break; } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(ima->runtime.cache_mutex); /* don't use notifiers because they are not 100% sure to succeeded * this also makes sure all scenes are accounted for. */ @@ -5130,11 +5150,11 @@ ImBuf *BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock) { ImBuf *ibuf; - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(ima->runtime.cache_mutex); ibuf = image_acquire_ibuf(ima, iuser, r_lock); - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(ima->runtime.cache_mutex); return ibuf; } @@ -5153,9 +5173,9 @@ void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock) } if (ibuf) { - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(ima->runtime.cache_mutex); IMB_freeImBuf(ibuf); - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(ima->runtime.cache_mutex); } } @@ -5169,7 +5189,7 @@ bool BKE_image_has_ibuf(Image *ima, ImageUser *iuser) return false; } - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(ima->runtime.cache_mutex); ibuf = image_get_cached_ibuf(ima, iuser, NULL, NULL, NULL); @@ -5177,7 +5197,7 @@ bool BKE_image_has_ibuf(Image *ima, ImageUser *iuser) ibuf = image_acquire_ibuf(ima, iuser, NULL); } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(ima->runtime.cache_mutex); IMB_freeImBuf(ibuf); @@ -5197,6 +5217,7 @@ typedef struct ImagePoolItem { typedef struct ImagePool { ListBase image_buffers; BLI_mempool *memory_pool; + ThreadMutex mutex; } ImagePool; ImagePool *BKE_image_pool_new(void) @@ -5204,21 +5225,28 @@ ImagePool *BKE_image_pool_new(void) ImagePool *pool = MEM_callocN(sizeof(ImagePool), "Image Pool"); pool->memory_pool = BLI_mempool_create(sizeof(ImagePoolItem), 0, 128, BLI_MEMPOOL_NOP); + BLI_mutex_init(&pool->mutex); + return pool; } void BKE_image_pool_free(ImagePool *pool) { /* Use single lock to dereference all the image buffers. */ - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(&pool->mutex); for (ImagePoolItem *item = pool->image_buffers.first; item != NULL; item = item->next) { if (item->ibuf != NULL) { + BLI_mutex_lock(item->image->runtime.cache_mutex); IMB_freeImBuf(item->ibuf); + BLI_mutex_unlock(item->image->runtime.cache_mutex); } } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(&pool->mutex); BLI_mempool_destroy(pool->memory_pool); + + BLI_mutex_end(&pool->mutex); + MEM_freeN(pool); } @@ -5250,28 +5278,34 @@ ImBuf *BKE_image_pool_acquire_ibuf(Image *ima, ImageUser *iuser, ImagePool *pool } if (pool == NULL) { - /* pool could be NULL, in this case use general acquire function */ + /* Pool could be NULL, in this case use general acquire function. */ return BKE_image_acquire_ibuf(ima, iuser, NULL); } image_get_entry_and_index(ima, iuser, &entry, &index); + /* Use double-checked locking, to avoid locking when the requested image buffer is already in the + * pool. */ + ibuf = image_pool_find_item(pool, ima, entry, index, &found); if (found) { return ibuf; } - BLI_mutex_lock(image_mutex); + /* Lock the pool, to allow thread-safe modification of the content of the pool. */ + BLI_mutex_lock(&pool->mutex); ibuf = image_pool_find_item(pool, ima, entry, index, &found); - /* will also create item even in cases image buffer failed to load, - * prevents trying to load the same buggy file multiple times - */ + /* Will also create item even in cases image buffer failed to load, + * prevents trying to load the same buggy file multiple times. */ if (!found) { ImagePoolItem *item; - ibuf = image_acquire_ibuf(ima, iuser, NULL); + /* Thread-safe acquisition of an image buffer from the image. + * The acquisition does not use image pools, so there is no risk of recursive or out-of-order + * mutex locking. */ + ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL); item = BLI_mempool_alloc(pool->memory_pool); item->image = ima; @@ -5282,7 +5316,7 @@ ImBuf *BKE_image_pool_acquire_ibuf(Image *ima, ImageUser *iuser, ImagePool *pool BLI_addtail(&pool->image_buffers, item); } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(&pool->mutex); return ibuf; } @@ -5671,7 +5705,7 @@ bool BKE_image_is_dirty_writable(Image *image, bool *r_is_writable) bool is_dirty = false; bool is_writable = false; - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(image->runtime.cache_mutex); if (image->cache != NULL) { struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache); @@ -5686,7 +5720,7 @@ bool BKE_image_is_dirty_writable(Image *image, bool *r_is_writable) } IMB_moviecacheIter_free(iter); } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(image->runtime.cache_mutex); if (r_is_writable) { *r_is_writable = is_writable; @@ -5715,7 +5749,7 @@ bool BKE_image_buffer_format_writable(ImBuf *ibuf) void BKE_image_file_format_set(Image *image, int ftype, const ImbFormatOptions *options) { - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(image->runtime.cache_mutex); if (image->cache != NULL) { struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache); @@ -5729,14 +5763,14 @@ void BKE_image_file_format_set(Image *image, int ftype, const ImbFormatOptions * } IMB_moviecacheIter_free(iter); } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(image->runtime.cache_mutex); } bool BKE_image_has_loaded_ibuf(Image *image) { bool has_loaded_ibuf = false; - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(image->runtime.cache_mutex); if (image->cache != NULL) { struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache); @@ -5746,7 +5780,7 @@ bool BKE_image_has_loaded_ibuf(Image *image) } IMB_moviecacheIter_free(iter); } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(image->runtime.cache_mutex); return has_loaded_ibuf; } @@ -5759,7 +5793,7 @@ ImBuf *BKE_image_get_ibuf_with_name(Image *image, const char *name) { ImBuf *ibuf = NULL; - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(image->runtime.cache_mutex); if (image->cache != NULL) { struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache); @@ -5774,7 +5808,7 @@ ImBuf *BKE_image_get_ibuf_with_name(Image *image, const char *name) } IMB_moviecacheIter_free(iter); } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(image->runtime.cache_mutex); return ibuf; } @@ -5792,7 +5826,7 @@ ImBuf *BKE_image_get_first_ibuf(Image *image) { ImBuf *ibuf = NULL; - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(image->runtime.cache_mutex); if (image->cache != NULL) { struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache); @@ -5805,7 +5839,7 @@ ImBuf *BKE_image_get_first_ibuf(Image *image) } IMB_moviecacheIter_free(iter); } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(image->runtime.cache_mutex); return ibuf; } diff --git a/source/blender/blenkernel/intern/image_gen.c b/source/blender/blenkernel/intern/image_gen.c index 943909cc90f..bef14b6ad70 100644 --- a/source/blender/blenkernel/intern/image_gen.c +++ b/source/blender/blenkernel/intern/image_gen.c @@ -369,7 +369,7 @@ static void checker_board_text( char text[3] = {'A', '1', '\0'}; const int mono = blf_mono_font_render; - BLF_size(mono, 54, 72); /* hard coded size! */ + BLF_size(mono, 54.0f, 72); /* hard coded size! */ /* OCIO_TODO: using NULL as display will assume using sRGB display * this is correct since currently generated images are assumed to be in sRGB space, diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index 26a1240080f..4532e2f9883 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -185,6 +185,7 @@ IDTypeInfo IDType_ID_IP = { .name_plural = "ipos", .translation_context = "", .flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING | IDTYPE_FLAGS_NO_ANIMDATA, + .asset_type_info = NULL, .init_data = NULL, .copy_data = NULL, diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index c09fcf0715e..d601c9594d0 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -213,6 +213,7 @@ IDTypeInfo IDType_ID_KE = { .name_plural = "shape_keys", .translation_context = BLT_I18NCONTEXT_ID_SHAPEKEY, .flags = IDTYPE_FLAGS_NO_LIBLINKING, + .asset_type_info = NULL, .init_data = NULL, .copy_data = shapekey_copy_data, diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index a2da59bca58..98b801160fb 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -197,6 +197,7 @@ IDTypeInfo IDType_ID_LT = { .name_plural = "lattices", .translation_context = BLT_I18NCONTEXT_ID_LATTICE, .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE, + .asset_type_info = NULL, .init_data = lattice_init_data, .copy_data = lattice_copy_data, diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index cd5b266eb75..0b0ed199981 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -99,6 +99,7 @@ IDTypeInfo IDType_ID_LINK_PLACEHOLDER = { .name_plural = "link_placeholders", .translation_context = BLT_I18NCONTEXT_ID_ID, .flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING, + .asset_type_info = NULL, .init_data = NULL, .copy_data = NULL, diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index 9ed7218027f..66a550ec6b0 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -1028,7 +1028,7 @@ static void lib_override_library_proxy_convert_do(Main *bmain, if (success) { CLOG_INFO(&LOG, 4, - "Proxy object '%s' successfuly converted to library overrides", + "Proxy object '%s' successfully converted to library overrides", ob_proxy->id.name); /* Remove the instance empty from this scene, the items now have an overridden collection * instead. */ diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c index 4165452801c..74750a9b61a 100644 --- a/source/blender/blenkernel/intern/lib_query.c +++ b/source/blender/blenkernel/intern/lib_query.c @@ -76,48 +76,52 @@ typedef struct LibraryForeachIDData { BLI_LINKSTACK_DECLARE(ids_todo, ID *); } LibraryForeachIDData; -bool BKE_lib_query_foreachid_process(LibraryForeachIDData *data, ID **id_pp, int cb_flag) +/** Check whether current iteration over ID usages should be stopped or not. + * \return true if the iteration should be stopped, false otherwise. */ +bool BKE_lib_query_foreachid_iter_stop(LibraryForeachIDData *data) { - if (!(data->status & IDWALK_STOP)) { - const int flag = data->flag; - ID *old_id = *id_pp; - - /* Update the callback flags with the ones defined (or forbidden) in `data` by the generic - * caller code. */ - cb_flag = ((cb_flag | data->cb_flag) & ~data->cb_flag_clear); - - /* Update the callback flags with some extra information regarding overrides: all 'loopback', - * 'internal', 'embedded' etc. ID pointers are never overridable. */ - if (cb_flag & - (IDWALK_CB_INTERNAL | IDWALK_CB_LOOPBACK | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) { - cb_flag |= IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE; - } + return (data->status & IDWALK_STOP) != 0; +} - const int callback_return = data->callback( - &(struct LibraryIDLinkCallbackData){.user_data = data->user_data, - .bmain = data->bmain, - .id_owner = data->owner_id, - .id_self = data->self_id, - .id_pointer = id_pp, - .cb_flag = cb_flag}); - if (flag & IDWALK_READONLY) { - BLI_assert(*(id_pp) == old_id); - } - if (old_id && (flag & IDWALK_RECURSE)) { - if (BLI_gset_add((data)->ids_handled, old_id)) { - if (!(callback_return & IDWALK_RET_STOP_RECURSION)) { - BLI_LINKSTACK_PUSH(data->ids_todo, old_id); - } +void BKE_lib_query_foreachid_process(LibraryForeachIDData *data, ID **id_pp, int cb_flag) +{ + if (BKE_lib_query_foreachid_iter_stop(data)) { + return; + } + + const int flag = data->flag; + ID *old_id = *id_pp; + + /* Update the callback flags with the ones defined (or forbidden) in `data` by the generic + * caller code. */ + cb_flag = ((cb_flag | data->cb_flag) & ~data->cb_flag_clear); + + /* Update the callback flags with some extra information regarding overrides: all 'loopback', + * 'internal', 'embedded' etc. ID pointers are never overridable. */ + if (cb_flag & (IDWALK_CB_INTERNAL | IDWALK_CB_LOOPBACK | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) { + cb_flag |= IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE; + } + + const int callback_return = data->callback( + &(struct LibraryIDLinkCallbackData){.user_data = data->user_data, + .bmain = data->bmain, + .id_owner = data->owner_id, + .id_self = data->self_id, + .id_pointer = id_pp, + .cb_flag = cb_flag}); + if (flag & IDWALK_READONLY) { + BLI_assert(*(id_pp) == old_id); + } + if (old_id && (flag & IDWALK_RECURSE)) { + if (BLI_gset_add((data)->ids_handled, old_id)) { + if (!(callback_return & IDWALK_RET_STOP_RECURSION)) { + BLI_LINKSTACK_PUSH(data->ids_todo, old_id); } } - if (callback_return & IDWALK_RET_STOP_ITER) { - data->status |= IDWALK_STOP; - return false; - } - return true; } - - return false; + if (callback_return & IDWALK_RET_STOP_ITER) { + data->status |= IDWALK_STOP; + } } int BKE_lib_query_foreachid_process_flags_get(LibraryForeachIDData *data) @@ -139,7 +143,7 @@ int BKE_lib_query_foreachid_process_callback_flag_override(LibraryForeachIDData return cb_flag_backup; } -static void library_foreach_ID_link(Main *bmain, +static bool library_foreach_ID_link(Main *bmain, ID *id_owner, ID *id, LibraryIDLinkCallback callback, @@ -158,19 +162,24 @@ void BKE_lib_query_idpropertiesForeachIDLink_callback(IDProperty *id_prop, void BKE_LIB_FOREACHID_PROCESS_ID(data, id_prop->data.pointer, cb_flag); } -bool BKE_library_foreach_ID_embedded(LibraryForeachIDData *data, ID **id_pp) +/** Process embedded ID pointers (root nodetrees, master collections, ...). + * + * Those require specific care, since they are technically sub-data of their owner, yet in some + * cases they still behave as regular IDs. */ +void BKE_library_foreach_ID_embedded(LibraryForeachIDData *data, ID **id_pp) { /* Needed e.g. for callbacks handling relationships. This call shall be absolutely read-only. */ ID *id = *id_pp; const int flag = data->flag; - if (!BKE_lib_query_foreachid_process(data, id_pp, IDWALK_CB_EMBEDDED)) { - return false; + BKE_lib_query_foreachid_process(data, id_pp, IDWALK_CB_EMBEDDED); + if (BKE_lib_query_foreachid_iter_stop(data)) { + return; } BLI_assert(id == *id_pp); if (id == NULL) { - return true; + return; } if (flag & IDWALK_IGNORE_EMBEDDED_ID) { @@ -186,14 +195,24 @@ bool BKE_library_foreach_ID_embedded(LibraryForeachIDData *data, ID **id_pp) } } else { - library_foreach_ID_link( - data->bmain, data->owner_id, id, data->callback, data->user_data, data->flag, data); + if (!library_foreach_ID_link( + data->bmain, data->owner_id, id, data->callback, data->user_data, data->flag, data)) { + data->status |= IDWALK_STOP; + return; + } } +} - return true; +static void library_foreach_ID_data_cleanup(LibraryForeachIDData *data) +{ + if (data->ids_handled != NULL) { + BLI_gset_free(data->ids_handled, NULL); + BLI_LINKSTACK_FREE(data->ids_todo); + } } -static void library_foreach_ID_link(Main *bmain, +/** \return false in case iteration over ID pointers must be stopped, true otherwise. */ +static bool library_foreach_ID_link(Main *bmain, ID *id_owner, ID *id, LibraryIDLinkCallback callback, @@ -210,6 +229,10 @@ static void library_foreach_ID_link(Main *bmain, flag |= IDWALK_READONLY; flag &= ~IDWALK_DO_INTERNAL_RUNTIME_POINTERS; + /* NOTE: This function itself should never be called recursively when IDWALK_RECURSE is set, + * see also comments in #BKE_library_foreach_ID_embedded. + * This is why we can always create this data here, and do not need to try and re-use it from + * `inherit_data`. */ data.ids_handled = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); BLI_LINKSTACK_INIT(data.ids_todo); @@ -224,10 +247,26 @@ static void library_foreach_ID_link(Main *bmain, data.user_data = user_data; #define CALLBACK_INVOKE_ID(check_id, cb_flag) \ - BKE_LIB_FOREACHID_PROCESS_ID(&data, check_id, cb_flag) + { \ + CHECK_TYPE_ANY((check_id), ID *, void *); \ + BKE_lib_query_foreachid_process(&data, (ID **)&(check_id), (cb_flag)); \ + if (BKE_lib_query_foreachid_iter_stop(&data)) { \ + library_foreach_ID_data_cleanup(&data); \ + return false; \ + } \ + } \ + ((void)0) #define CALLBACK_INVOKE(check_id_super, cb_flag) \ - BKE_LIB_FOREACHID_PROCESS_IDSUPER(&data, check_id_super, cb_flag) + { \ + CHECK_TYPE(&((check_id_super)->id), ID *); \ + BKE_lib_query_foreachid_process(&data, (ID **)&(check_id_super), (cb_flag)); \ + if (BKE_lib_query_foreachid_iter_stop(&data)) { \ + library_foreach_ID_data_cleanup(&data); \ + return false; \ + } \ + } \ + ((void)0) for (; id != NULL; id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL) { data.self_id = id; @@ -269,6 +308,10 @@ static void library_foreach_ID_link(Main *bmain, to_id_entry = to_id_entry->next) { BKE_lib_query_foreachid_process( &data, to_id_entry->id_pointer.to, to_id_entry->usage_flag); + if (BKE_lib_query_foreachid_iter_stop(&data)) { + library_foreach_ID_data_cleanup(&data); + return false; + } } continue; } @@ -292,26 +335,33 @@ static void library_foreach_ID_link(Main *bmain, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, &data); + if (BKE_lib_query_foreachid_iter_stop(&data)) { + library_foreach_ID_data_cleanup(&data); + return false; + } AnimData *adt = BKE_animdata_from_id(id); if (adt) { BKE_animdata_foreach_id(adt, &data); + if (BKE_lib_query_foreachid_iter_stop(&data)) { + library_foreach_ID_data_cleanup(&data); + return false; + } } const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id); if (id_type->foreach_id != NULL) { id_type->foreach_id(id, &data); - if (data.status & IDWALK_STOP) { - break; + if (BKE_lib_query_foreachid_iter_stop(&data)) { + library_foreach_ID_data_cleanup(&data); + return false; } } } - if (data.ids_handled) { - BLI_gset_free(data.ids_handled, NULL); - BLI_LINKSTACK_FREE(data.ids_todo); - } + library_foreach_ID_data_cleanup(&data); + return true; #undef CALLBACK_INVOKE_ID #undef CALLBACK_INVOKE diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c index 905ac5af512..014c923f04f 100644 --- a/source/blender/blenkernel/intern/lib_remap.c +++ b/source/blender/blenkernel/intern/lib_remap.c @@ -132,7 +132,8 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data) const bool is_obj = (GS(id_owner->name) == ID_OB); const bool is_obj_proxy = (is_obj && (((Object *)id_owner)->proxy || ((Object *)id_owner)->proxy_group)); - const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id_owner)); + const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id_owner) && + (id_remap_data->flag & ID_REMAP_FORCE_OBDATA_IN_EDITMODE) == 0); const bool is_never_null = ((cb_flag & IDWALK_CB_NEVER_NULL) && (new_id == NULL) && (id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0); const bool skip_reference = (id_remap_data->flag & ID_REMAP_SKIP_OVERRIDE_LIBRARY) != 0; @@ -669,57 +670,10 @@ void BKE_libblock_relink_ex( DEG_relations_tag_update(bmain); } +static void libblock_relink_to_newid(Main *bmain, ID *id, const int remap_flag); static int id_relink_to_newid_looper(LibraryIDLinkCallbackData *cb_data) { const int cb_flag = cb_data->cb_flag; - if (cb_flag & IDWALK_CB_EMBEDDED) { - return IDWALK_RET_NOP; - } - - ID **id_pointer = cb_data->id_pointer; - ID *id = *id_pointer; - if (id) { - /* See: NEW_ID macro */ - if (id->newid) { - BKE_library_update_ID_link_user(id->newid, id, cb_flag); - id = id->newid; - *id_pointer = id; - } - if (id->tag & LIB_TAG_NEW) { - id->tag &= ~LIB_TAG_NEW; - BKE_libblock_relink_to_newid(id); - } - } - return IDWALK_RET_NOP; -} - -/** - * Similar to #libblock_relink_ex, - * but is remapping IDs to their newid value if non-NULL, in given \a id. - * - * Very specific usage, not sure we'll keep it on the long run, - * currently only used in Object/Collection duplication code... - * - * WARNING: This is a deprecated version of this function, should not be used by new code. See - * #BKE_libblock_relink_to_newid_new below. - */ -void BKE_libblock_relink_to_newid(ID *id) -{ - if (ID_IS_LINKED(id)) { - return; - } - - BKE_library_foreach_ID_link(NULL, id, id_relink_to_newid_looper, NULL, 0); -} - -/* ************************ - * FIXME: Port all usages of #BKE_libblock_relink_to_newid to this - * #BKE_libblock_relink_to_newid_new new code and remove old one. - ************************** */ -static void libblock_relink_to_newid_new(Main *bmain, ID *id); -static int id_relink_to_newid_looper_new(LibraryIDLinkCallbackData *cb_data) -{ - const int cb_flag = cb_data->cb_flag; if (cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) { return IDWALK_RET_NOP; } @@ -729,31 +683,31 @@ static int id_relink_to_newid_looper_new(LibraryIDLinkCallbackData *cb_data) ID **id_pointer = cb_data->id_pointer; ID *id = *id_pointer; if (id) { + const int remap_flag = POINTER_AS_INT(cb_data->user_data); /* See: NEW_ID macro */ if (id->newid != NULL) { - BKE_libblock_relink_ex(bmain, - id_owner, - id, - id->newid, - ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY); + const int remap_flag_final = remap_flag | ID_REMAP_SKIP_INDIRECT_USAGE | + ID_REMAP_SKIP_OVERRIDE_LIBRARY; + BKE_libblock_relink_ex(bmain, id_owner, id, id->newid, (short)remap_flag_final); id = id->newid; } if (id->tag & LIB_TAG_NEW) { id->tag &= ~LIB_TAG_NEW; - libblock_relink_to_newid_new(bmain, id); + libblock_relink_to_newid(bmain, id, remap_flag); } } return IDWALK_RET_NOP; } -static void libblock_relink_to_newid_new(Main *bmain, ID *id) +static void libblock_relink_to_newid(Main *bmain, ID *id, const int remap_flag) { if (ID_IS_LINKED(id)) { return; } id->tag &= ~LIB_TAG_NEW; - BKE_library_foreach_ID_link(bmain, id, id_relink_to_newid_looper_new, NULL, 0); + BKE_library_foreach_ID_link( + bmain, id, id_relink_to_newid_looper, POINTER_FROM_INT(remap_flag), 0); } /** @@ -765,7 +719,7 @@ static void libblock_relink_to_newid_new(Main *bmain, ID *id) * Very specific usage, not sure we'll keep it on the long run, * currently only used in Object/Collection duplication code... */ -void BKE_libblock_relink_to_newid_new(Main *bmain, ID *id) +void BKE_libblock_relink_to_newid(Main *bmain, ID *id, const int remap_flag) { if (ID_IS_LINKED(id)) { return; @@ -774,7 +728,7 @@ void BKE_libblock_relink_to_newid_new(Main *bmain, ID *id) BLI_assert(bmain->relations == NULL); BKE_layer_collection_resync_forbid(); - libblock_relink_to_newid_new(bmain, id); + libblock_relink_to_newid(bmain, id, remap_flag); BKE_layer_collection_resync_allow(); BKE_main_collection_sync_remap(bmain); } diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 1dba353d8ce..74b1a612ccf 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -69,6 +69,7 @@ IDTypeInfo IDType_ID_LI = { .name_plural = "libraries", .translation_context = BLT_I18NCONTEXT_ID_LIBRARY, .flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING | IDTYPE_FLAGS_NO_ANIMDATA, + .asset_type_info = NULL, .init_data = NULL, .copy_data = NULL, diff --git a/source/blender/blenkernel/intern/light.c b/source/blender/blenkernel/intern/light.c index a6150028f46..305df19b70d 100644 --- a/source/blender/blenkernel/intern/light.c +++ b/source/blender/blenkernel/intern/light.c @@ -129,7 +129,8 @@ static void light_foreach_id(ID *id, LibraryForeachIDData *data) Light *lamp = (Light *)id; if (lamp->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - BKE_library_foreach_ID_embedded(data, (ID **)&lamp->nodetree); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_library_foreach_ID_embedded(data, (ID **)&lamp->nodetree)); } } @@ -194,6 +195,7 @@ IDTypeInfo IDType_ID_LA = { .name_plural = "lights", .translation_context = BLT_I18NCONTEXT_ID_LIGHT, .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE, + .asset_type_info = NULL, .init_data = light_init_data, .copy_data = light_copy_data, diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c index 57ad6695db4..58390d8e912 100644 --- a/source/blender/blenkernel/intern/lightprobe.c +++ b/source/blender/blenkernel/intern/lightprobe.c @@ -92,6 +92,7 @@ IDTypeInfo IDType_ID_LP = { .name_plural = "lightprobes", .translation_context = BLT_I18NCONTEXT_ID_LIGHTPROBE, .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE, + .asset_type_info = NULL, .init_data = lightprobe_init_data, .copy_data = NULL, diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c index a1c93920731..7300dff3a09 100644 --- a/source/blender/blenkernel/intern/linestyle.c +++ b/source/blender/blenkernel/intern/linestyle.c @@ -155,12 +155,14 @@ static void linestyle_foreach_id(ID *id, LibraryForeachIDData *data) for (int i = 0; i < MAX_MTEX; i++) { if (linestyle->mtex[i]) { - BKE_texture_mtex_foreach_id(data, linestyle->mtex[i]); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_texture_mtex_foreach_id(data, linestyle->mtex[i])); } } if (linestyle->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - BKE_library_foreach_ID_embedded(data, (ID **)&linestyle->nodetree); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_library_foreach_ID_embedded(data, (ID **)&linestyle->nodetree)); } LISTBASE_FOREACH (LineStyleModifier *, lsm, &linestyle->color_modifiers) { @@ -752,6 +754,7 @@ IDTypeInfo IDType_ID_LS = { .name_plural = "linestyles", .translation_context = BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE, .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE, + .asset_type_info = NULL, .init_data = linestyle_init_data, .copy_data = linestyle_copy_data, diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index 1d3ebaac303..e3d3b54f458 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -255,6 +255,7 @@ IDTypeInfo IDType_ID_MSK = { .name_plural = "masks", .translation_context = BLT_I18NCONTEXT_ID_MASK, .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE, + .asset_type_info = NULL, .init_data = NULL, .copy_data = mask_copy_data, diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index d82559a27cb..cf3fd4a7c6e 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -166,9 +166,8 @@ static void material_foreach_id(ID *id, LibraryForeachIDData *data) { Material *material = (Material *)id; /* Nodetrees **are owned by IDs**, treat them as mere sub-data and not real ID! */ - if (!BKE_library_foreach_ID_embedded(data, (ID **)&material->nodetree)) { - return; - } + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_library_foreach_ID_embedded(data, (ID **)&material->nodetree)); if (material->texpaintslot != NULL) { BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, material->texpaintslot->ima, IDWALK_CB_NOP); } @@ -262,6 +261,7 @@ IDTypeInfo IDType_ID_MA = { .name_plural = "materials", .translation_context = BLT_I18NCONTEXT_ID_MATERIAL, .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE, + .asset_type_info = NULL, .init_data = material_init_data, .copy_data = material_copy_data, @@ -903,7 +903,7 @@ void BKE_object_materials_test(Main *bmain, Object *ob, ID *id) if ((ob->id.tag & LIB_TAG_MISSING) == 0 && (id->tag & LIB_TAG_MISSING) != 0) { /* Exception: In case the object is a valid data, but its obdata is an empty place-holder, * use object's material slots amount as reference. - * This avoids loosing materials in a local object when its linked obdata gets missing. + * This avoids losing materials in a local object when its linked obdata goes missing. * See T92780. */ BKE_id_material_resize(bmain, id, (short)ob->totcol, false); } diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index 48d31361eac..37fbd2b1e3c 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -189,6 +189,7 @@ IDTypeInfo IDType_ID_MB = { .name_plural = "metaballs", .translation_context = BLT_I18NCONTEXT_ID_METABALL, .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE, + .asset_type_info = NULL, .init_data = metaball_init_data, .copy_data = metaball_copy_data, diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.cc index f0ba83b396b..3f115d98891 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.cc @@ -124,7 +124,7 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int CustomData_MeshMasks_update(&mask, &CD_MASK_DERIVEDMESH); } - mesh_dst->mat = MEM_dupallocN(mesh_src->mat); + mesh_dst->mat = (Material **)MEM_dupallocN(mesh_src->mat); BKE_defgroup_copy_list(&mesh_dst->vertex_group_names, &mesh_src->vertex_group_names); @@ -142,9 +142,9 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int BKE_mesh_update_customdata_pointers(mesh_dst, do_tessface); - mesh_dst->edit_mesh = NULL; + mesh_dst->edit_mesh = nullptr; - mesh_dst->mselect = MEM_dupallocN(mesh_dst->mselect); + mesh_dst->mselect = (MSelect *)MEM_dupallocN(mesh_dst->mselect); /* TODO: Do we want to add flag to prevent this? */ if (mesh_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) { @@ -165,7 +165,7 @@ static void mesh_free_data(ID *id) BKE_editmesh_free_data(mesh->edit_mesh); } MEM_freeN(mesh->edit_mesh); - mesh->edit_mesh = NULL; + mesh->edit_mesh = nullptr; } BKE_mesh_runtime_free_data(mesh); @@ -188,14 +188,14 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address Mesh *mesh = (Mesh *)id; const bool is_undo = BLO_write_is_undo(writer); - CustomDataLayer *vlayers = NULL, vlayers_buff[CD_TEMP_CHUNK_SIZE]; - CustomDataLayer *elayers = NULL, elayers_buff[CD_TEMP_CHUNK_SIZE]; - CustomDataLayer *flayers = NULL, flayers_buff[CD_TEMP_CHUNK_SIZE]; - CustomDataLayer *llayers = NULL, llayers_buff[CD_TEMP_CHUNK_SIZE]; - CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE]; + CustomDataLayer *vlayers = nullptr, vlayers_buff[CD_TEMP_CHUNK_SIZE]; + CustomDataLayer *elayers = nullptr, elayers_buff[CD_TEMP_CHUNK_SIZE]; + CustomDataLayer *flayers = nullptr, flayers_buff[CD_TEMP_CHUNK_SIZE]; + CustomDataLayer *llayers = nullptr, llayers_buff[CD_TEMP_CHUNK_SIZE]; + CustomDataLayer *players = nullptr, players_buff[CD_TEMP_CHUNK_SIZE]; /* cache only - don't write */ - mesh->mface = NULL; + mesh->mface = nullptr; mesh->totface = 0; memset(&mesh->fdata, 0, sizeof(mesh->fdata)); memset(&mesh->runtime, 0, sizeof(mesh->runtime)); @@ -203,22 +203,22 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address /* Do not store actual geometry data in case this is a library override ID. */ if (ID_IS_OVERRIDE_LIBRARY(mesh) && !is_undo) { - mesh->mvert = NULL; + mesh->mvert = nullptr; mesh->totvert = 0; memset(&mesh->vdata, 0, sizeof(mesh->vdata)); vlayers = vlayers_buff; - mesh->medge = NULL; + mesh->medge = nullptr; mesh->totedge = 0; memset(&mesh->edata, 0, sizeof(mesh->edata)); elayers = elayers_buff; - mesh->mloop = NULL; + mesh->mloop = nullptr; mesh->totloop = 0; memset(&mesh->ldata, 0, sizeof(mesh->ldata)); llayers = llayers_buff; - mesh->mpoly = NULL; + mesh->mpoly = nullptr; mesh->totpoly = 0; memset(&mesh->pdata, 0, sizeof(mesh->pdata)); players = players_buff; @@ -307,13 +307,13 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id) CustomData_blend_read(reader, &mesh->pdata, mesh->totpoly); mesh->texflag &= ~ME_AUTOSPACE_EVALUATED; - mesh->edit_mesh = NULL; + mesh->edit_mesh = nullptr; memset(&mesh->runtime, 0, sizeof(mesh->runtime)); BKE_mesh_runtime_init_data(mesh); /* happens with old files */ - if (mesh->mselect == NULL) { + if (mesh->mselect == nullptr) { mesh->totselect = 0; } @@ -355,31 +355,32 @@ static void mesh_read_expand(BlendExpander *expander, ID *id) } IDTypeInfo IDType_ID_ME = { - .id_code = ID_ME, - .id_filter = FILTER_ID_ME, - .main_listbase_index = INDEX_ID_ME, - .struct_size = sizeof(Mesh), - .name = "Mesh", - .name_plural = "meshes", - .translation_context = BLT_I18NCONTEXT_ID_MESH, - .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE, - - .init_data = mesh_init_data, - .copy_data = mesh_copy_data, - .free_data = mesh_free_data, - .make_local = NULL, - .foreach_id = mesh_foreach_id, - .foreach_cache = NULL, - .owner_get = NULL, - - .blend_write = mesh_blend_write, - .blend_read_data = mesh_blend_read_data, - .blend_read_lib = mesh_blend_read_lib, - .blend_read_expand = mesh_read_expand, - - .blend_read_undo_preserve = NULL, - - .lib_override_apply_post = NULL, + /* id_code */ ID_ME, + /* id_filter */ FILTER_ID_ME, + /* main_listbase_index */ INDEX_ID_ME, + /* struct_size */ sizeof(Mesh), + /* name */ "Mesh", + /* name_plural */ "meshes", + /* translation_context */ BLT_I18NCONTEXT_ID_MESH, + /* flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE, + /* asset_type_info */ nullptr, + + /* init_data */ mesh_init_data, + /* copy_data */ mesh_copy_data, + /* free_data */ mesh_free_data, + /* make_local */ nullptr, + /* foreach_id */ mesh_foreach_id, + /* foreach_cache */ nullptr, + /* owner_get */ nullptr, + + /* blend_write */ mesh_blend_write, + /* blend_read_data */ mesh_blend_read_data, + /* blend_read_lib */ mesh_blend_read_lib, + /* blend_read_expand */ mesh_read_expand, + + /* blend_read_undo_preserve */ nullptr, + + /* lib_override_apply_post */ nullptr, }; enum { @@ -441,13 +442,15 @@ static int customdata_compare( const uint64_t cd_mask_all_attr = CD_MASK_PROP_ALL | cd_mask_non_generic; for (int i = 0; i < c1->totlayer; i++) { - if (CD_TYPE_AS_MASK(c1->layers[i].type) & cd_mask_all_attr) { + l1 = &c1->layers[i]; + if (CD_TYPE_AS_MASK(l1->type) & cd_mask_all_attr && l1->anonymous_id != nullptr) { layer_count1++; } } for (int i = 0; i < c2->totlayer; i++) { - if (CD_TYPE_AS_MASK(c2->layers[i].type) & cd_mask_all_attr) { + l2 = &c2->layers[i]; + if (CD_TYPE_AS_MASK(l1->type) & cd_mask_all_attr && l2->anonymous_id != nullptr) { layer_count2++; } } @@ -463,7 +466,8 @@ static int customdata_compare( l1 = c1->layers + i1; for (int i2 = 0; i2 < c2->totlayer; i2++) { l2 = c2->layers + i2; - if (l1->type != l2->type || !STREQ(l1->name, l2->name)) { + if (l1->type != l2->type || !STREQ(l1->name, l2->name) || l1->anonymous_id != nullptr || + l2->anonymous_id != nullptr) { continue; } /* At this point `l1` and `l2` have the same name and type, so they should be compared. */ @@ -471,8 +475,8 @@ static int customdata_compare( switch (l1->type) { case CD_MVERT: { - MVert *v1 = l1->data; - MVert *v2 = l2->data; + MVert *v1 = (MVert *)l1->data; + MVert *v2 = (MVert *)l2->data; int vtot = m1->totvert; for (j = 0; j < vtot; j++, v1++, v2++) { @@ -488,8 +492,8 @@ static int customdata_compare( /* We're order-agnostic for edges here. */ case CD_MEDGE: { - MEdge *e1 = l1->data; - MEdge *e2 = l2->data; + MEdge *e1 = (MEdge *)l1->data; + MEdge *e2 = (MEdge *)l2->data; int etot = m1->totedge; EdgeHash *eh = BLI_edgehash_new_ex(__func__, etot); @@ -502,12 +506,12 @@ static int customdata_compare( return MESHCMP_EDGEUNKNOWN; } } - BLI_edgehash_free(eh, NULL); + BLI_edgehash_free(eh, nullptr); break; } case CD_MPOLY: { - MPoly *p1 = l1->data; - MPoly *p2 = l2->data; + MPoly *p1 = (MPoly *)l1->data; + MPoly *p2 = (MPoly *)l2->data; int ptot = m1->totpoly; for (j = 0; j < ptot; j++, p1++, p2++) { @@ -530,8 +534,8 @@ static int customdata_compare( break; } case CD_MLOOP: { - MLoop *lp1 = l1->data; - MLoop *lp2 = l2->data; + MLoop *lp1 = (MLoop *)l1->data; + MLoop *lp2 = (MLoop *)l2->data; int ltot = m1->totloop; for (j = 0; j < ltot; j++, lp1++, lp2++) { @@ -542,8 +546,8 @@ static int customdata_compare( break; } case CD_MLOOPUV: { - MLoopUV *lp1 = l1->data; - MLoopUV *lp2 = l2->data; + MLoopUV *lp1 = (MLoopUV *)l1->data; + MLoopUV *lp2 = (MLoopUV *)l2->data; int ltot = m1->totloop; for (j = 0; j < ltot; j++, lp1++, lp2++) { @@ -554,8 +558,8 @@ static int customdata_compare( break; } case CD_MLOOPCOL: { - MLoopCol *lp1 = l1->data; - MLoopCol *lp2 = l2->data; + MLoopCol *lp1 = (MLoopCol *)l1->data; + MLoopCol *lp2 = (MLoopCol *)l2->data; int ltot = m1->totloop; for (j = 0; j < ltot; j++, lp1++, lp2++) { @@ -566,8 +570,8 @@ static int customdata_compare( break; } case CD_MDEFORMVERT: { - MDeformVert *dv1 = l1->data; - MDeformVert *dv2 = l2->data; + MDeformVert *dv1 = (MDeformVert *)l1->data; + MDeformVert *dv2 = (MDeformVert *)l2->data; int dvtot = m1->totvert; for (j = 0; j < dvtot; j++, dv1++, dv2++) { @@ -590,8 +594,8 @@ static int customdata_compare( break; } case CD_PROP_FLOAT: { - const float *l1_data = l1->data; - const float *l2_data = l2->data; + const float *l1_data = (float *)l1->data; + const float *l2_data = (float *)l2->data; for (int i = 0; i < total_length; i++) { if (compare_threshold_relative(l1_data[i], l2_data[i], thresh)) { @@ -601,8 +605,8 @@ static int customdata_compare( break; } case CD_PROP_FLOAT2: { - const float(*l1_data)[2] = l1->data; - const float(*l2_data)[2] = l2->data; + const float(*l1_data)[2] = (float(*)[2])l1->data; + const float(*l2_data)[2] = (float(*)[2])l2->data; for (int i = 0; i < total_length; i++) { if (compare_threshold_relative(l1_data[i][0], l2_data[i][0], thresh)) { @@ -615,8 +619,8 @@ static int customdata_compare( break; } case CD_PROP_FLOAT3: { - const float(*l1_data)[3] = l1->data; - const float(*l2_data)[3] = l2->data; + const float(*l1_data)[3] = (float(*)[3])l1->data; + const float(*l2_data)[3] = (float(*)[3])l2->data; for (int i = 0; i < total_length; i++) { if (compare_threshold_relative(l1_data[i][0], l2_data[i][0], thresh)) { @@ -632,8 +636,8 @@ static int customdata_compare( break; } case CD_PROP_INT32: { - const int *l1_data = l1->data; - const int *l2_data = l2->data; + const int *l1_data = (int *)l1->data; + const int *l2_data = (int *)l2->data; for (int i = 0; i < total_length; i++) { if (l1_data[i] != l2_data[i]) { @@ -643,8 +647,8 @@ static int customdata_compare( break; } case CD_PROP_BOOL: { - const bool *l1_data = l1->data; - const bool *l2_data = l2->data; + const bool *l1_data = (bool *)l1->data; + const bool *l2_data = (bool *)l2->data; for (int i = 0; i < total_length; i++) { if (l1_data[i] != l2_data[i]) { @@ -654,8 +658,8 @@ static int customdata_compare( break; } case CD_PROP_COLOR: { - const MPropCol *l1_data = l1->data; - const MPropCol *l2_data = l2->data; + const MPropCol *l1_data = (MPropCol *)l1->data; + const MPropCol *l2_data = (MPropCol *)l2->data; for (int i = 0; i < total_length; i++) { for (j = 0; j < 4; j++) { @@ -722,7 +726,7 @@ const char *BKE_mesh_cmp(Mesh *me1, Mesh *me2, float thresh) return cmpcode_to_str(c); } - return NULL; + return nullptr; } static void mesh_ensure_tessellation_customdata(Mesh *me) @@ -767,7 +771,7 @@ static void mesh_ensure_tessellation_customdata(Mesh *me) void BKE_mesh_ensure_skin_customdata(Mesh *me) { - BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : NULL; + BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : nullptr; MVertSkin *vs; if (bm) { @@ -779,7 +783,7 @@ void BKE_mesh_ensure_skin_customdata(Mesh *me) /* Mark an arbitrary vertex as root */ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - vs = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_MVERT_SKIN); + vs = (MVertSkin *)CustomData_bmesh_get(&bm->vdata, v->head.data, CD_MVERT_SKIN); vs->flag |= MVERT_SKIN_ROOT; break; } @@ -787,7 +791,8 @@ void BKE_mesh_ensure_skin_customdata(Mesh *me) } else { if (!CustomData_has_layer(&me->vdata, CD_MVERT_SKIN)) { - vs = CustomData_add_layer(&me->vdata, CD_MVERT_SKIN, CD_DEFAULT, NULL, me->totvert); + vs = (MVertSkin *)CustomData_add_layer( + &me->vdata, CD_MVERT_SKIN, CD_DEFAULT, nullptr, me->totvert); /* Mark an arbitrary vertex as root */ if (vs) { @@ -799,7 +804,7 @@ void BKE_mesh_ensure_skin_customdata(Mesh *me) bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me) { - BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : NULL; + BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : nullptr; bool changed = false; if (bm) { if (!CustomData_has_layer(&bm->pdata, CD_FACEMAP)) { @@ -809,7 +814,7 @@ bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me) } else { if (!CustomData_has_layer(&me->pdata, CD_FACEMAP)) { - CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_DEFAULT, NULL, me->totpoly); + CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_DEFAULT, nullptr, me->totpoly); changed = true; } } @@ -818,7 +823,7 @@ bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me) bool BKE_mesh_clear_facemap_customdata(struct Mesh *me) { - BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : NULL; + BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : nullptr; bool changed = false; if (bm) { if (CustomData_has_layer(&bm->pdata, CD_FACEMAP)) { @@ -836,12 +841,12 @@ bool BKE_mesh_clear_facemap_customdata(struct Mesh *me) } /** - * This ensures grouped customdata (e.g. mtexpoly and mloopuv and mtface, or - * mloopcol and mcol) have the same relative active/render/clone/mask indices. + * This ensures grouped custom-data (e.g. #CD_MLOOPUV and #CD_MTFACE, or + * #CD_MLOOPCOL and #CD_MCOL) have the same relative active/render/clone/mask indices. * - * NOTE(campbell): that for undo mesh data we want to skip 'ensure_tess_cd' call since - * we don't want to store memory for tessface when its only used for older - * Versions of the mesh. + * NOTE(@campbellbarton): that for undo mesh data we want to skip 'ensure_tess_cd' call since + * we don't want to store memory for #MFace data when its only used for older + * versions of the mesh. */ static void mesh_update_linked_customdata(Mesh *me, const bool do_ensure_tess_cd) { @@ -856,20 +861,20 @@ void BKE_mesh_update_customdata_pointers(Mesh *me, const bool do_ensure_tess_cd) { mesh_update_linked_customdata(me, do_ensure_tess_cd); - me->mvert = CustomData_get_layer(&me->vdata, CD_MVERT); - me->dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT); + me->mvert = (MVert *)CustomData_get_layer(&me->vdata, CD_MVERT); + me->dvert = (MDeformVert *)CustomData_get_layer(&me->vdata, CD_MDEFORMVERT); - me->medge = CustomData_get_layer(&me->edata, CD_MEDGE); + me->medge = (MEdge *)CustomData_get_layer(&me->edata, CD_MEDGE); - me->mface = CustomData_get_layer(&me->fdata, CD_MFACE); - me->mcol = CustomData_get_layer(&me->fdata, CD_MCOL); - me->mtface = CustomData_get_layer(&me->fdata, CD_MTFACE); + me->mface = (MFace *)CustomData_get_layer(&me->fdata, CD_MFACE); + me->mcol = (MCol *)CustomData_get_layer(&me->fdata, CD_MCOL); + me->mtface = (MTFace *)CustomData_get_layer(&me->fdata, CD_MTFACE); - me->mpoly = CustomData_get_layer(&me->pdata, CD_MPOLY); - me->mloop = CustomData_get_layer(&me->ldata, CD_MLOOP); + me->mpoly = (MPoly *)CustomData_get_layer(&me->pdata, CD_MPOLY); + me->mloop = (MLoop *)CustomData_get_layer(&me->ldata, CD_MLOOP); - me->mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL); - me->mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV); + me->mloopcol = (MLoopCol *)CustomData_get_layer(&me->ldata, CD_MLOOPCOL); + me->mloopuv = (MLoopUV *)CustomData_get_layer(&me->ldata, CD_MLOOPUV); } bool BKE_mesh_has_custom_loop_normals(Mesh *me) @@ -883,7 +888,7 @@ bool BKE_mesh_has_custom_loop_normals(Mesh *me) /** * Free (or release) any data used by this mesh (does not free the mesh itself). - * Only use for undo, in most cases `BKE_id_free(NULL, me)` should be used. + * Only use for undo, in most cases `BKE_id_free(nullptr, me)` should be used. */ void BKE_mesh_free_data_for_undo(Mesh *me) { @@ -939,15 +944,15 @@ static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata) CustomData_reset(&mesh->fdata); } - mesh->mface = NULL; - mesh->mtface = NULL; - mesh->mcol = NULL; + mesh->mface = nullptr; + mesh->mtface = nullptr; + mesh->mcol = nullptr; mesh->totface = 0; } Mesh *BKE_mesh_add(Main *bmain, const char *name) { - Mesh *me = BKE_id_new(bmain, ID_ME, name); + Mesh *me = (Mesh *)BKE_id_new(bmain, ID_ME, name); return me; } @@ -956,28 +961,28 @@ Mesh *BKE_mesh_add(Main *bmain, const char *name) static void mesh_ensure_cdlayers_primary(Mesh *mesh, bool do_tessface) { if (!CustomData_get_layer(&mesh->vdata, CD_MVERT)) { - CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, mesh->totvert); + CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, nullptr, mesh->totvert); } if (!CustomData_get_layer(&mesh->edata, CD_MEDGE)) { - CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, NULL, mesh->totedge); + CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, nullptr, mesh->totedge); } if (!CustomData_get_layer(&mesh->ldata, CD_MLOOP)) { - CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, mesh->totloop); + CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, nullptr, mesh->totloop); } if (!CustomData_get_layer(&mesh->pdata, CD_MPOLY)) { - CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, mesh->totpoly); + CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, nullptr, mesh->totpoly); } if (do_tessface && !CustomData_get_layer(&mesh->fdata, CD_MFACE)) { - CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_CALLOC, NULL, mesh->totface); + CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_CALLOC, nullptr, mesh->totface); } } Mesh *BKE_mesh_new_nomain( int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len) { - Mesh *mesh = BKE_libblock_alloc( - NULL, ID_ME, BKE_idtype_idcode_to_name(ID_ME), LIB_ID_CREATE_LOCALIZE); + Mesh *mesh = (Mesh *)BKE_libblock_alloc( + nullptr, ID_ME, BKE_idtype_idcode_to_name(ID_ME), LIB_ID_CREATE_LOCALIZE); BKE_libblock_init_empty(&mesh->id); /* Don't use #CustomData_reset because we don't want to touch custom-data. */ @@ -1043,10 +1048,10 @@ void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src) BKE_defgroup_copy_list(&me_dst->vertex_group_names, &me_src->vertex_group_names); /* Copy materials. */ - if (me_dst->mat != NULL) { + if (me_dst->mat != nullptr) { MEM_freeN(me_dst->mat); } - me_dst->mat = MEM_dupallocN(me_src->mat); + me_dst->mat = (Material **)MEM_dupallocN(me_src->mat); me_dst->totcol = me_src->totcol; } @@ -1061,9 +1066,9 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src, /* Only do tessface if we are creating tessfaces or copying from mesh with only tessfaces. */ const bool do_tessface = (tessface_len || ((me_src->totface != 0) && (me_src->totpoly == 0))); - Mesh *me_dst = BKE_id_new_nomain(ID_ME, NULL); + Mesh *me_dst = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr); - me_dst->mselect = MEM_dupallocN(me_src->mselect); + me_dst->mselect = (MSelect *)MEM_dupallocN(me_src->mselect); me_dst->totvert = verts_len; me_dst->totedge = edges_len; @@ -1107,7 +1112,7 @@ Mesh *BKE_mesh_new_nomain_from_template(const Mesh *me_src, void BKE_mesh_eval_delete(struct Mesh *mesh_eval) { /* Evaluated mesh may point to edit mesh, but never owns it. */ - mesh_eval->edit_mesh = NULL; + mesh_eval->edit_mesh = nullptr; mesh_free_data(&mesh_eval->id); BKE_libblock_free_data(&mesh_eval->id, false); MEM_freeN(mesh_eval); @@ -1121,7 +1126,7 @@ Mesh *BKE_mesh_copy_for_eval(const Mesh *source, bool reference) flags |= LIB_ID_COPY_CD_REFERENCE; } - Mesh *result = (Mesh *)BKE_id_copy_ex(NULL, &source->id, NULL, flags); + Mesh *result = (Mesh *)BKE_id_copy_ex(nullptr, &source->id, nullptr, flags); return result; } @@ -1142,14 +1147,12 @@ BMesh *BKE_mesh_to_bmesh(Mesh *me, const bool add_key_index, const struct BMeshCreateParams *params) { - return BKE_mesh_to_bmesh_ex(me, - params, - &(struct BMeshFromMeshParams){ - .calc_face_normal = false, - .add_key_index = add_key_index, - .use_shapekey = true, - .active_shapekey = ob->shapenr, - }); + BMeshFromMeshParams bmesh_from_mesh_params{}; + bmesh_from_mesh_params.calc_face_normal = false; + bmesh_from_mesh_params.add_key_index = add_key_index; + bmesh_from_mesh_params.use_shapekey = true; + bmesh_from_mesh_params.active_shapekey = ob->shapenr; + return BKE_mesh_to_bmesh_ex(me, params, &bmesh_from_mesh_params); } Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm, @@ -1157,8 +1160,8 @@ Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm, const Mesh *me_settings) { BLI_assert(params->calc_object_remap == false); - Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL); - BM_mesh_bm_to_me(NULL, bm, mesh, params); + Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr); + BM_mesh_bm_to_me(nullptr, bm, mesh, params); BKE_mesh_copy_parameters_for_eval(mesh, me_settings); return mesh; } @@ -1167,7 +1170,7 @@ Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, const CustomData_MeshMasks *cd_mask_extra, const Mesh *me_settings) { - Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL); + Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr); BM_mesh_bm_to_me_for_eval(bm, mesh, cd_mask_extra); BKE_mesh_copy_parameters_for_eval(mesh, me_settings); return mesh; @@ -1177,8 +1180,8 @@ BoundBox *BKE_mesh_boundbox_get(Object *ob) { /* This is Object-level data access, * DO NOT touch to Mesh's bb, would be totally thread-unsafe. */ - if (ob->runtime.bb == NULL || ob->runtime.bb->flag & BOUNDBOX_DIRTY) { - Mesh *me = ob->data; + if (ob->runtime.bb == nullptr || ob->runtime.bb->flag & BOUNDBOX_DIRTY) { + Mesh *me = (Mesh *)ob->data; float min[3], max[3]; INIT_MINMAX(min, max); @@ -1187,8 +1190,8 @@ BoundBox *BKE_mesh_boundbox_get(Object *ob) max[0] = max[1] = max[2] = 1.0f; } - if (ob->runtime.bb == NULL) { - ob->runtime.bb = MEM_mallocN(sizeof(*ob->runtime.bb), __func__); + if (ob->runtime.bb == nullptr) { + ob->runtime.bb = (BoundBox *)MEM_mallocN(sizeof(*ob->runtime.bb), __func__); } BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max); ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY; @@ -1257,13 +1260,13 @@ void BKE_mesh_texspace_get_reference(Mesh *me, short **r_texflag, float **r_loc, { BKE_mesh_texspace_ensure(me); - if (r_texflag != NULL) { + if (r_texflag != nullptr) { *r_texflag = &me->texflag; } - if (r_loc != NULL) { + if (r_loc != nullptr) { *r_loc = me->loc; } - if (r_size != NULL) { + if (r_size != nullptr) { *r_size = me->size; } } @@ -1282,11 +1285,11 @@ void BKE_mesh_texspace_copy_from_object(Mesh *me, Object *ob) float (*BKE_mesh_orco_verts_get(Object *ob))[3] { - Mesh *me = ob->data; + Mesh *me = (Mesh *)ob->data; Mesh *tme = me->texcomesh ? me->texcomesh : me; /* Get appropriate vertex coordinates */ - float(*vcos)[3] = MEM_calloc_arrayN(me->totvert, sizeof(*vcos), "orco mesh"); + float(*vcos)[3] = (float(*)[3])MEM_calloc_arrayN(me->totvert, sizeof(*vcos), "orco mesh"); MVert *mvert = tme->mvert; int totvert = min_ii(tme->totvert, me->totvert); @@ -1393,28 +1396,28 @@ int BKE_mesh_mface_index_validate(MFace *mface, CustomData *fdata, int mfindex, Mesh *BKE_mesh_from_object(Object *ob) { - if (ob == NULL) { - return NULL; + if (ob == nullptr) { + return nullptr; } if (ob->type == OB_MESH) { - return ob->data; + return (Mesh *)ob->data; } - return NULL; + return nullptr; } void BKE_mesh_assign_object(Main *bmain, Object *ob, Mesh *me) { - Mesh *old = NULL; + Mesh *old = nullptr; - if (ob == NULL) { + if (ob == nullptr) { return; } multires_force_sculpt_rebuild(ob); if (ob->type == OB_MESH) { - old = ob->data; + old = (Mesh *)ob->data; if (old) { id_us_min(&old->id); } @@ -1605,8 +1608,9 @@ bool BKE_mesh_minmax(const Mesh *me, float r_min[3], float r_max[3]) void BKE_mesh_transform(Mesh *me, const float mat[4][4], bool do_keys) { int i; - MVert *mvert = CustomData_duplicate_referenced_layer(&me->vdata, CD_MVERT, me->totvert); - float(*lnors)[3] = CustomData_duplicate_referenced_layer(&me->ldata, CD_NORMAL, me->totloop); + MVert *mvert = (MVert *)CustomData_duplicate_referenced_layer(&me->vdata, CD_MVERT, me->totvert); + float(*lnors)[3] = (float(*)[3])CustomData_duplicate_referenced_layer( + &me->ldata, CD_NORMAL, me->totloop); /* If the referenced layer has been re-allocated need to update pointers stored in the mesh. */ BKE_mesh_update_customdata_pointers(me, false); @@ -1616,9 +1620,8 @@ void BKE_mesh_transform(Mesh *me, const float mat[4][4], bool do_keys) } if (do_keys && me->key) { - KeyBlock *kb; - for (kb = me->key->block.first; kb; kb = kb->next) { - float *fp = kb->data; + LISTBASE_FOREACH (KeyBlock *, kb, &me->key->block) { + float *fp = (float *)kb->data; for (i = kb->totelem; i--; fp += 3) { mul_m4_v3(mat, fp); } @@ -1651,9 +1654,8 @@ void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys) } if (do_keys && me->key) { - KeyBlock *kb; - for (kb = me->key->block.first; kb; kb = kb->next) { - float *fp = kb->data; + LISTBASE_FOREACH (KeyBlock *, kb, &me->key->block) { + float *fp = (float *)kb->data; for (i = kb->totelem; i--; fp += 3) { add_v3_v3(fp, offset); } @@ -1725,7 +1727,8 @@ void BKE_mesh_mselect_validate(Mesh *me) } mselect_src = me->mselect; - mselect_dst = MEM_malloc_arrayN((me->totselect), sizeof(MSelect), "Mesh selection history"); + mselect_dst = (MSelect *)MEM_malloc_arrayN( + (me->totselect), sizeof(MSelect), "Mesh selection history"); for (i_src = 0, i_dst = 0; i_src < me->totselect; i_src++) { int index = mselect_src[i_src].index; @@ -1762,10 +1765,10 @@ void BKE_mesh_mselect_validate(Mesh *me) if (i_dst == 0) { MEM_freeN(mselect_dst); - mselect_dst = NULL; + mselect_dst = nullptr; } else if (i_dst != me->totselect) { - mselect_dst = MEM_reallocN(mselect_dst, sizeof(MSelect) * i_dst); + mselect_dst = (MSelect *)MEM_reallocN(mselect_dst, sizeof(MSelect) * i_dst); } me->totselect = i_dst; @@ -1809,7 +1812,7 @@ void BKE_mesh_mselect_active_set(Mesh *me, int index, int type) if (msel_index == -1) { /* add to the end */ - me->mselect = MEM_reallocN(me->mselect, sizeof(MSelect) * (me->totselect + 1)); + me->mselect = (MSelect *)MEM_reallocN(me->mselect, sizeof(MSelect) * (me->totselect + 1)); me->mselect[me->totselect].index = index; me->mselect[me->totselect].type = type; me->totselect++; @@ -1845,7 +1848,7 @@ void BKE_mesh_vert_coords_get(const Mesh *mesh, float (*vert_coords)[3]) float (*BKE_mesh_vert_coords_alloc(const Mesh *mesh, int *r_vert_len))[3] { - float(*vert_coords)[3] = MEM_mallocN(sizeof(float[3]) * mesh->totvert, __func__); + float(*vert_coords)[3] = (float(*)[3])MEM_mallocN(sizeof(float[3]) * mesh->totvert, __func__); BKE_mesh_vert_coords_get(mesh, vert_coords); if (r_vert_len) { *r_vert_len = mesh->totvert; @@ -1856,7 +1859,8 @@ float (*BKE_mesh_vert_coords_alloc(const Mesh *mesh, int *r_vert_len))[3] void BKE_mesh_vert_coords_apply(Mesh *mesh, const float (*vert_coords)[3]) { /* This will just return the pointer if it wasn't a referenced layer. */ - MVert *mv = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert); + MVert *mv = (MVert *)CustomData_duplicate_referenced_layer( + &mesh->vdata, CD_MVERT, mesh->totvert); mesh->mvert = mv; for (int i = 0; i < mesh->totvert; i++, mv++) { copy_v3_v3(mv->co, vert_coords[i]); @@ -1869,7 +1873,8 @@ void BKE_mesh_vert_coords_apply_with_mat4(Mesh *mesh, const float mat[4][4]) { /* This will just return the pointer if it wasn't a referenced layer. */ - MVert *mv = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert); + MVert *mv = (MVert *)CustomData_duplicate_referenced_layer( + &mesh->vdata, CD_MVERT, mesh->totvert); mesh->mvert = mv; for (int i = 0; i < mesh->totvert; i++, mv++) { mul_v3_m4v3(mv->co, mat, vert_coords[i]); @@ -1880,7 +1885,8 @@ void BKE_mesh_vert_coords_apply_with_mat4(Mesh *mesh, void BKE_mesh_vert_normals_apply(Mesh *mesh, const short (*vert_normals)[3]) { /* This will just return the pointer if it wasn't a referenced layer. */ - MVert *mv = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert); + MVert *mv = (MVert *)CustomData_duplicate_referenced_layer( + &mesh->vdata, CD_MVERT, mesh->totvert); mesh->mvert = mv; for (int i = 0; i < mesh->totvert; i++, mv++) { copy_v3_v3_short(mv->no, vert_normals[i]); @@ -1899,35 +1905,37 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac { float(*r_loopnors)[3]; float(*polynors)[3]; - short(*clnors)[2] = NULL; + short(*clnors)[2] = nullptr; bool free_polynors = false; /* Note that we enforce computing clnors when the clnor space array is requested by caller here. - * However, we obviously only use the autosmooth angle threshold - * only in case autosmooth is enabled. */ - const bool use_split_normals = (r_lnors_spacearr != NULL) || ((mesh->flag & ME_AUTOSMOOTH) != 0); + * However, we obviously only use the auto-smooth angle threshold + * only in case auto-smooth is enabled. */ + const bool use_split_normals = (r_lnors_spacearr != nullptr) || + ((mesh->flag & ME_AUTOSMOOTH) != 0); const float split_angle = (mesh->flag & ME_AUTOSMOOTH) != 0 ? mesh->smoothresh : (float)M_PI; if (CustomData_has_layer(&mesh->ldata, CD_NORMAL)) { - r_loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL); + r_loopnors = (float(*)[3])CustomData_get_layer(&mesh->ldata, CD_NORMAL); memset(r_loopnors, 0, sizeof(float[3]) * mesh->totloop); } else { - r_loopnors = CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_CALLOC, NULL, mesh->totloop); + r_loopnors = (float(*)[3])CustomData_add_layer( + &mesh->ldata, CD_NORMAL, CD_CALLOC, nullptr, mesh->totloop); CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY); } - /* may be NULL */ - clnors = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); + /* may be nullptr */ + clnors = (short(*)[2])CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); if (CustomData_has_layer(&mesh->pdata, CD_NORMAL)) { /* This assume that layer is always up to date, not sure this is the case * (esp. in Edit mode?)... */ - polynors = CustomData_get_layer(&mesh->pdata, CD_NORMAL); + polynors = (float(*)[3])CustomData_get_layer(&mesh->pdata, CD_NORMAL); free_polynors = false; } else { - polynors = MEM_malloc_arrayN(mesh->totpoly, sizeof(float[3]), __func__); + polynors = (float(*)[3])MEM_malloc_arrayN(mesh->totpoly, sizeof(float[3]), __func__); BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert, mesh->totvert, mesh->mloop, @@ -1935,7 +1943,7 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac mesh->mpoly, mesh->totpoly, polynors, - NULL); + nullptr); free_polynors = true; } @@ -1953,7 +1961,7 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac split_angle, r_lnors_spacearr, clnors, - NULL); + nullptr); if (free_polynors) { MEM_freeN(polynors); @@ -1966,25 +1974,25 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac void BKE_mesh_calc_normals_split(Mesh *mesh) { - BKE_mesh_calc_normals_split_ex(mesh, NULL); + BKE_mesh_calc_normals_split_ex(mesh, nullptr); } /* Split faces helper functions. */ -typedef struct SplitFaceNewVert { +struct SplitFaceNewVert { struct SplitFaceNewVert *next; int new_index; int orig_index; float *vnor; -} SplitFaceNewVert; +}; -typedef struct SplitFaceNewEdge { +struct SplitFaceNewEdge { struct SplitFaceNewEdge *next; int new_index; int orig_index; int v1; int v2; -} SplitFaceNewEdge; +}; /* Detect needed new vertices, and update accordingly loops' vertex indices. * WARNING! Leaves mesh in invalid state. */ @@ -1996,7 +2004,7 @@ static int split_faces_prepare_new_verts(const Mesh *mesh, /* This is now mandatory, trying to do the job in simple way without that data is doomed to fail, * even when only dealing with smooth/flat faces one can find cases that no simple algorithm * can handle properly. */ - BLI_assert(lnors_spacearr != NULL); + BLI_assert(lnors_spacearr != nullptr); const int loops_len = mesh->totloop; int verts_len = mesh->totvert; @@ -2049,7 +2057,8 @@ static int split_faces_prepare_new_verts(const Mesh *mesh, } else { /* Add new vert to list. */ - SplitFaceNewVert *new_vert = BLI_memarena_alloc(memarena, sizeof(*new_vert)); + SplitFaceNewVert *new_vert = (SplitFaceNewVert *)BLI_memarena_alloc(memarena, + sizeof(*new_vert)); new_vert->orig_index = vert_idx; new_vert->new_index = new_vert_idx; new_vert->vnor = (*lnor_space)->vec_lnor; /* See note above. */ @@ -2096,7 +2105,8 @@ static int split_faces_prepare_new_edges(const Mesh *mesh, *eval = POINTER_FROM_INT(new_edge_idx); ml_prev->e = new_edge_idx; - SplitFaceNewEdge *new_edge = BLI_memarena_alloc(memarena, sizeof(*new_edge)); + SplitFaceNewEdge *new_edge = (SplitFaceNewEdge *)BLI_memarena_alloc(memarena, + sizeof(*new_edge)); new_edge->orig_index = edge_idx; new_edge->new_index = new_edge_idx; new_edge->v1 = ml_prev->v; @@ -2122,7 +2132,7 @@ static int split_faces_prepare_new_edges(const Mesh *mesh, } MEM_freeN(edges_used); - BLI_edgehash_free(edges_hash, NULL); + BLI_edgehash_free(edges_hash, nullptr); return num_edges - mesh->totedge; } @@ -2181,14 +2191,14 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals) } BKE_mesh_tessface_clear(mesh); - MLoopNorSpaceArray lnors_spacearr = {NULL}; + MLoopNorSpaceArray lnors_spacearr = {nullptr}; /* Compute loop normals and loop normal spaces (a.k.a. smooth fans of faces around vertices). */ BKE_mesh_calc_normals_split_ex(mesh, &lnors_spacearr); /* Stealing memarena from loop normals space array. */ MemArena *memarena = lnors_spacearr.mem; - SplitFaceNewVert *new_verts = NULL; - SplitFaceNewEdge *new_edges = NULL; + SplitFaceNewVert *new_verts = nullptr; + SplitFaceNewEdge *new_edges = nullptr; /* Ensure we own the layers, we need to do this before split_faces_prepare_new_verts as it will * directly assign new indices to existing edges and loops. */ @@ -2252,10 +2262,10 @@ void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh) /* We are here because something did change in the mesh. This means we can not trust the existing * evaluated mesh, and we don't know what parts of the mesh did change. So we simply delete the * evaluated mesh and let objects to re-create it with updated settings. */ - if (mesh->runtime.mesh_eval != NULL) { - mesh->runtime.mesh_eval->edit_mesh = NULL; - BKE_id_free(NULL, mesh->runtime.mesh_eval); - mesh->runtime.mesh_eval = NULL; + if (mesh->runtime.mesh_eval != nullptr) { + mesh->runtime.mesh_eval->edit_mesh = nullptr; + BKE_id_free(nullptr, mesh->runtime.mesh_eval); + mesh->runtime.mesh_eval = nullptr; } if (DEG_is_active(depsgraph)) { Mesh *mesh_orig = (Mesh *)DEG_get_original_id(&mesh->id); diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc index 9f5703a015d..3447185089d 100644 --- a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc +++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc @@ -410,7 +410,8 @@ struct Mesh *BKE_mesh_remesh_voxel_fix_poles(const Mesh *mesh) { const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh); - const BMeshCreateParams bmesh_create_params = {true}; + BMeshCreateParams bmesh_create_params{}; + bmesh_create_params.use_toolflags = true; BMesh *bm = BM_mesh_create(&allocsize, &bmesh_create_params); BMeshFromMeshParams bmesh_from_mesh_params{}; diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c index ce89c723a61..7b1d5140421 100644 --- a/source/blender/blenkernel/intern/mesh_runtime.c +++ b/source/blender/blenkernel/intern/mesh_runtime.c @@ -113,7 +113,7 @@ void BKE_mesh_runtime_reset_on_copy(Mesh *mesh, const int UNUSED(flag)) /** * \brief This function clears runtime cache of the given mesh. - * + * * Call this function to recalculate runtime data when used. */ void BKE_mesh_runtime_clear_cache(Mesh *mesh) diff --git a/source/blender/blenkernel/intern/mesh_sample.cc b/source/blender/blenkernel/intern/mesh_sample.cc index 2274d34f0f1..a046cc68bf2 100644 --- a/source/blender/blenkernel/intern/mesh_sample.cc +++ b/source/blender/blenkernel/intern/mesh_sample.cc @@ -269,7 +269,7 @@ void MeshAttributeInterpolator::sample_attribute(const ReadAttributeLookup &src_ eAttributeMapMode mode) { if (src_attribute && dst_attribute) { - this->sample_data(*src_attribute.varray, src_attribute.domain, mode, dst_attribute.as_span()); + this->sample_data(src_attribute.varray, src_attribute.domain, mode, dst_attribute.as_span()); } } diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index 34fb9f71bd9..ae7a56ff9a0 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -347,6 +347,7 @@ IDTypeInfo IDType_ID_MC = { .name_plural = "movieclips", .translation_context = BLT_I18NCONTEXT_ID_MOVIECLIP, .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE, + .asset_type_info = NULL, .init_data = movie_clip_init_data, .copy_data = movie_clip_copy_data, diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index ef84afd8668..8f2a60358e7 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -390,6 +390,16 @@ NlaStrip *BKE_nlastrip_new(bAction *act) */ strip->flag = NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_SYNC_LENGTH; + /* Disable sync for actions with a manual frame range, since it only syncs to range anyway. */ + if (act->flag & ACT_FRAME_RANGE) { + strip->flag &= ~NLASTRIP_FLAG_SYNC_LENGTH; + } + + /* Enable cyclic time for known cyclic actions. */ + if (BKE_action_is_cyclic(act)) { + strip->flag |= NLASTRIP_FLAG_USR_TIME_CYCLIC; + } + /* assign the action reference */ strip->act = act; id_us_plus(&act->id); @@ -397,7 +407,7 @@ NlaStrip *BKE_nlastrip_new(bAction *act) /* determine initial range * - strip length cannot be 0... ever... */ - calc_action_range(strip->act, &strip->actstart, &strip->actend, 0); + BKE_action_get_frame_range(strip->act, &strip->actstart, &strip->actend); strip->start = strip->actstart; strip->end = (IS_EQF(strip->actstart, strip->actend)) ? (strip->actstart + 1.0f) : @@ -491,11 +501,11 @@ void BKE_nla_strip_foreach_id(NlaStrip *strip, LibraryForeachIDData *data) BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, strip->act, IDWALK_CB_USER); LISTBASE_FOREACH (FCurve *, fcu, &strip->fcurves) { - BKE_fcurve_foreach_id(fcu, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_fcurve_foreach_id(fcu, data)); } LISTBASE_FOREACH (NlaStrip *, substrip, &strip->strips) { - BKE_nla_strip_foreach_id(substrip, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_nla_strip_foreach_id(substrip, data)); } } @@ -1444,7 +1454,7 @@ void BKE_nlastrip_recalculate_bounds_sync_action(NlaStrip *strip) prev_actstart = strip->actstart; - calc_action_range(strip->act, &strip->actstart, &strip->actend, 0); + BKE_action_get_frame_range(strip->act, &strip->actstart, &strip->actend); /* Set start such that key's do not visually move, to preserve the overall animation result. */ strip->start += (strip->actstart - prev_actstart) * strip->scale; diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index ab3132a5d58..288d46bf089 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -66,6 +66,7 @@ #include "BKE_colortools.h" #include "BKE_cryptomatte.h" #include "BKE_global.h" +#include "BKE_icons.h" #include "BKE_idprop.h" #include "BKE_idtype.h" #include "BKE_lib_id.h" @@ -129,10 +130,6 @@ static void node_socket_interface_free(bNodeTree *UNUSED(ntree), static void nodeMuteRerouteOutputLinks(struct bNodeTree *ntree, struct bNode *node, const bool mute); -static FieldInferencingInterface *node_field_inferencing_interface_copy( - const FieldInferencingInterface &field_inferencing_interface); -static void node_field_inferencing_interface_free( - const FieldInferencingInterface *field_inferencing_interface); static void ntree_init_data(ID *id) { @@ -245,9 +242,16 @@ static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c ntree_dst->interface_type = nullptr; if (ntree_src->field_inferencing_interface) { - ntree_dst->field_inferencing_interface = node_field_inferencing_interface_copy( + ntree_dst->field_inferencing_interface = new FieldInferencingInterface( *ntree_src->field_inferencing_interface); } + + if (flag & LIB_ID_COPY_NO_PREVIEW) { + ntree_dst->preview = nullptr; + } + else { + BKE_previewimg_id_copy(&ntree_dst->id, &ntree_src->id); + } } static void ntree_free_data(ID *id) @@ -293,7 +297,7 @@ static void ntree_free_data(ID *id) MEM_freeN(sock); } - node_field_inferencing_interface_free(ntree->field_inferencing_interface); + delete ntree->field_inferencing_interface; /* free preview hash */ if (ntree->previews) { @@ -303,12 +307,16 @@ static void ntree_free_data(ID *id) if (ntree->id.tag & LIB_TAG_LOCALIZED) { BKE_libblock_free_data(&ntree->id, true); } + + BKE_previewimg_free(&ntree->preview); } static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket *sock) { - IDP_foreach_property( - sock->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + IDP_foreach_property( + sock->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data)); switch ((eNodeSocketDatatype)sock->type) { case SOCK_OBJECT: { @@ -360,21 +368,25 @@ static void node_foreach_id(ID *id, LibraryForeachIDData *data) LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { BKE_LIB_FOREACHID_PROCESS_ID(data, node->id, IDWALK_CB_USER); - IDP_foreach_property( - node->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + IDP_foreach_property(node->prop, + IDP_TYPE_FILTER_ID, + BKE_lib_query_idpropertiesForeachIDLink_callback, + data)); LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { - library_foreach_node_socket(data, sock); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, library_foreach_node_socket(data, sock)); } LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { - library_foreach_node_socket(data, sock); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, library_foreach_node_socket(data, sock)); } } LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) { - library_foreach_node_socket(data, sock); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, library_foreach_node_socket(data, sock)); } LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) { - library_foreach_node_socket(data, sock); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, library_foreach_node_socket(data, sock)); } } @@ -635,6 +647,8 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree) LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) { write_node_socket_interface(writer, sock); } + + BKE_previewimg_blend_write(writer, ntree->preview); } static void ntree_blend_write(BlendWriter *writer, ID *id, const void *id_address) @@ -665,6 +679,7 @@ static void direct_link_node_socket(BlendDataReader *reader, bNodeSocket *sock) BLO_read_data_address(reader, &sock->default_value); sock->total_inputs = 0; /* Clear runtime data set before drawing. */ sock->cache = nullptr; + sock->declaration = nullptr; } /* ntree itself has been read! */ @@ -828,6 +843,9 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree) ntree->update |= NTREE_UPDATE_FIELD_INFERENCING; } + BLO_read_data_address(reader, &ntree->preview); + BKE_previewimg_blend_read(reader, ntree->preview); + /* type verification is in lib-link */ } @@ -1029,6 +1047,7 @@ IDTypeInfo IDType_ID_NT = { /* name_plural */ "node_groups", /* translation_context */ BLT_I18NCONTEXT_ID_NODETREE, /* flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE, + /* asset_type_info */ nullptr, /* init_data */ ntree_init_data, /* copy_data */ ntree_copy_data, @@ -1051,8 +1070,7 @@ IDTypeInfo IDType_ID_NT = { static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType *ntype) { if (ntype->declare != nullptr) { - nodeDeclarationEnsure(ntree, node); - node->declaration->build(*ntree, *node); + node_verify_sockets(ntree, node, true); return; } bNodeSocketTemplate *sockdef; @@ -1141,15 +1159,15 @@ static void ntree_set_typeinfo(bNodeTree *ntree, bNodeTreeType *typeinfo) { if (typeinfo) { ntree->typeinfo = typeinfo; - - /* deprecated integer type */ - ntree->type = typeinfo->type; } else { ntree->typeinfo = &NodeTreeTypeUndefined; ntree->init &= ~NTREE_TYPE_INIT; } + + /* Deprecated integer type. */ + ntree->type = ntree->typeinfo->type; } static void node_set_typeinfo(const struct bContext *C, @@ -1523,7 +1541,7 @@ static bNodeSocket *make_socket(bNodeTree *ntree, } /* make the identifier unique */ BLI_uniquename_cb( - unique_identifier_check, lb, "socket", '.', auto_identifier, sizeof(auto_identifier)); + unique_identifier_check, lb, "socket", '_', auto_identifier, sizeof(auto_identifier)); bNodeSocket *sock = (bNodeSocket *)MEM_callocN(sizeof(bNodeSocket), "sock"); sock->in_out = in_out; @@ -3975,8 +3993,10 @@ int nodeSocketIsHidden(const bNodeSocket *sock) return ((sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) != 0); } -void nodeSetSocketAvailability(bNodeSocket *sock, bool is_available) +void nodeSetSocketAvailability(bNodeTree *UNUSED(ntree), bNodeSocket *sock, bool is_available) { + /* #ntree is not needed right now, but it's generally necessary when changing the tree because we + * want to tag it as changed in the future. */ if (is_available) { sock->flag &= ~SOCK_UNAVAIL; } @@ -3999,17 +4019,38 @@ int nodeSocketLinkLimit(const bNodeSocket *sock) return sock->limit; } +static void update_socket_declarations(ListBase *sockets, + Span<blender::nodes::SocketDeclarationPtr> declarations) +{ + int index; + LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, sockets, index) { + const SocketDeclaration &socket_decl = *declarations[index]; + socket->declaration = &socket_decl; + } +} + /** - * If the node implements a `declare` function, this function makes sure that `node->declaration` - * is up to date. + * Update `socket->declaration` for all sockets in the node. This assumes that the node declaration + * and sockets are up to date already. */ -void nodeDeclarationEnsure(bNodeTree *UNUSED(ntree), bNode *node) +void nodeSocketDeclarationsUpdate(bNode *node) +{ + BLI_assert(node->declaration != nullptr); + update_socket_declarations(&node->inputs, node->declaration->inputs()); + update_socket_declarations(&node->outputs, node->declaration->outputs()); +} + +/** + * Just update `node->declaration` if necessary. This can also be called on nodes that may not be + * up to date (e.g. because the need versioning or are dynamic). + */ +bool nodeDeclarationEnsureOnOutdatedNode(bNodeTree *UNUSED(ntree), bNode *node) { if (node->declaration != nullptr) { - return; + return false; } if (node->typeinfo->declare == nullptr) { - return; + return false; } if (node->typeinfo->declaration_is_dynamic) { node->declaration = new blender::nodes::NodeDeclaration(); @@ -4021,6 +4062,20 @@ void nodeDeclarationEnsure(bNodeTree *UNUSED(ntree), bNode *node) BLI_assert(node->typeinfo->fixed_declaration != nullptr); node->declaration = node->typeinfo->fixed_declaration; } + return true; +} + +/** + * If the node implements a `declare` function, this function makes sure that `node->declaration` + * is up to date. It is expected that the sockets of the node are up to date already. + */ +bool nodeDeclarationEnsure(bNodeTree *ntree, bNode *node) +{ + if (nodeDeclarationEnsureOnOutdatedNode(ntree, node)) { + nodeSocketDeclarationsUpdate(node); + return true; + } + return false; } /* ************** Node Clipboard *********** */ @@ -4492,18 +4547,6 @@ void ntreeUpdateAllNew(Main *main) FOREACH_NODETREE_END; } -static FieldInferencingInterface *node_field_inferencing_interface_copy( - const FieldInferencingInterface &field_inferencing_interface) -{ - return new FieldInferencingInterface(field_inferencing_interface); -} - -static void node_field_inferencing_interface_free( - const FieldInferencingInterface *field_inferencing_interface) -{ - delete field_inferencing_interface; -} - namespace blender::bke::node_field_inferencing { static bool is_field_socket_type(eNodeSocketDatatype type) @@ -5195,9 +5238,8 @@ bool nodeUpdateID(bNodeTree *ntree, ID *id) void nodeUpdateInternalLinks(bNodeTree *ntree, bNode *node) { BLI_freelistN(&node->internal_links); - - if (node->typeinfo && node->typeinfo->update_internal_links) { - node->typeinfo->update_internal_links(ntree, node); + if (!node->typeinfo->no_muting) { + node_internal_links_create(ntree, node); } } @@ -5462,12 +5504,6 @@ void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpu_fn) ntype->gpu_fn = gpu_fn; } -void node_type_internal_links(bNodeType *ntype, - void (*update_internal_links)(bNodeTree *, bNode *)) -{ - ntype->update_internal_links = update_internal_links; -} - /* callbacks for undefined types */ static bool node_undefined_poll(bNodeType *UNUSED(ntype), @@ -5485,6 +5521,7 @@ static void register_undefined_types() * they are just used as placeholders in case the actual types are not registered. */ + NodeTreeTypeUndefined.type = NTREE_UNDEFINED; strcpy(NodeTreeTypeUndefined.idname, "NodeTreeUndefined"); strcpy(NodeTreeTypeUndefined.ui_name, N_("Undefined")); strcpy(NodeTreeTypeUndefined.ui_description, N_("Undefined Node Tree Type")); diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc index 45e14675107..e3b9e4109ed 100644 --- a/source/blender/blenkernel/intern/object.cc +++ b/source/blender/blenkernel/intern/object.cc @@ -160,11 +160,10 @@ static CLG_LogRef LOG = {"bke.object"}; /** - * Vertex parent modifies original BMesh which is not safe for threading. + * NOTE(@sergey): Vertex parent modifies original #BMesh which is not safe for threading. * Ideally such a modification should be handled as a separate DAG update - * callback for mesh datablock, but for until it is actually supported use + * callback for mesh data-block, but for until it is actually supported use * simpler solution with a mutex lock. - * - sergey - */ #define VPARENT_THREADING_HACK @@ -390,7 +389,8 @@ static void library_foreach_modifiersForeachIDLink(void *user_data, int cb_flag) { LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag)); } static void library_foreach_gpencil_modifiersForeachIDLink(void *user_data, @@ -399,7 +399,8 @@ static void library_foreach_gpencil_modifiersForeachIDLink(void *user_data, int cb_flag) { LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag)); } static void library_foreach_shaderfxForeachIDLink(void *user_data, @@ -408,7 +409,8 @@ static void library_foreach_shaderfxForeachIDLink(void *user_data, int cb_flag) { LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag)); } static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), @@ -418,7 +420,8 @@ static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), { LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; const int cb_flag = is_reference ? IDWALK_CB_USER : IDWALK_CB_NOP; - BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag)); } static void library_foreach_particlesystemsObjectLooper(ParticleSystem *UNUSED(psys), @@ -427,7 +430,8 @@ static void library_foreach_particlesystemsObjectLooper(ParticleSystem *UNUSED(p int cb_flag) { LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag)); } static void object_foreach_id(ID *id, LibraryForeachIDData *data) @@ -494,10 +498,18 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data) const int cb_flag_orig = BKE_lib_query_foreachid_process_callback_flag_override( data, proxy_cb_flag, false); LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { - IDP_foreach_property( - pchan->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + IDP_foreach_property(pchan->prop, + IDP_TYPE_FILTER_ID, + BKE_lib_query_idpropertiesForeachIDLink_callback, + data)); + BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, pchan->custom, IDWALK_CB_USER); - BKE_constraints_id_loop(&pchan->constraints, library_foreach_constraintObjectLooper, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + BKE_constraints_id_loop( + &pchan->constraints, library_foreach_constraintObjectLooper, data)); } BKE_lib_query_foreachid_process_callback_flag_override(data, cb_flag_orig, true); } @@ -509,14 +521,21 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data) data, object->rigidbody_constraint->ob2, IDWALK_CB_NEVER_SELF); } - BKE_modifiers_foreach_ID_link(object, library_foreach_modifiersForeachIDLink, data); - BKE_gpencil_modifiers_foreach_ID_link( - object, library_foreach_gpencil_modifiersForeachIDLink, data); - BKE_constraints_id_loop(&object->constraints, library_foreach_constraintObjectLooper, data); - BKE_shaderfx_foreach_ID_link(object, library_foreach_shaderfxForeachIDLink, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_modifiers_foreach_ID_link(object, library_foreach_modifiersForeachIDLink, data)); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + BKE_gpencil_modifiers_foreach_ID_link( + object, library_foreach_gpencil_modifiersForeachIDLink, data)); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + BKE_constraints_id_loop(&object->constraints, library_foreach_constraintObjectLooper, data)); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_shaderfx_foreach_ID_link(object, library_foreach_shaderfxForeachIDLink, data)); LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) { - BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, data)); } if (object->soft) { @@ -1204,7 +1223,7 @@ static IDProperty *object_asset_dimensions_property(Object *ob) return nullptr; } - IDPropertyTemplate idprop = {0}; + IDPropertyTemplate idprop{}; idprop.array.len = ARRAY_SIZE(dimensions); idprop.array.type = IDP_FLOAT; @@ -1239,6 +1258,7 @@ IDTypeInfo IDType_ID_OB = { /* name_plural */ "objects", /* translation_context */ BLT_I18NCONTEXT_ID_OBJECT, /* flags */ 0, + /* asset_type_info */ &AssetType_OB, /* init_data */ object_init_data, /* copy_data */ object_copy_data, @@ -1256,8 +1276,6 @@ IDTypeInfo IDType_ID_OB = { /* blend_read_undo_preserve */ nullptr, /* lib_override_apply_post */ object_lib_override_apply_post, - - /* asset_type_info */ &AssetType_OB, }; void BKE_object_workob_clear(Object *workob) @@ -1747,24 +1765,24 @@ static void object_update_from_subsurf_ccg(Object *object) /* NOTE: we need to reshape into an original mesh from main database, * allowing: * - * - Update copies of that mesh at any moment. - * - Save the file without doing extra reshape. - * - All the users of the mesh have updated displacement. + * - Update copies of that mesh at any moment. + * - Save the file without doing extra reshape. + * - All the users of the mesh have updated displacement. * * However, the tricky part here is that we only know about sculpted * state of a mesh on an object level, and object is being updated after - * mesh datablock is updated. This forces us to: + * mesh data-block is updated. This forces us to: * - * - Update mesh datablock from object evaluation, which is technically - * forbidden, but there is no other place for this yet. - * - Reshape to the original mesh from main database, and then copy updated - * layer to copy of that mesh (since copy of the mesh has decoupled - * custom data layers). + * - Update mesh data-block from object evaluation, which is technically + * forbidden, but there is no other place for this yet. + * - Reshape to the original mesh from main database, and then copy updated + * layer to copy of that mesh (since copy of the mesh has decoupled + * custom data layers). * * All this is defeating all the designs we need to follow to allow safe * threaded evaluation, but this is as good as we can make it within the * current sculpt/evaluated mesh design. This is also how we've survived - * with old DerivedMesh based solutions. So, while this is all wrong and + * with old #DerivedMesh based solutions. So, while this is all wrong and * needs reconsideration, doesn't seem to be a big stopper for real * production artists. */ @@ -1803,7 +1821,7 @@ void BKE_object_eval_assign_data(Object *object_eval, ID *data_eval, bool is_own object_eval->runtime.data_eval = data_eval; object_eval->runtime.is_data_eval_owned = is_owned; - /* Overwrite data of evaluated object, if the datablock types match. */ + /* Overwrite data of evaluated object, if the data-block types match. */ ID *data = (ID *)object_eval->data; if (GS(data->name) == GS(data_eval->name)) { /* NOTE: we are not supposed to invoke evaluation for original objects, @@ -1845,8 +1863,8 @@ void BKE_object_free_derived_caches(Object *ob) ob->runtime.mesh_deform_eval = nullptr; } - /* Restore initial pointer for copy-on-write datablocks, object->data - * might be pointing to an evaluated datablock data was just freed above. */ + /* Restore initial pointer for copy-on-write data-blocks, object->data + * might be pointing to an evaluated data-block data was just freed above. */ if (ob->runtime.data_orig != nullptr) { ob->data = ob->runtime.data_orig; } @@ -2345,13 +2363,13 @@ Object *BKE_object_add_from( } /** - * Add a new object, but assign the given datablock as the ob->data + * Add a new object, but assign the given data-block as the `ob->data` * for the newly created object. * - * \param data: The datablock to assign as ob->data for the new object. - * This is assumed to be of the correct type. - * \param do_id_user: If true, id_us_plus() will be called on data when - * assigning it to the object. + * \param data: The data-block to assign as `ob->data` for the new object. + * This is assumed to be of the correct type. + * \param do_id_user: If true, #id_us_plus() will be called on data when + * assigning it to the object. */ Object *BKE_object_add_for_data( Main *bmain, ViewLayer *view_layer, int type, const char *name, ID *data, bool do_id_user) @@ -2616,7 +2634,7 @@ Object **BKE_object_pose_array_get_ex(ViewLayer *view_layer, Object *ob_pose = BKE_object_pose_armature_get(ob_active); Object **objects = nullptr; if (ob_pose == ob_active) { - ObjectsInModeParams ob_params = {0}; + ObjectsInModeParams ob_params{}; ob_params.object_mode = OB_MODE_POSE; ob_params.no_dup_data = unique; @@ -2663,7 +2681,7 @@ Base **BKE_object_pose_base_array_get_ex(ViewLayer *view_layer, } if (base_active && (base_pose == base_active)) { - ObjectsInModeParams ob_params = {0}; + ObjectsInModeParams ob_params{}; ob_params.object_mode = OB_MODE_POSE; ob_params.no_dup_data = unique; @@ -2851,7 +2869,7 @@ Object *BKE_object_duplicate(Main *bmain, Object *ob, uint dupflag, uint duplica if (!is_subprocess) { /* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW. */ - BKE_libblock_relink_to_newid((ID *)&obn->id); + BKE_libblock_relink_to_newid(bmain, &obn->id, 0); #ifndef NDEBUG /* Call to `BKE_libblock_relink_to_newid` above is supposed to have cleared all those flags. */ @@ -4316,7 +4334,7 @@ void BKE_object_foreach_display_point(Object *ob, } } else if (ob->type == OB_GPENCIL) { - GPencilStrokePointIterData iter_data = {nullptr}; + GPencilStrokePointIterData iter_data{}; iter_data.obmat = obmat; iter_data.point_func_cb = func_cb; iter_data.user_data = user_data; @@ -4354,28 +4372,18 @@ void BKE_scene_foreach_display_point(Depsgraph *depsgraph, } /** - * Struct members from DNA_object_types.h + * See struct members from #Object in DNA_object_types.h */ struct ObTfmBack { float loc[3], dloc[3]; - /** scale and delta scale. */ float scale[3], dscale[3]; - /** euler rotation. */ float rot[3], drot[3]; - /** quaternion rotation. */ float quat[4], dquat[4]; - /** axis angle rotation - axis part. */ float rotAxis[3], drotAxis[3]; - /** axis angle rotation - angle part. */ float rotAngle, drotAngle; - /** final worldspace matrix with constraints & animsys applied. */ float obmat[4][4]; - /** inverse result of parent, so that object doesn't 'stick' to parent. */ float parentinv[4][4]; - /** inverse result of constraints. doesn't include effect of parent or object local transform. - */ float constinv[4][4]; - /** inverse matrix of 'obmat' for during render, temporally: ipokeys of transform. */ float imat[4][4]; }; @@ -5432,7 +5440,7 @@ void BKE_object_groups_clear(Main *bmain, Scene *scene, Object *ob) } /** - * Return a KDTree_3d from the deformed object (in worldspace) + * Return a KDTree_3d from the deformed object (in world-space). * * \note Only mesh objects currently support deforming, others are TODO. * @@ -5458,7 +5466,7 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot) MVert *mvert = me_eval->mvert; uint totvert = me_eval->totvert; - /* tree over-allocs in case where some verts have ORIGINDEX_NONE */ + /* Tree over-allocates in case where some verts have #ORIGINDEX_NONE. */ tot = 0; tree = BLI_kdtree_3d_new(totvert); diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index d6030941c6d..9c4b7ebb37a 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -143,6 +143,7 @@ IDTypeInfo IDType_ID_PAL = { .name_plural = "palettes", .translation_context = BLT_I18NCONTEXT_ID_PALETTE, .flags = IDTYPE_FLAGS_NO_ANIMDATA, + .asset_type_info = NULL, .init_data = palette_init_data, .copy_data = palette_copy_data, @@ -208,6 +209,7 @@ IDTypeInfo IDType_ID_PC = { .name_plural = "paint_curves", .translation_context = BLT_I18NCONTEXT_ID_PAINTCURVE, .flags = IDTYPE_FLAGS_NO_ANIMDATA, + .asset_type_info = NULL, .init_data = NULL, .copy_data = paint_curve_copy_data, diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index b13fd8a395f..bb3113c7e28 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -180,7 +180,8 @@ static void particle_settings_foreach_id(ID *id, LibraryForeachIDData *data) for (int i = 0; i < MAX_MTEX; i++) { if (psett->mtex[i]) { - BKE_texture_mtex_foreach_id(data, psett->mtex[i]); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, + BKE_texture_mtex_foreach_id(data, psett->mtex[i])); } } @@ -499,6 +500,7 @@ IDTypeInfo IDType_ID_PA = { .name_plural = "particles", .translation_context = BLT_I18NCONTEXT_ID_PARTICLESETTINGS, .flags = 0, + .asset_type_info = NULL, .init_data = particle_settings_init, .copy_data = particle_settings_copy_data, diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 3358f3e6dea..2318a05e635 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -2798,7 +2798,7 @@ float (*BKE_pbvh_vert_coords_alloc(PBVH *pbvh))[3] void BKE_pbvh_vert_coords_apply(PBVH *pbvh, const float (*vertCos)[3], const int totvert) { if (totvert != pbvh->totvert) { - BLI_assert_msg(0, "PBVH: Given deforming vcos number does not natch PBVH vertex number!"); + BLI_assert_msg(0, "PBVH: Given deforming vcos number does not match PBVH vertex number!"); return; } diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc index 15c5a809118..26d9c88566c 100644 --- a/source/blender/blenkernel/intern/pointcloud.cc +++ b/source/blender/blenkernel/intern/pointcloud.cc @@ -175,6 +175,7 @@ IDTypeInfo IDType_ID_PT = { /* name_plural */ "pointclouds", /* translation_context */ BLT_I18NCONTEXT_ID_POINTCLOUD, /* flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE, + /* asset_type_info */ nullptr, /* init_data */ pointcloud_init_data, /* copy_data */ pointcloud_copy_data, diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 0aeee11ed17..a5937326e3b 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -471,7 +471,8 @@ static void scene_foreach_rigidbodyworldSceneLooper(struct RigidBodyWorld *UNUSE int cb_flag) { LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag)); } /** @@ -522,7 +523,10 @@ static void scene_foreach_toolsettings_id_pointer_process( } } -#define BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS( \ +/* Special handling is needed here, as `scene_foreach_toolsettings` (and its dependency + * `scene_foreach_paint`) are also used by `scene_undo_preserve`, where `LibraryForeachIDData + * *data` is NULL. */ +#define BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER( \ __data, __id, __do_undo_restore, __action, __reader, __id_old, __cb_flag) \ { \ if (__do_undo_restore) { \ @@ -530,24 +534,38 @@ static void scene_foreach_toolsettings_id_pointer_process( (ID **)&(__id), __action, __reader, (ID **)&(__id_old), __cb_flag); \ } \ else { \ + BLI_assert((__data) != NULL); \ BKE_LIB_FOREACHID_PROCESS_IDSUPER(__data, __id, __cb_flag); \ } \ } \ (void)0 +#define BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( \ + __data, __do_undo_restore, __func_call) \ + { \ + if (__do_undo_restore) { \ + __func_call; \ + } \ + else { \ + BLI_assert((__data) != NULL); \ + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(__data, __func_call); \ + } \ + } \ + (void)0 + static void scene_foreach_paint(LibraryForeachIDData *data, Paint *paint, const bool do_undo_restore, BlendLibReader *reader, Paint *paint_old) { - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - paint->brush, - do_undo_restore, - SCENE_FOREACH_UNDO_RESTORE, - reader, - paint_old->brush, - IDWALK_CB_USER); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + paint->brush, + do_undo_restore, + SCENE_FOREACH_UNDO_RESTORE, + reader, + paint_old->brush, + IDWALK_CB_USER); for (int i = 0; i < paint_old->tool_slots_len; i++) { /* This is a bit tricky. * - In case we do not do `undo_restore`, `paint` and `paint_old` pointers are the same, so @@ -559,21 +577,21 @@ static void scene_foreach_paint(LibraryForeachIDData *data, */ Brush *brush_tmp = NULL; Brush **brush_p = i < paint->tool_slots_len ? &paint->tool_slots[i].brush : &brush_tmp; - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - *brush_p, - do_undo_restore, - SCENE_FOREACH_UNDO_RESTORE, - reader, - paint_old->brush, - IDWALK_CB_USER); - } - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - paint->palette, - do_undo_restore, - SCENE_FOREACH_UNDO_RESTORE, - reader, - paint_old->palette, - IDWALK_CB_USER); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + *brush_p, + do_undo_restore, + SCENE_FOREACH_UNDO_RESTORE, + reader, + paint_old->brush, + IDWALK_CB_USER); + } + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + paint->palette, + do_undo_restore, + SCENE_FOREACH_UNDO_RESTORE, + reader, + paint_old->palette, + IDWALK_CB_USER); } static void scene_foreach_toolsettings(LibraryForeachIDData *data, @@ -582,110 +600,152 @@ static void scene_foreach_toolsettings(LibraryForeachIDData *data, BlendLibReader *reader, ToolSettings *toolsett_old) { - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - toolsett->particle.scene, - do_undo_restore, - SCENE_FOREACH_UNDO_NO_RESTORE, - reader, - toolsett_old->particle.scene, - IDWALK_CB_NOP); - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - toolsett->particle.object, - do_undo_restore, - SCENE_FOREACH_UNDO_NO_RESTORE, - reader, - toolsett_old->particle.object, - IDWALK_CB_NOP); - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - toolsett->particle.shape_object, - do_undo_restore, - SCENE_FOREACH_UNDO_NO_RESTORE, - reader, - toolsett_old->particle.shape_object, - IDWALK_CB_NOP); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + toolsett->particle.scene, + do_undo_restore, + SCENE_FOREACH_UNDO_NO_RESTORE, + reader, + toolsett_old->particle.scene, + IDWALK_CB_NOP); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + toolsett->particle.object, + do_undo_restore, + SCENE_FOREACH_UNDO_NO_RESTORE, + reader, + toolsett_old->particle.object, + IDWALK_CB_NOP); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + toolsett->particle.shape_object, + do_undo_restore, + SCENE_FOREACH_UNDO_NO_RESTORE, + reader, + toolsett_old->particle.shape_object, + IDWALK_CB_NOP); scene_foreach_paint( data, &toolsett->imapaint.paint, do_undo_restore, reader, &toolsett_old->imapaint.paint); - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - toolsett->imapaint.stencil, - do_undo_restore, - SCENE_FOREACH_UNDO_RESTORE, - reader, - toolsett_old->imapaint.stencil, - IDWALK_CB_USER); - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - toolsett->imapaint.clone, - do_undo_restore, - SCENE_FOREACH_UNDO_RESTORE, - reader, - toolsett_old->imapaint.clone, - IDWALK_CB_USER); - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - toolsett->imapaint.canvas, - do_undo_restore, - SCENE_FOREACH_UNDO_RESTORE, - reader, - toolsett_old->imapaint.canvas, - IDWALK_CB_USER); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + toolsett->imapaint.stencil, + do_undo_restore, + SCENE_FOREACH_UNDO_RESTORE, + reader, + toolsett_old->imapaint.stencil, + IDWALK_CB_USER); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + toolsett->imapaint.clone, + do_undo_restore, + SCENE_FOREACH_UNDO_RESTORE, + reader, + toolsett_old->imapaint.clone, + IDWALK_CB_USER); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + toolsett->imapaint.canvas, + do_undo_restore, + SCENE_FOREACH_UNDO_RESTORE, + reader, + toolsett_old->imapaint.canvas, + IDWALK_CB_USER); if (toolsett->vpaint) { - scene_foreach_paint( - data, &toolsett->vpaint->paint, do_undo_restore, reader, &toolsett_old->vpaint->paint); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( + data, + do_undo_restore, + scene_foreach_paint(data, + &toolsett->vpaint->paint, + do_undo_restore, + reader, + &toolsett_old->vpaint->paint)); } if (toolsett->wpaint) { - scene_foreach_paint( - data, &toolsett->wpaint->paint, do_undo_restore, reader, &toolsett_old->wpaint->paint); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( + data, + do_undo_restore, + scene_foreach_paint(data, + &toolsett->wpaint->paint, + do_undo_restore, + reader, + &toolsett_old->wpaint->paint)); } if (toolsett->sculpt) { - scene_foreach_paint( - data, &toolsett->sculpt->paint, do_undo_restore, reader, &toolsett_old->sculpt->paint); - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - toolsett->sculpt->gravity_object, - do_undo_restore, - SCENE_FOREACH_UNDO_NO_RESTORE, - reader, - toolsett_old->sculpt->gravity_object, - IDWALK_CB_NOP); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( + data, + do_undo_restore, + scene_foreach_paint(data, + &toolsett->sculpt->paint, + do_undo_restore, + reader, + &toolsett_old->sculpt->paint)); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + toolsett->sculpt->gravity_object, + do_undo_restore, + SCENE_FOREACH_UNDO_NO_RESTORE, + reader, + toolsett_old->sculpt->gravity_object, + IDWALK_CB_NOP); } if (toolsett->uvsculpt) { - scene_foreach_paint( - data, &toolsett->uvsculpt->paint, do_undo_restore, reader, &toolsett_old->uvsculpt->paint); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( + data, + do_undo_restore, + scene_foreach_paint(data, + &toolsett->uvsculpt->paint, + do_undo_restore, + reader, + &toolsett_old->uvsculpt->paint)); } if (toolsett->gp_paint) { - scene_foreach_paint( - data, &toolsett->gp_paint->paint, do_undo_restore, reader, &toolsett_old->gp_paint->paint); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( + data, + do_undo_restore, + scene_foreach_paint(data, + &toolsett->gp_paint->paint, + do_undo_restore, + reader, + &toolsett_old->gp_paint->paint)); } if (toolsett->gp_vertexpaint) { - scene_foreach_paint(data, - &toolsett->gp_vertexpaint->paint, - do_undo_restore, - reader, - &toolsett_old->gp_vertexpaint->paint); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( + data, + do_undo_restore, + scene_foreach_paint(data, + &toolsett->gp_vertexpaint->paint, + do_undo_restore, + reader, + &toolsett_old->gp_vertexpaint->paint)); } if (toolsett->gp_sculptpaint) { - scene_foreach_paint(data, - &toolsett->gp_sculptpaint->paint, - do_undo_restore, - reader, - &toolsett_old->gp_sculptpaint->paint); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( + data, + do_undo_restore, + scene_foreach_paint(data, + &toolsett->gp_sculptpaint->paint, + do_undo_restore, + reader, + &toolsett_old->gp_sculptpaint->paint)); } if (toolsett->gp_weightpaint) { - scene_foreach_paint(data, - &toolsett->gp_weightpaint->paint, - do_undo_restore, - reader, - &toolsett_old->gp_weightpaint->paint); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( + data, + do_undo_restore, + scene_foreach_paint(data, + &toolsett->gp_weightpaint->paint, + do_undo_restore, + reader, + &toolsett_old->gp_weightpaint->paint)); } - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - toolsett->gp_sculpt.guide.reference_object, - do_undo_restore, - SCENE_FOREACH_UNDO_NO_RESTORE, - reader, - toolsett_old->gp_sculpt.guide.reference_object, - IDWALK_CB_NOP); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + toolsett->gp_sculpt.guide.reference_object, + do_undo_restore, + SCENE_FOREACH_UNDO_NO_RESTORE, + reader, + toolsett_old->gp_sculpt.guide.reference_object, + IDWALK_CB_NOP); } +#undef BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER +#undef BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL + static void scene_foreach_layer_collection(LibraryForeachIDData *data, ListBase *lb) { LISTBASE_FOREACH (LayerCollection *, lc, lb) { @@ -707,7 +767,8 @@ static bool seq_foreach_member_id_cb(Sequence *seq, void *user_data) #define FOREACHID_PROCESS_IDSUPER(_data, _id_super, _cb_flag) \ { \ CHECK_TYPE(&((_id_super)->id), ID *); \ - if (!BKE_lib_query_foreachid_process((_data), (ID **)&(_id_super), (_cb_flag))) { \ + BKE_lib_query_foreachid_process((_data), (ID **)&(_id_super), (_cb_flag)); \ + if (BKE_lib_query_foreachid_iter_stop((_data))) { \ return false; \ } \ } \ @@ -746,15 +807,18 @@ static void scene_foreach_id(ID *id, LibraryForeachIDData *data) BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, scene->r.bake.cage_object, IDWALK_CB_NOP); if (scene->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - BKE_library_foreach_ID_embedded(data, (ID **)&scene->nodetree); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_library_foreach_ID_embedded(data, (ID **)&scene->nodetree)); } if (scene->ed) { - SEQ_for_each_callback(&scene->ed->seqbase, seq_foreach_member_id_cb, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, SEQ_for_each_callback(&scene->ed->seqbase, seq_foreach_member_id_cb, data)); } /* This pointer can be NULL during old files reading, better be safe than sorry. */ if (scene->master_collection != NULL) { - BKE_library_foreach_ID_embedded(data, (ID **)&scene->master_collection); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_library_foreach_ID_embedded(data, (ID **)&scene->master_collection)); } LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { @@ -765,7 +829,8 @@ static void scene_foreach_id(ID *id, LibraryForeachIDData *data) data, base->object, IDWALK_CB_NOP | IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE); } - scene_foreach_layer_collection(data, &view_layer->layer_collections); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, scene_foreach_layer_collection(data, &view_layer->layer_collections)); LISTBASE_FOREACH (FreestyleModuleConfig *, fmc, &view_layer->freestyle_config.modules) { if (fmc->script) { @@ -786,18 +851,25 @@ static void scene_foreach_id(ID *id, LibraryForeachIDData *data) LISTBASE_FOREACH (TimeMarker *, marker, &scene->markers) { BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, marker->camera, IDWALK_CB_NOP); - IDP_foreach_property( - marker->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + IDP_foreach_property(marker->prop, + IDP_TYPE_FILTER_ID, + BKE_lib_query_idpropertiesForeachIDLink_callback, + data)); } ToolSettings *toolsett = scene->toolsettings; if (toolsett) { - scene_foreach_toolsettings(data, toolsett, false, NULL, toolsett); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, scene_foreach_toolsettings(data, toolsett, false, NULL, toolsett)); } if (scene->rigidbody_world) { - BKE_rigidbody_world_id_loop( - scene->rigidbody_world, scene_foreach_rigidbodyworldSceneLooper, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + BKE_rigidbody_world_id_loop( + scene->rigidbody_world, scene_foreach_rigidbodyworldSceneLooper, data)); } } @@ -1528,6 +1600,7 @@ IDTypeInfo IDType_ID_SCE = { .name_plural = "scenes", .translation_context = BLT_I18NCONTEXT_ID_SCENE, .flags = 0, + .asset_type_info = NULL, .init_data = scene_init_data, .copy_data = scene_copy_data, @@ -1853,7 +1926,7 @@ Scene *BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type) if (!is_subprocess) { /* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW. */ - BKE_libblock_relink_to_newid(&sce_copy->id); + BKE_libblock_relink_to_newid(bmain, &sce_copy->id, 0); #ifndef NDEBUG /* Call to `BKE_libblock_relink_to_newid` above is supposed to have cleared all those diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 233a4f344b5..81c85e93cc0 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -97,6 +97,10 @@ static void screen_foreach_id_dopesheet(LibraryForeachIDData *data, bDopeSheet * } } +/** + * Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of + * `IDTypeInfo` structure). + */ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area) { BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, area->full, IDWALK_CB_NOP); @@ -107,10 +111,8 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area switch (sl->spacetype) { case SPACE_VIEW3D: { View3D *v3d = (View3D *)sl; - BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, v3d->camera, IDWALK_CB_NOP); BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, v3d->ob_center, IDWALK_CB_NOP); - if (v3d->localvd) { BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, v3d->localvd->camera, IDWALK_CB_NOP); } @@ -118,13 +120,12 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area } case SPACE_GRAPH: { SpaceGraph *sipo = (SpaceGraph *)sl; - - screen_foreach_id_dopesheet(data, sipo->ads); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, + screen_foreach_id_dopesheet(data, sipo->ads)); break; } case SPACE_PROPERTIES: { SpaceProperties *sbuts = (SpaceProperties *)sl; - BKE_LIB_FOREACHID_PROCESS_ID(data, sbuts->pinid, IDWALK_CB_NOP); break; } @@ -132,14 +133,12 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area break; case SPACE_ACTION: { SpaceAction *saction = (SpaceAction *)sl; - screen_foreach_id_dopesheet(data, &saction->ads); BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, saction->action, IDWALK_CB_NOP); break; } case SPACE_IMAGE: { SpaceImage *sima = (SpaceImage *)sl; - BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sima->image, IDWALK_CB_USER_ONE); BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sima->mask_info.mask, IDWALK_CB_USER_ONE); BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sima->gpd, IDWALK_CB_USER); @@ -147,33 +146,28 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area } case SPACE_SEQ: { SpaceSeq *sseq = (SpaceSeq *)sl; - BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sseq->gpd, IDWALK_CB_USER); break; } case SPACE_NLA: { SpaceNla *snla = (SpaceNla *)sl; - - screen_foreach_id_dopesheet(data, snla->ads); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, + screen_foreach_id_dopesheet(data, snla->ads)); break; } case SPACE_TEXT: { SpaceText *st = (SpaceText *)sl; - BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, st->text, IDWALK_CB_NOP); break; } case SPACE_SCRIPT: { SpaceScript *scpt = (SpaceScript *)sl; - BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, scpt->script, IDWALK_CB_NOP); break; } case SPACE_OUTLINER: { SpaceOutliner *space_outliner = (SpaceOutliner *)sl; - BKE_LIB_FOREACHID_PROCESS_ID(data, space_outliner->search_tse.id, IDWALK_CB_NOP); - if (space_outliner->treestore != NULL) { TreeStoreElem *tselem; BLI_mempool_iter iter; @@ -187,13 +181,11 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area } case SPACE_NODE: { SpaceNode *snode = (SpaceNode *)sl; - const bool is_private_nodetree = snode->id != NULL && ntreeFromID(snode->id) == snode->nodetree; BKE_LIB_FOREACHID_PROCESS_ID(data, snode->id, IDWALK_CB_NOP); BKE_LIB_FOREACHID_PROCESS_ID(data, snode->from, IDWALK_CB_NOP); - BKE_LIB_FOREACHID_PROCESS_IDSUPER( data, snode->nodetree, is_private_nodetree ? IDWALK_CB_EMBEDDED : IDWALK_CB_USER_ONE); @@ -219,14 +211,12 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area } case SPACE_CLIP: { SpaceClip *sclip = (SpaceClip *)sl; - BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sclip->clip, IDWALK_CB_USER_ONE); BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sclip->mask_info.mask, IDWALK_CB_USER_ONE); break; } case SPACE_SPREADSHEET: { SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl; - LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) { if (context->type == SPREADSHEET_CONTEXT_OBJECT) { BKE_LIB_FOREACHID_PROCESS_IDSUPER( @@ -243,12 +233,13 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area static void screen_foreach_id(ID *id, LibraryForeachIDData *data) { - if (BKE_lib_query_foreachid_process_flags_get(data) & IDWALK_INCLUDE_UI) { - bScreen *screen = (bScreen *)id; + if ((BKE_lib_query_foreachid_process_flags_get(data) & IDWALK_INCLUDE_UI) == 0) { + return; + } + bScreen *screen = (bScreen *)id; - LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { - BKE_screen_foreach_id_screen_area(data, area); - } + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_screen_foreach_id_screen_area(data, area)); } } @@ -313,6 +304,7 @@ IDTypeInfo IDType_ID_SCR = { .name_plural = "screens", .translation_context = BLT_I18NCONTEXT_ID_SCREEN, .flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_ONLY_APPEND | IDTYPE_FLAGS_NO_ANIMDATA, + .asset_type_info = NULL, .init_data = NULL, .copy_data = NULL, diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc index 1d297b3ced9..44d326bdb64 100644 --- a/source/blender/blenkernel/intern/simulation.cc +++ b/source/blender/blenkernel/intern/simulation.cc @@ -103,7 +103,8 @@ static void simulation_foreach_id(ID *id, LibraryForeachIDData *data) Simulation *simulation = (Simulation *)id; if (simulation->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - BKE_library_foreach_ID_embedded(data, (ID **)&simulation->nodetree); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_library_foreach_ID_embedded(data, (ID **)&simulation->nodetree)); } } @@ -153,6 +154,7 @@ IDTypeInfo IDType_ID_SIM = { /* name_plural */ "simulations", /* translation_context */ BLT_I18NCONTEXT_ID_SIMULATION, /* flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE, + /* asset_type_info */ nullptr, /* init_data */ simulation_init_data, /* copy_data */ simulation_copy_data, diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index b7eb9d31b23..a008edd038a 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -2633,7 +2633,7 @@ static void interpolate_exciter(Object *ob, int timescale, int time) } } -/* ************ convertors ********** */ +/* ************ converters ********** */ /* for each object type we need; * - xxxx_to_softbody(Object *ob) : a full (new) copy, creates SB geometry diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index f523c5e02bd..ce348648532 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -205,6 +205,7 @@ IDTypeInfo IDType_ID_SO = { .name_plural = "sounds", .translation_context = BLT_I18NCONTEXT_ID_SOUND, .flags = IDTYPE_FLAGS_NO_ANIMDATA | IDTYPE_FLAGS_APPEND_IS_REUSABLE, + .asset_type_info = NULL, /* A fuzzy case, think NULLified content is OK here... */ .init_data = NULL, diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c index 230ff9d6da0..79a5e4fd9f4 100644 --- a/source/blender/blenkernel/intern/speaker.c +++ b/source/blender/blenkernel/intern/speaker.c @@ -99,6 +99,7 @@ IDTypeInfo IDType_ID_SPK = { .name_plural = "speakers", .translation_context = BLT_I18NCONTEXT_ID_SPEAKER, .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE, + .asset_type_info = NULL, .init_data = speaker_init_data, .copy_data = NULL, diff --git a/source/blender/blenkernel/intern/spline_base.cc b/source/blender/blenkernel/intern/spline_base.cc index c2c9d178171..52bbd2bec57 100644 --- a/source/blender/blenkernel/intern/spline_base.cc +++ b/source/blender/blenkernel/intern/spline_base.cc @@ -30,14 +30,12 @@ using blender::float3; using blender::IndexRange; using blender::MutableSpan; using blender::Span; +using blender::VArray; using blender::attribute_math::convert_to_static_type; using blender::bke::AttributeIDRef; using blender::fn::GMutableSpan; using blender::fn::GSpan; using blender::fn::GVArray; -using blender::fn::GVArray_For_GSpan; -using blender::fn::GVArray_Typed; -using blender::fn::GVArrayPtr; Spline::Type Spline::type() const { @@ -416,7 +414,7 @@ Span<float3> Spline::evaluated_normals() const } /* Rotate the generated normals with the interpolated tilt data. */ - GVArray_Typed<float> tilts = this->interpolate_to_evaluated(this->tilts()); + VArray<float> tilts = this->interpolate_to_evaluated(this->tilts()); for (const int i : normals.index_range()) { normals[i] = rotate_direction_around_axis(normals[i], tangents[i], tilts[i]); } @@ -529,9 +527,9 @@ void Spline::bounds_min_max(float3 &min, float3 &max, const bool use_evaluated) } } -GVArrayPtr Spline::interpolate_to_evaluated(GSpan data) const +GVArray Spline::interpolate_to_evaluated(GSpan data) const { - return this->interpolate_to_evaluated(GVArray_For_GSpan(data)); + return this->interpolate_to_evaluated(GVArray::ForSpan(data)); } /** @@ -547,7 +545,7 @@ void Spline::sample_with_index_factors(const GVArray &src, blender::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { using T = decltype(dummy); - const GVArray_Typed<T> src_typed = src.typed<T>(); + const VArray<T> src_typed = src.typed<T>(); MutableSpan<T> dst_typed = dst.typed<T>(); if (src.size() == 1) { dst_typed.fill(src_typed[0]); diff --git a/source/blender/blenkernel/intern/spline_bezier.cc b/source/blender/blenkernel/intern/spline_bezier.cc index 18d195f19da..0cadab998f5 100644 --- a/source/blender/blenkernel/intern/spline_bezier.cc +++ b/source/blender/blenkernel/intern/spline_bezier.cc @@ -25,9 +25,8 @@ using blender::float3; using blender::IndexRange; using blender::MutableSpan; using blender::Span; +using blender::VArray; using blender::fn::GVArray; -using blender::fn::GVArray_For_ArrayContainer; -using blender::fn::GVArrayPtr; void BezierSpline::copy_settings(Spline &dst) const { @@ -708,26 +707,26 @@ static void interpolate_to_evaluated_impl(const BezierSpline &spline, } } -GVArrayPtr BezierSpline::interpolate_to_evaluated(const GVArray &src) const +GVArray BezierSpline::interpolate_to_evaluated(const GVArray &src) const { BLI_assert(src.size() == this->size()); if (src.is_single()) { - return src.shallow_copy(); + return src; } const int eval_size = this->evaluated_points_size(); if (eval_size == 1) { - return src.shallow_copy(); + return src; } - GVArrayPtr new_varray; + GVArray new_varray; blender::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<blender::attribute_math::DefaultMixer<T>>) { Array<T> values(eval_size); interpolate_to_evaluated_impl<T>(*this, src.typed<T>(), values); - new_varray = std::make_unique<GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); diff --git a/source/blender/blenkernel/intern/spline_nurbs.cc b/source/blender/blenkernel/intern/spline_nurbs.cc index 6d30d8ba916..7fa332a0330 100644 --- a/source/blender/blenkernel/intern/spline_nurbs.cc +++ b/source/blender/blenkernel/intern/spline_nurbs.cc @@ -26,10 +26,8 @@ using blender::float3; using blender::IndexRange; using blender::MutableSpan; using blender::Span; +using blender::VArray; using blender::fn::GVArray; -using blender::fn::GVArray_For_ArrayContainer; -using blender::fn::GVArray_Typed; -using blender::fn::GVArrayPtr; void NURBSpline::copy_settings(Spline &dst) const { @@ -410,23 +408,23 @@ void interpolate_to_evaluated_impl(Span<NURBSpline::BasisCache> weights, mixer.finalize(); } -GVArrayPtr NURBSpline::interpolate_to_evaluated(const GVArray &src) const +GVArray NURBSpline::interpolate_to_evaluated(const GVArray &src) const { BLI_assert(src.size() == this->size()); if (src.is_single()) { - return src.shallow_copy(); + return src; } Span<BasisCache> basis_cache = this->calculate_basis_cache(); - GVArrayPtr new_varray; + GVArray new_varray; blender::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<blender::attribute_math::DefaultMixer<T>>) { Array<T> values(this->evaluated_points_size()); interpolate_to_evaluated_impl<T>(basis_cache, src.typed<T>(), values); - new_varray = std::make_unique<GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); @@ -448,8 +446,8 @@ Span<float3> NURBSpline::evaluated_positions() const evaluated_position_cache_.resize(eval_size); /* TODO: Avoid copying the evaluated data from the temporary array. */ - GVArray_Typed<float3> evaluated = Spline::interpolate_to_evaluated(positions_.as_span()); - evaluated->materialize(evaluated_position_cache_); + VArray<float3> evaluated = Spline::interpolate_to_evaluated(positions_.as_span()); + evaluated.materialize(evaluated_position_cache_); position_cache_dirty_ = false; return evaluated_position_cache_; diff --git a/source/blender/blenkernel/intern/spline_poly.cc b/source/blender/blenkernel/intern/spline_poly.cc index 338b5d0ac9e..d495c977285 100644 --- a/source/blender/blenkernel/intern/spline_poly.cc +++ b/source/blender/blenkernel/intern/spline_poly.cc @@ -23,7 +23,6 @@ using blender::float3; using blender::MutableSpan; using blender::Span; using blender::fn::GVArray; -using blender::fn::GVArrayPtr; void PolySpline::copy_settings(Spline &UNUSED(dst)) const { @@ -122,9 +121,8 @@ Span<float3> PolySpline::evaluated_positions() const * the original data. Therefore the lifetime of the returned virtual array must not be longer than * the source data. */ -GVArrayPtr PolySpline::interpolate_to_evaluated(const GVArray &src) const +GVArray PolySpline::interpolate_to_evaluated(const GVArray &src) const { BLI_assert(src.size() == this->size()); - - return src.shallow_copy(); + return src; } diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 0c58c8e8a5a..6796b1ac397 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -2020,7 +2020,7 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm, &dm->loopData, &ccgdm->dm.loopData, loopidx, w2, NULL, numVerts, loopindex2); loopindex2++; - /* Copy over poly data, e.g. mtexpoly. */ + /* Copy over poly data, e.g. #CD_FACEMAP. */ CustomData_copy_data(&dm->polyData, &ccgdm->dm.polyData, origIndex, faceNum, 1); /* Set original index data. */ diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 0cb2218e7e0..9655d2fcbca 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -242,6 +242,7 @@ IDTypeInfo IDType_ID_TXT = { .name_plural = "texts", .translation_context = BLT_I18NCONTEXT_ID_TEXT, .flags = IDTYPE_FLAGS_NO_ANIMDATA | IDTYPE_FLAGS_APPEND_IS_REUSABLE, + .asset_type_info = NULL, .init_data = text_init_data, .copy_data = text_copy_data, @@ -1977,7 +1978,7 @@ static char tab_to_spaces[] = " "; static void txt_convert_tab_to_spaces(Text *text) { /* sb aims to pad adjust the tab-width needed so that the right number of spaces - * is added so that the indention of the line is the right width (i.e. aligned + * is added so that the indentation of the line is the right width (i.e. aligned * to multiples of TXT_TABSIZE) */ const char *sb = &tab_to_spaces[text->curc % TXT_TABSIZE]; diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index c878abf0dff..f6e437088cc 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -142,7 +142,8 @@ static void texture_foreach_id(ID *id, LibraryForeachIDData *data) Tex *texture = (Tex *)id; if (texture->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - BKE_library_foreach_ID_embedded(data, (ID **)&texture->nodetree); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_library_foreach_ID_embedded(data, (ID **)&texture->nodetree)); } BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, texture->ima, IDWALK_CB_USER); } @@ -210,6 +211,7 @@ IDTypeInfo IDType_ID_TE = { .name_plural = "textures", .translation_context = BLT_I18NCONTEXT_ID_TEXTURE, .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE, + .asset_type_info = NULL, .init_data = texture_init_data, .copy_data = texture_copy_data, diff --git a/source/blender/blenkernel/intern/vfont.c b/source/blender/blenkernel/intern/vfont.c index 43c8a59baad..9ec81989d53 100644 --- a/source/blender/blenkernel/intern/vfont.c +++ b/source/blender/blenkernel/intern/vfont.c @@ -162,6 +162,7 @@ IDTypeInfo IDType_ID_VF = { .name_plural = "fonts", .translation_context = BLT_I18NCONTEXT_ID_VFONT, .flags = IDTYPE_FLAGS_NO_ANIMDATA | IDTYPE_FLAGS_APPEND_IS_REUSABLE, + .asset_type_info = NULL, .init_data = vfont_init_data, .copy_data = vfont_copy_data, diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc index a72b5268e1d..75f23ca0598 100644 --- a/source/blender/blenkernel/intern/volume.cc +++ b/source/blender/blenkernel/intern/volume.cc @@ -645,6 +645,7 @@ IDTypeInfo IDType_ID_VO = { /* name_plural */ "volumes", /* translation_context */ BLT_I18NCONTEXT_ID_VOLUME, /* flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE, + /* asset_type_info */ nullptr, /* init_data */ volume_init_data, /* copy_data */ volume_copy_data, diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c index 6269cfc4349..35a262470e7 100644 --- a/source/blender/blenkernel/intern/workspace.c +++ b/source/blender/blenkernel/intern/workspace.c @@ -187,6 +187,7 @@ IDTypeInfo IDType_ID_WS = { .name_plural = "workspaces", .translation_context = BLT_I18NCONTEXT_ID_WORKSPACE, .flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_ONLY_APPEND | IDTYPE_FLAGS_NO_ANIMDATA, + .asset_type_info = NULL, .init_data = workspace_init_data, .copy_data = NULL, diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index fe03c5b817a..5b6b90712cd 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -131,7 +131,8 @@ static void world_foreach_id(ID *id, LibraryForeachIDData *data) if (world->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - BKE_library_foreach_ID_embedded(data, (ID **)&world->nodetree); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_library_foreach_ID_embedded(data, (ID **)&world->nodetree)); } } @@ -191,6 +192,7 @@ IDTypeInfo IDType_ID_WO = { .name_plural = "worlds", .translation_context = BLT_I18NCONTEXT_ID_WORLD, .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE, + .asset_type_info = NULL, .init_data = world_init_data, .copy_data = world_copy_data, |