diff options
Diffstat (limited to 'source')
515 files changed, 11225 insertions, 7532 deletions
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h index 217a4d5d918..fa8e764139d 100644 --- a/source/blender/blenfont/BLF_api.h +++ b/source/blender/blenfont/BLF_api.h @@ -65,7 +65,7 @@ void BLF_metrics_attach(int fontid, unsigned char *mem, int mem_size); void BLF_aspect(int fontid, float x, float y, float z); void BLF_position(int fontid, float x, float y, float z); -void BLF_size(int fontid, int size, int dpi); +void BLF_size(int fontid, float size, int dpi); /* goal: small but useful color API */ void BLF_color4ubv(int fontid, const unsigned char rgba[4]); diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index 34ddb6f22d2..d6773916abd 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -363,7 +363,7 @@ void BLF_position(int fontid, float x, float y, float z) } } -void BLF_size(int fontid, int size, int dpi) +void BLF_size(int fontid, float size, int dpi) { FontBLF *font = blf_get(fontid); @@ -910,7 +910,7 @@ void BLF_state_print(int fontid) if (font) { printf("fontid %d %p\n", fontid, (void *)font); printf(" name: '%s'\n", font->name); - printf(" size: %u\n", font->size); + printf(" size: %f\n", font->size); printf(" dpi: %u\n", font->dpi); printf(" pos: %.6f %.6f %.6f\n", UNPACK3(font->pos)); printf(" aspect: (%d) %.6f %.6f %.6f\n", diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index d536a0b8486..c81d18ba7de 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -582,7 +582,7 @@ void blf_font_draw_buffer(FontBLF *font, /** \} */ /* -------------------------------------------------------------------- */ -/** \name Text Evaluation: Width to Sting Length +/** \name Text Evaluation: Width to String Length * * Use to implement exported functions: * - #BLF_width_to_strlen @@ -1350,19 +1350,24 @@ void blf_font_free(FontBLF *font) /** \name Font Configure * \{ */ -void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi) +void blf_font_size(FontBLF *font, float size, unsigned int dpi) { blf_glyph_cache_acquire(font); + /* FreeType uses fixed-point integers in 64ths. */ + FT_F26Dot6 ft_size = lroundf(size * 64.0f); + /* Adjust our size to be on even 64ths. */ + size = (float)ft_size / 64.0f; + GlyphCacheBLF *gc = blf_glyph_cache_find(font, size, dpi); if (gc && (font->size == size && font->dpi == dpi)) { /* Optimization: do not call FT_Set_Char_Size if size did not change. */ } else { - const FT_Error err = FT_Set_Char_Size(font->face, 0, ((FT_F26Dot6)(size)) * 64, dpi, dpi); + const FT_Error err = FT_Set_Char_Size(font->face, 0, ft_size, dpi, dpi); if (err) { /* FIXME: here we can go through the fixed size and choice a close one */ - printf("The current font don't support the size, %u and dpi, %u\n", size, dpi); + printf("The current font don't support the size, %f and dpi, %u\n", size, dpi); } else { font->size = size; diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index a9d00151e99..5f14ef433e9 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -76,7 +76,7 @@ static FT_Fixed to_16dot16(double val) /** * Find a glyph cache that matches a size, DPI & styles. */ -GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, unsigned int size, unsigned int dpi) +GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, float size, unsigned int dpi) { GlyphCacheBLF *gc = (GlyphCacheBLF *)font->cache.first; while (gc) { diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h index a715d5df692..cec20995dc6 100644 --- a/source/blender/blenfont/intern/blf_internal.h +++ b/source/blender/blenfont/intern/blf_internal.h @@ -52,7 +52,7 @@ struct FontBLF *blf_font_new(const char *name, const char *filename); struct FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, int mem_size); void blf_font_attach_from_mem(struct FontBLF *font, const unsigned char *mem, int mem_size); -void blf_font_size(struct FontBLF *font, unsigned int size, unsigned int dpi); +void blf_font_size(struct FontBLF *font, float size, unsigned int dpi); void blf_font_draw(struct FontBLF *font, const char *str, size_t str_len, @@ -130,9 +130,7 @@ int blf_font_count_missing_chars(struct FontBLF *font, void blf_font_free(struct FontBLF *font); -struct GlyphCacheBLF *blf_glyph_cache_find(struct FontBLF *font, - unsigned int size, - unsigned int dpi); +struct GlyphCacheBLF *blf_glyph_cache_find(struct FontBLF *font, float size, unsigned int dpi); struct GlyphCacheBLF *blf_glyph_cache_new(struct FontBLF *font); struct GlyphCacheBLF *blf_glyph_cache_acquire(struct FontBLF *font); void blf_glyph_cache_release(struct FontBLF *font); diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index aae666fa182..46156edbb1f 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -65,7 +65,7 @@ typedef struct GlyphCacheBLF { struct GlyphCacheBLF *prev; /* font size. */ - unsigned int size; + float size; /* and dpi. */ unsigned int dpi; @@ -205,7 +205,7 @@ typedef struct FontBLF { unsigned int dpi; /* font size. */ - unsigned int size; + float size; /* Column width when printing monospaced. */ int fixed_width; diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c index 12a83f7634e..bbdb26a61b6 100644 --- a/source/blender/blenfont/intern/blf_thumbs.c +++ b/source/blender/blenfont/intern/blf_thumbs.c @@ -95,7 +95,7 @@ void BLF_thumb_preview(const char *filename, const size_t draw_str_i18n_len = strlen(draw_str_i18n); int draw_str_i18n_nbr = 0; - blf_font_size(font, (unsigned int)MAX2(font_size_min, font_size_curr), dpi); + blf_font_size(font, (float)MAX2(font_size_min, font_size_curr), dpi); gc = blf_glyph_cache_find(font, font->size, font->dpi); /* There will be no matching glyph cache if blf_font_size() failed to set font size. */ if (!gc) { diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index 9f69c5e3976..763e540fdd9 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -125,6 +125,17 @@ struct bActionGroup *BKE_action_group_find_name(struct bAction *act, const char /* Clear all 'temp' flags on all groups */ void action_groups_clear_tempflags(struct bAction *act); +/** + * Return whether the action has one unique point in time keyed. + * + * This is mostly for the pose library, which will have different behavior depending on whether an + * Action corresponds to a "pose" (one keyframe) or "animation snippet" (multiple keyframes). + * + * \return `false` when there is no keyframe at all or keys on different points in time, `true` + * when exactly one point in time is keyed. + */ +bool BKE_action_has_single_frame(const struct bAction *act); + /* Pose API ----------------- */ void BKE_pose_channel_free(struct bPoseChannel *pchan); diff --git a/source/blender/blenkernel/BKE_asset_catalog.hh b/source/blender/blenkernel/BKE_asset_catalog.hh index 766a3f34a66..d071f782bd6 100644 --- a/source/blender/blenkernel/BKE_asset_catalog.hh +++ b/source/blender/blenkernel/BKE_asset_catalog.hh @@ -98,6 +98,15 @@ class AssetCatalogService { bool write_to_disk(const CatalogFilePath &blend_file_path); /** + * Ensure that the next call to #on_blend_save_post() will choose a new location for the CDF + * suitable for the location of the blend file (regardless of where the current catalogs come + * from), and that catalogs will be merged with already-existing ones in that location. + * + * Use this for a "Save as..." that has to write the catalogs to the new blend file location, + * instead of updating the previously read CDF. */ + void prepare_to_merge_on_write(); + + /** * Merge on-disk changes into the in-memory asset catalogs. * This should be called before writing the asset catalogs to disk. * @@ -238,6 +247,11 @@ class AssetCatalogService { */ void create_missing_catalogs(); + /** + * For every catalog, mark it as "dirty". + */ + void tag_all_catalogs_as_unsaved_changes(); + /* For access by subclasses, as those will not be marked as friend by #AssetCatalogCollection. */ AssetCatalogDefinitionFile *get_catalog_definition_file(); OwningAssetCatalogMap &get_catalogs(); @@ -429,7 +443,9 @@ class AssetCatalog { * Simple, human-readable name for the asset catalog. This is stored on assets alongside the * catalog ID; the catalog ID is a UUID that is not human-readable, * so to avoid complete data-loss when the catalog definition file gets lost, - * we also store a human-readable simple name for the catalog. */ + * we also store a human-readable simple name for the catalog. + * + * It should fit in sizeof(AssetMetaData::catalog_simple_name) bytes. */ std::string simple_name; struct Flags { diff --git a/source/blender/blenkernel/BKE_attribute.h b/source/blender/blenkernel/BKE_attribute.h index 7476474258b..2c83bef7517 100644 --- a/source/blender/blenkernel/BKE_attribute.h +++ b/source/blender/blenkernel/BKE_attribute.h @@ -43,12 +43,13 @@ struct ReportList; * Arrays may be initialized from this (e.g. #DATASET_layout_hierarchy). */ typedef enum AttributeDomain { - ATTR_DOMAIN_AUTO = -1, /* Use for nodes to choose automatically based on other data. */ - ATTR_DOMAIN_POINT = 0, /* Mesh, Hair or PointCloud Point */ - ATTR_DOMAIN_EDGE = 1, /* Mesh Edge */ - ATTR_DOMAIN_FACE = 2, /* Mesh Face */ - ATTR_DOMAIN_CORNER = 3, /* Mesh Corner */ - ATTR_DOMAIN_CURVE = 4, /* Hair Curve */ + ATTR_DOMAIN_AUTO = -1, /* Use for nodes to choose automatically based on other data. */ + ATTR_DOMAIN_POINT = 0, /* Mesh, Hair or PointCloud Point */ + ATTR_DOMAIN_EDGE = 1, /* Mesh Edge */ + ATTR_DOMAIN_FACE = 2, /* Mesh Face */ + ATTR_DOMAIN_CORNER = 3, /* Mesh Corner */ + ATTR_DOMAIN_CURVE = 4, /* Hair Curve */ + ATTR_DOMAIN_INSTANCE = 5, /* Instance */ ATTR_DOMAIN_NUM } AttributeDomain; diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh index 6a87375e5e2..47f62b52a0f 100644 --- a/source/blender/blenkernel/BKE_attribute_access.hh +++ b/source/blender/blenkernel/BKE_attribute_access.hh @@ -115,10 +115,10 @@ struct AttributeInitDefault : public AttributeInit { * Note that this can be used to fill the new attribute with the default */ struct AttributeInitVArray : public AttributeInit { - const blender::fn::GVArray *varray; + blender::fn::GVArray varray; - AttributeInitVArray(const blender::fn::GVArray *varray) - : AttributeInit(Type::VArray), varray(varray) + AttributeInitVArray(blender::fn::GVArray varray) + : AttributeInit(Type::VArray), varray(std::move(varray)) { } }; @@ -150,9 +150,7 @@ namespace blender::bke { using fn::CPPType; using fn::GVArray; -using fn::GVArrayPtr; using fn::GVMutableArray; -using fn::GVMutableArrayPtr; const CPPType *custom_data_type_to_cpp_type(const CustomDataType type); CustomDataType cpp_type_to_custom_data_type(const CPPType &type); @@ -164,14 +162,14 @@ AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains) */ struct ReadAttributeLookup { /* The virtual array that is used to read from this attribute. */ - GVArrayPtr varray; + GVArray varray; /* Domain the attribute lives on in the geometry. */ AttributeDomain domain; /* Convenience function to check if the attribute has been found. */ operator bool() const { - return this->varray.get() != nullptr; + return this->varray; } }; @@ -180,7 +178,7 @@ struct ReadAttributeLookup { */ struct WriteAttributeLookup { /* The virtual array that is used to read from and write to the attribute. */ - GVMutableArrayPtr varray; + GVMutableArray varray; /* Domain the attributes lives on in the geometry. */ AttributeDomain domain; /* Call this after changing the attribute to invalidate caches that depend on this attribute. */ @@ -189,7 +187,7 @@ struct WriteAttributeLookup { /* Convenience function to check if the attribute has been found. */ operator bool() const { - return this->varray.get() != nullptr; + return this->varray; } }; @@ -209,7 +207,7 @@ class OutputAttribute { using SaveFn = std::function<void(OutputAttribute &)>; private: - GVMutableArrayPtr varray_; + GVMutableArray varray_; AttributeDomain domain_ = ATTR_DOMAIN_AUTO; SaveFn save_; std::unique_ptr<fn::GVMutableArray_GSpan> optional_span_varray_; @@ -219,7 +217,7 @@ class OutputAttribute { public: OutputAttribute(); OutputAttribute(OutputAttribute &&other); - OutputAttribute(GVMutableArrayPtr varray, + OutputAttribute(GVMutableArray varray, AttributeDomain domain, SaveFn save, const bool ignore_old_values); @@ -229,7 +227,7 @@ class OutputAttribute { operator bool() const; GVMutableArray &operator*(); - GVMutableArray *operator->(); + fn::GVMutableArray *operator->(); GVMutableArray &varray(); AttributeDomain domain() const; const CPPType &cpp_type() const; @@ -247,16 +245,14 @@ class OutputAttribute { template<typename T> class OutputAttribute_Typed { private: OutputAttribute attribute_; - std::unique_ptr<fn::GVMutableArray_Typed<T>> optional_varray_; - VMutableArray<T> *varray_ = nullptr; + VMutableArray<T> varray_; public: OutputAttribute_Typed(); OutputAttribute_Typed(OutputAttribute attribute) : attribute_(std::move(attribute)) { if (attribute_) { - optional_varray_ = std::make_unique<fn::GVMutableArray_Typed<T>>(attribute_.varray()); - varray_ = &**optional_varray_; + varray_ = attribute_.varray().template typed<T>(); } } @@ -275,22 +271,22 @@ template<typename T> class OutputAttribute_Typed { operator bool() const { - return varray_ != nullptr; + return varray_; } VMutableArray<T> &operator*() { - return *varray_; + return varray_; } VMutableArray<T> *operator->() { - return varray_; + return &varray_; } VMutableArray<T> &varray() { - return *varray_; + return varray_; } AttributeDomain domain() const @@ -351,18 +347,17 @@ class CustomDataAttributes { std::optional<blender::fn::GSpan> get_for_read(const AttributeIDRef &attribute_id) const; - blender::fn::GVArrayPtr get_for_read(const AttributeIDRef &attribute_id, - const CustomDataType data_type, - const void *default_value) const; + blender::fn::GVArray get_for_read(const AttributeIDRef &attribute_id, + const CustomDataType data_type, + const void *default_value) const; template<typename T> - blender::fn::GVArray_Typed<T> get_for_read(const AttributeIDRef &attribute_id, - const T &default_value) const + blender::VArray<T> get_for_read(const AttributeIDRef &attribute_id, const T &default_value) const { const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>(); const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type); - GVArrayPtr varray = this->get_for_read(attribute_id, type, &default_value); - return blender::fn::GVArray_Typed<T>(std::move(varray)); + GVArray varray = this->get_for_read(attribute_id, type, &default_value); + return varray.typed<T>(); } std::optional<blender::fn::GMutableSpan> get_for_write(const AttributeIDRef &attribute_id); @@ -465,7 +460,7 @@ inline bool AttributeIDRef::should_be_kept() const inline OutputAttribute::OutputAttribute() = default; inline OutputAttribute::OutputAttribute(OutputAttribute &&other) = default; -inline OutputAttribute::OutputAttribute(GVMutableArrayPtr varray, +inline OutputAttribute::OutputAttribute(GVMutableArray varray, AttributeDomain domain, SaveFn save, const bool ignore_old_values) @@ -478,22 +473,22 @@ inline OutputAttribute::OutputAttribute(GVMutableArrayPtr varray, inline OutputAttribute::operator bool() const { - return varray_.get() != nullptr; + return varray_; } inline GVMutableArray &OutputAttribute::operator*() { - return *varray_; + return varray_; } -inline GVMutableArray *OutputAttribute::operator->() +inline fn::GVMutableArray *OutputAttribute::operator->() { - return varray_.get(); + return &varray_; } inline GVMutableArray &OutputAttribute::varray() { - return *varray_; + return varray_; } inline AttributeDomain OutputAttribute::domain() const @@ -503,7 +498,7 @@ inline AttributeDomain OutputAttribute::domain() const inline const CPPType &OutputAttribute::cpp_type() const { - return varray_->type(); + return varray_.type(); } inline CustomDataType OutputAttribute::custom_data_type() const diff --git a/source/blender/blenkernel/BKE_blender_copybuffer.h b/source/blender/blenkernel/BKE_blender_copybuffer.h index 1dd6d495276..4dd7145e66d 100644 --- a/source/blender/blenkernel/BKE_blender_copybuffer.h +++ b/source/blender/blenkernel/BKE_blender_copybuffer.h @@ -31,16 +31,18 @@ struct ReportList; struct bContext; /* copybuffer (wrapper for BKE_blendfile_write_partial) */ -void BKE_copybuffer_begin(struct Main *bmain_src); -void BKE_copybuffer_tag_ID(struct ID *id); -bool BKE_copybuffer_save(struct Main *bmain_src, const char *filename, struct ReportList *reports); +void BKE_copybuffer_copy_begin(struct Main *bmain_src); +void BKE_copybuffer_copy_tag_ID(struct ID *id); +bool BKE_copybuffer_copy_end(struct Main *bmain_src, + const char *filename, + struct ReportList *reports); bool BKE_copybuffer_read(struct Main *bmain_dst, const char *libname, struct ReportList *reports, const uint64_t id_types_mask); int BKE_copybuffer_paste(struct bContext *C, const char *libname, - const short flag, + const int flag, struct ReportList *reports, const uint64_t id_types_mask); diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 00934ef2002..966d6c95421 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -39,13 +39,13 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 1 +#define BLENDER_FILE_SUBVERSION 3 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and show a warning if the file * was written with too new a version. */ #define BLENDER_FILE_MIN_VERSION 300 -#define BLENDER_FILE_MIN_SUBVERSION 36 +#define BLENDER_FILE_MIN_SUBVERSION 42 /** User readable version string. */ const char *BKE_blender_version_string(void); diff --git a/source/blender/blenkernel/BKE_blendfile_link_append.h b/source/blender/blenkernel/BKE_blendfile_link_append.h new file mode 100644 index 00000000000..9e4a498f5e7 --- /dev/null +++ b/source/blender/blenkernel/BKE_blendfile_link_append.h @@ -0,0 +1,112 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#pragma once + +/** \file + * \ingroup bke + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct BlendHandle; +struct ID; +struct Library; +struct LibraryLink_Params; +struct Main; +struct ReportList; +struct Scene; +struct ViewLayer; +struct View3D; + +typedef struct BlendfileLinkAppendContext BlendfileLinkAppendContext; +typedef struct BlendfileLinkAppendContextItem BlendfileLinkAppendContextItem; + +BlendfileLinkAppendContext *BKE_blendfile_link_append_context_new( + struct LibraryLink_Params *params); +void BKE_blendfile_link_append_context_free(struct BlendfileLinkAppendContext *lapp_context); +void BKE_blendfile_link_append_context_flag_set(struct BlendfileLinkAppendContext *lapp_context, + const int flag, + const bool do_set); + +void BKE_blendfile_link_append_context_embedded_blendfile_set( + struct BlendfileLinkAppendContext *lapp_context, + const void *blendfile_mem, + int blendfile_memsize); +void BKE_blendfile_link_append_context_embedded_blendfile_clear( + struct BlendfileLinkAppendContext *lapp_context); + +void BKE_blendfile_link_append_context_library_add(struct BlendfileLinkAppendContext *lapp_context, + const char *libname, + struct BlendHandle *blo_handle); +struct BlendfileLinkAppendContextItem *BKE_blendfile_link_append_context_item_add( + struct BlendfileLinkAppendContext *lapp_context, + const char *idname, + const short idcode, + void *userdata); +void BKE_blendfile_link_append_context_item_library_index_enable( + struct BlendfileLinkAppendContext *lapp_context, + struct BlendfileLinkAppendContextItem *item, + const int library_index); +bool BKE_blendfile_link_append_context_is_empty(struct BlendfileLinkAppendContext *lapp_context); + +void *BKE_blendfile_link_append_context_item_userdata_get( + struct BlendfileLinkAppendContext *lapp_context, struct BlendfileLinkAppendContextItem *item); +struct ID *BKE_blendfile_link_append_context_item_newid_get( + struct BlendfileLinkAppendContext *lapp_context, struct BlendfileLinkAppendContextItem *item); +short BKE_blendfile_link_append_context_item_idcode_get( + struct BlendfileLinkAppendContext *lapp_context, struct BlendfileLinkAppendContextItem *item); + +typedef enum eBlendfileLinkAppendForeachItemFlag { + /** Loop over directly linked items (i.e. those explicitely defined by user code). */ + BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_DIRECT = 1 << 0, + /** Loop over indirectly linked items (i.e. those defined by internal code, as dependencies of + * direct ones). + * + * IMPORTANT: Those 'indirect' items currently may not cover **all** indrectly linked data. See + * comments in #foreach_libblock_link_append_callback. */ + BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_INDIRECT = 1 << 0, +} eBlendfileLinkAppendForeachItemFlag; +/** Callback called by #BKE_blendfile_link_append_context_item_foreach over each (or a subset of + * each) of the items in given #BlendfileLinkAppendContext. + * + * \param userdata: An opaque void pointer passed to the `callback_function`. + * + * \return `true` if iteration should continue, `false` otherwise. */ +typedef bool (*BKE_BlendfileLinkAppendContexteItemFunction)( + struct BlendfileLinkAppendContext *lapp_context, + struct BlendfileLinkAppendContextItem *item, + void *userdata); +void BKE_blendfile_link_append_context_item_foreach( + struct BlendfileLinkAppendContext *lapp_context, + BKE_BlendfileLinkAppendContexteItemFunction callback_function, + const eBlendfileLinkAppendForeachItemFlag flag, + void *userdata); + +void BKE_blendfile_append(struct BlendfileLinkAppendContext *lapp_context, + struct ReportList *reports); +void BKE_blendfile_link(struct BlendfileLinkAppendContext *lapp_context, + struct ReportList *reports); + +void BKE_blendfile_library_relocate(struct BlendfileLinkAppendContext *lapp_context, + struct ReportList *reports, + struct Library *library, + const bool do_reload); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index 452a08bc9c8..c5f1af4c755 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -78,7 +78,7 @@ void BKE_brush_randomize_texture_coords(struct UnifiedPaintSettings *ups, bool m /* brush curve */ void BKE_brush_curve_preset(struct Brush *b, enum eCurveMappingPreset preset); -float BKE_brush_curve_strength_clamped(struct Brush *br, float p, const float len); +float BKE_brush_curve_strength_clamped(const struct Brush *br, float p, const float len); float BKE_brush_curve_strength(const struct Brush *br, float p, const float len); /* sampling */ diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index 58a89d0207a..35e66908d54 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -119,10 +119,21 @@ class GeometryComponent { /* Get a read-only attribute for the domain based on the given attribute. This can be used to * interpolate from one domain to another. * Returns null if the interpolation is not implemented. */ - virtual std::unique_ptr<blender::fn::GVArray> attribute_try_adapt_domain( - std::unique_ptr<blender::fn::GVArray> varray, - const AttributeDomain from_domain, - const AttributeDomain to_domain) const; + blender::fn::GVArray attribute_try_adapt_domain(const blender::fn::GVArray &varray, + const AttributeDomain from_domain, + const AttributeDomain to_domain) const + { + return this->attribute_try_adapt_domain_impl(varray, from_domain, to_domain); + } + + template<typename T> + blender::VArray<T> attribute_try_adapt_domain(const blender::VArray<T> &varray, + const AttributeDomain from_domain, + const AttributeDomain to_domain) const + { + return this->attribute_try_adapt_domain_impl(varray, from_domain, to_domain) + .template typed<T>(); + } /* Returns true when the attribute has been deleted. */ bool attribute_try_delete(const blender::bke::AttributeIDRef &attribute_id); @@ -146,16 +157,15 @@ class GeometryComponent { /* Get a virtual array to read the data of an attribute on the given domain and data type. * Returns null when the attribute does not exist or cannot be converted to the requested domain * and data type. */ - std::unique_ptr<blender::fn::GVArray> attribute_try_get_for_read( - const blender::bke::AttributeIDRef &attribute_id, - const AttributeDomain domain, - const CustomDataType data_type) const; + blender::fn::GVArray attribute_try_get_for_read(const blender::bke::AttributeIDRef &attribute_id, + const AttributeDomain domain, + const CustomDataType data_type) const; /* Get a virtual array to read the data of an attribute on the given domain. The data type is * left unchanged. Returns null when the attribute does not exist or cannot be adapted to the * requested domain. */ - std::unique_ptr<blender::fn::GVArray> attribute_try_get_for_read( - const blender::bke::AttributeIDRef &attribute_id, const AttributeDomain domain) const; + blender::fn::GVArray attribute_try_get_for_read(const blender::bke::AttributeIDRef &attribute_id, + const AttributeDomain domain) const; /* Get a virtual array to read data of an attribute with the given data type. The domain is * left unchanged. Returns null when the attribute does not exist or cannot be converted to the @@ -165,25 +175,22 @@ class GeometryComponent { /* Get a virtual array to read the data of an attribute. If that is not possible, the returned * virtual array will contain a default value. This never returns null. */ - std::unique_ptr<blender::fn::GVArray> attribute_get_for_read( - const blender::bke::AttributeIDRef &attribute_id, - const AttributeDomain domain, - const CustomDataType data_type, - const void *default_value = nullptr) const; + blender::fn::GVArray attribute_get_for_read(const blender::bke::AttributeIDRef &attribute_id, + const AttributeDomain domain, + const CustomDataType data_type, + const void *default_value = nullptr) const; /* Should be used instead of the method above when the requested data type is known at compile * time for better type safety. */ template<typename T> - blender::fn::GVArray_Typed<T> attribute_get_for_read( - const blender::bke::AttributeIDRef &attribute_id, - const AttributeDomain domain, - const T &default_value) const + blender::VArray<T> attribute_get_for_read(const blender::bke::AttributeIDRef &attribute_id, + const AttributeDomain domain, + const T &default_value) const { const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>(); const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type); - std::unique_ptr varray = this->attribute_get_for_read( - attribute_id, domain, type, &default_value); - return blender::fn::GVArray_Typed<T>(std::move(varray)); + return this->attribute_get_for_read(attribute_id, domain, type, &default_value) + .template typed<T>(); } /** @@ -234,6 +241,11 @@ class GeometryComponent { private: virtual const blender::bke::ComponentAttributeProviders *get_attribute_providers() const; + + virtual blender::fn::GVArray attribute_try_adapt_domain_impl( + const blender::fn::GVArray &varray, + const AttributeDomain from_domain, + const AttributeDomain to_domain) const; }; template<typename T> @@ -391,10 +403,6 @@ class MeshComponent : public GeometryComponent { Mesh *get_for_write(); int attribute_domain_size(const AttributeDomain domain) const final; - std::unique_ptr<blender::fn::GVArray> attribute_try_adapt_domain( - std::unique_ptr<blender::fn::GVArray> varray, - const AttributeDomain from_domain, - const AttributeDomain to_domain) const final; bool is_empty() const final; @@ -405,6 +413,11 @@ class MeshComponent : public GeometryComponent { private: const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final; + + blender::fn::GVArray attribute_try_adapt_domain_impl( + const blender::fn::GVArray &varray, + const AttributeDomain from_domain, + const AttributeDomain to_domain) const final; }; /** A geometry component that stores a point cloud. */ @@ -469,10 +482,6 @@ class CurveComponent : public GeometryComponent { CurveEval *get_for_write(); int attribute_domain_size(const AttributeDomain domain) const final; - std::unique_ptr<blender::fn::GVArray> attribute_try_adapt_domain( - std::unique_ptr<blender::fn::GVArray> varray, - const AttributeDomain from_domain, - const AttributeDomain to_domain) const final; bool is_empty() const final; @@ -485,6 +494,11 @@ class CurveComponent : public GeometryComponent { private: const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final; + + blender::fn::GVArray attribute_try_adapt_domain_impl( + const blender::fn::GVArray &varray, + const AttributeDomain from_domain, + const AttributeDomain to_domain) const final; }; class InstanceReference { @@ -637,6 +651,8 @@ class InstancesComponent : public GeometryComponent { mutable std::mutex almost_unique_ids_mutex_; mutable blender::Array<int> almost_unique_ids_; + blender::bke::CustomDataAttributes attributes_; + public: InstancesComponent(); ~InstancesComponent() = default; @@ -671,6 +687,9 @@ class InstancesComponent : public GeometryComponent { blender::Span<int> almost_unique_ids() const; + blender::bke::CustomDataAttributes &attributes(); + const blender::bke::CustomDataAttributes &attributes() const; + int attribute_domain_size(const AttributeDomain domain) const final; void foreach_referenced_geometry( @@ -759,9 +778,9 @@ class AttributeFieldInput : public fn::FieldInput { return name_; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &scope) const override; + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &scope) const override; std::string socket_inspection_name() const override; @@ -776,9 +795,9 @@ class IDAttributeFieldInput : public fn::FieldInput { category_ = Category::Generated; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &scope) const override; + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &scope) const override; std::string socket_inspection_name() const override; @@ -815,9 +834,9 @@ class AnonymousAttributeFieldInput : public fn::FieldInput { return fn::Field<T>{field_input}; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &scope) const override; + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &scope) const override; std::string socket_inspection_name() const override; diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h index 261d313c4b7..d9cb8f44bb7 100644 --- a/source/blender/blenkernel/BKE_global.h +++ b/source/blender/blenkernel/BKE_global.h @@ -45,7 +45,6 @@ typedef struct Global { /** When set: `G_MAIN->name` contains valid relative base path. */ bool relbase_valid; - bool file_loaded; bool save_over; /** Strings of recent opened files. */ @@ -215,7 +214,7 @@ enum { /** * Set when transforming the cursor itself. * Used as a hint to draw the cursor (even when hidden). - * Otherwise it's not possible to see whats being transformed. + * Otherwise it's not possible to see what's being transformed. */ G_TRANSFORM_CURSOR = (1 << 5), }; diff --git a/source/blender/blenkernel/BKE_gpencil_geom.h b/source/blender/blenkernel/BKE_gpencil_geom.h index a9cd553a8fe..41b1bba10ba 100644 --- a/source/blender/blenkernel/BKE_gpencil_geom.h +++ b/source/blender/blenkernel/BKE_gpencil_geom.h @@ -128,8 +128,9 @@ struct bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(struct bGPdata *gpd, struct bGPDstroke *gps, struct bGPDstroke *next_stroke, int tag_flags, - bool select, - int limit); + const bool select, + const bool flat_cap, + const int limit); void BKE_gpencil_curve_delete_tagged_points(struct bGPdata *gpd, struct bGPDframe *gpf, struct bGPDstroke *gps, diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h index c8af1a91725..08b44959096 100644 --- a/source/blender/blenkernel/BKE_layer.h +++ b/source/blender/blenkernel/BKE_layer.h @@ -328,7 +328,7 @@ void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *iter); { \ Object *_instance; \ Base *_base; \ - for (_base = (view_layer)->object_bases.first; _base; _base = _base->next) { \ + for (_base = (Base *)(view_layer)->object_bases.first; _base; _base = _base->next) { \ _instance = _base->object; #define FOREACH_OBJECT_END \ diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h index b38125b791d..359fb72534a 100644 --- a/source/blender/blenkernel/BKE_lib_id.h +++ b/source/blender/blenkernel/BKE_lib_id.h @@ -123,6 +123,9 @@ enum { LIB_ID_COPY_CD_REFERENCE = 1 << 20, /** Do not copy id->override_library, used by ID datablock override routines. */ LIB_ID_COPY_NO_LIB_OVERRIDE = 1 << 21, + /** When copying local sub-data (like constraints or modifiers), do not set their "library + * override local data" flag. */ + LIB_ID_COPY_NO_LIB_OVERRIDE_LOCAL_DATA_FLAG = 1 << 22, /* *** XXX Hackish/not-so-nice specific behaviors needed for some corner cases. *** */ /* *** Ideally we should not have those, but we need them for now... *** */ @@ -134,8 +137,10 @@ enum { LIB_ID_COPY_SHAPEKEY = 1 << 26, /** EXCEPTION! Specific deep-copy of node trees used e.g. for rendering purposes. */ LIB_ID_COPY_NODETREE_LOCALIZE = 1 << 27, - /** EXCEPTION! Specific handling of RB objects regarding collections differs depending whether we - duplicate scene/collections, or objects. */ + /** + * EXCEPTION! Specific handling of RB objects regarding collections differs depending whether we + * duplicate scene/collections, or objects. + */ LIB_ID_COPY_RIGID_BODY_NO_COLLECTION_HANDLING = 1 << 28, /* *** Helper 'defines' gathering most common flag sets. *** */ diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index f44d35c62a3..be9b84ccd62 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -209,6 +209,7 @@ struct Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob_eval, struct ModifierData *md_eval, + const bool use_virtual_modifiers, const bool build_shapekey_layers); /* Copies a nomain-Mesh into an existing Mesh. */ diff --git a/source/blender/blenkernel/BKE_mesh_runtime.h b/source/blender/blenkernel/BKE_mesh_runtime.h index 3efbef94081..df111360bcd 100644 --- a/source/blender/blenkernel/BKE_mesh_runtime.h +++ b/source/blender/blenkernel/BKE_mesh_runtime.h @@ -41,7 +41,8 @@ struct Mesh; struct Object; struct Scene; -void BKE_mesh_runtime_reset(struct Mesh *mesh); +void BKE_mesh_runtime_init_data(struct Mesh *mesh); +void BKE_mesh_runtime_free_data(struct Mesh *mesh); void BKE_mesh_runtime_reset_on_copy(struct Mesh *mesh, const int flag); int BKE_mesh_runtime_looptri_len(const struct Mesh *mesh); void BKE_mesh_runtime_looptri_recalc(struct Mesh *mesh); diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h index 067dc694109..73c7494b8fa 100644 --- a/source/blender/blenkernel/BKE_movieclip.h +++ b/source/blender/blenkernel/BKE_movieclip.h @@ -95,6 +95,7 @@ void BKE_movieclip_build_proxy_frame_for_ibuf(struct MovieClip *clip, int *build_sizes, int build_count, bool undistorted); +bool BKE_movieclip_proxy_enabled(struct MovieClip *clip); float BKE_movieclip_remap_scene_to_clip_frame(const struct MovieClip *clip, float framenr); float BKE_movieclip_remap_clip_to_scene_frame(const struct MovieClip *clip, float framenr); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 645b4410623..5ed1b512fd5 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -121,12 +121,11 @@ class MFDataType; } // namespace fn } // namespace blender +using CPPTypeHandle = blender::fn::CPPType; using NodeMultiFunctionBuildFunction = void (*)(blender::nodes::NodeMultiFunctionBuilder &builder); using NodeGeometryExecFunction = void (*)(blender::nodes::GeoNodeExecParams params); using NodeDeclareFunction = void (*)(blender::nodes::NodeDeclarationBuilder &builder); -using SocketGetCPPTypeFunction = const blender::fn::CPPType *(*)(); using SocketGetCPPValueFunction = void (*)(const struct bNodeSocket &socket, void *r_value); -using SocketGetGeometryNodesCPPTypeFunction = const blender::fn::CPPType *(*)(); using SocketGetGeometryNodesCPPValueFunction = void (*)(const struct bNodeSocket &socket, void *r_value); @@ -138,6 +137,7 @@ typedef void *SocketGetCPPTypeFunction; typedef void *SocketGetGeometryNodesCPPTypeFunction; typedef void *SocketGetGeometryNodesCPPValueFunction; typedef void *SocketGetCPPValueFunction; +typedef struct CPPTypeHandle CPPTypeHandle; #endif /** @@ -197,11 +197,11 @@ typedef struct bNodeSocketType { void (*free_self)(struct bNodeSocketType *stype); /* Return the CPPType of this socket. */ - SocketGetCPPTypeFunction get_base_cpp_type; + const CPPTypeHandle *base_cpp_type; /* Get the value of this socket in a generic way. */ SocketGetCPPValueFunction get_base_cpp_value; /* Get geometry nodes cpp type. */ - SocketGetGeometryNodesCPPTypeFunction get_geometry_nodes_cpp_type; + const CPPTypeHandle *geometry_nodes_cpp_type; /* Get geometry nodes cpp value. */ SocketGetGeometryNodesCPPValueFunction get_geometry_nodes_cpp_value; } bNodeSocketType; @@ -318,8 +318,6 @@ typedef struct bNodeType { /* optional handling of link insertion */ void (*insert_link)(struct bNodeTree *ntree, struct bNode *node, struct bNodeLink *link); - /* Update the internal links list, for muting and disconnect operators. */ - void (*update_internal_links)(struct bNodeTree *, struct bNode *node); void (*free_self)(struct bNodeType *ntype); @@ -344,6 +342,9 @@ typedef struct bNodeType { /* Declaration to be used when it is not dynamic. */ NodeDeclarationHandle *fixed_declaration; + /** True when the node cannot be muted. */ + bool no_muting; + /* RNA integration */ ExtensionRNA rna_ext; } bNodeType; @@ -731,7 +732,9 @@ void nodeUpdateInternalLinks(struct bNodeTree *ntree, struct bNode *node); int nodeSocketIsHidden(const struct bNodeSocket *sock); void ntreeTagUsedSockets(struct bNodeTree *ntree); -void nodeSetSocketAvailability(struct bNodeSocket *sock, bool is_available); +void nodeSetSocketAvailability(struct bNodeTree *ntree, + struct bNodeSocket *sock, + bool is_available); int nodeSocketLinkLimit(const struct bNodeSocket *sock); @@ -889,8 +892,6 @@ void node_type_exec(struct bNodeType *ntype, NodeFreeExecFunction free_exec_fn, NodeExecFunction exec_fn); void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpu_fn); -void node_type_internal_links(struct bNodeType *ntype, - void (*update_internal_links)(struct bNodeTree *, struct bNode *)); /** \} */ diff --git a/source/blender/blenkernel/BKE_preferences.h b/source/blender/blenkernel/BKE_preferences.h index fd4d13f4125..e9cb024f117 100644 --- a/source/blender/blenkernel/BKE_preferences.h +++ b/source/blender/blenkernel/BKE_preferences.h @@ -42,6 +42,9 @@ void BKE_preferences_asset_library_name_set(struct UserDef *userdef, struct bUserAssetLibrary *library, const char *name) ATTR_NONNULL(); +void BKE_preferences_asset_library_path_set(struct bUserAssetLibrary *library, const char *path) + ATTR_NONNULL(); + struct bUserAssetLibrary *BKE_preferences_asset_library_find_from_index( const struct UserDef *userdef, int index) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; struct bUserAssetLibrary *BKE_preferences_asset_library_find_from_name( diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh index 8509b730709..67eaa7c12c9 100644 --- a/source/blender/blenkernel/BKE_spline.hh +++ b/source/blender/blenkernel/BKE_spline.hh @@ -187,14 +187,14 @@ class Spline { blender::MutableSpan<T> dst) const { this->sample_with_index_factors( - blender::fn::GVArray_For_VArray(src), index_factors, blender::fn::GMutableSpan(dst)); + blender::fn::GVArray(src), index_factors, blender::fn::GMutableSpan(dst)); } template<typename T> void sample_with_index_factors(blender::Span<T> src, blender::Span<float> index_factors, blender::MutableSpan<T> dst) const { - this->sample_with_index_factors(blender::VArray_For_Span(src), index_factors, dst); + this->sample_with_index_factors(blender::VArray<T>::ForSpan(src), index_factors, dst); } /** @@ -202,13 +202,11 @@ class Spline { * evaluated points. For poly splines, the lifetime of the returned virtual array must not * exceed the lifetime of the input data. */ - virtual blender::fn::GVArrayPtr interpolate_to_evaluated( - const blender::fn::GVArray &src) const = 0; - blender::fn::GVArrayPtr interpolate_to_evaluated(blender::fn::GSpan data) const; - template<typename T> - blender::fn::GVArray_Typed<T> interpolate_to_evaluated(blender::Span<T> data) const + virtual blender::fn::GVArray interpolate_to_evaluated(const blender::fn::GVArray &src) const = 0; + blender::fn::GVArray interpolate_to_evaluated(blender::fn::GSpan data) const; + template<typename T> blender::VArray<T> interpolate_to_evaluated(blender::Span<T> data) const { - return blender::fn::GVArray_Typed<T>(this->interpolate_to_evaluated(blender::fn::GSpan(data))); + return this->interpolate_to_evaluated(blender::fn::GSpan(data)).typed<T>(); } protected: @@ -306,11 +304,23 @@ class BezierSpline final : public Spline { blender::Span<HandleType> handle_types_left() const; blender::MutableSpan<HandleType> handle_types_left(); blender::Span<blender::float3> handle_positions_left() const; - blender::MutableSpan<blender::float3> handle_positions_left(); + /** + * Get writable access to the handle position. + * + * \param write_only: pass true for an uninitialized spline, this prevents accessing + * uninitialized memory while auto-generating handles. + */ + blender::MutableSpan<blender::float3> handle_positions_left(bool write_only = false); blender::Span<HandleType> handle_types_right() const; blender::MutableSpan<HandleType> handle_types_right(); blender::Span<blender::float3> handle_positions_right() const; - blender::MutableSpan<blender::float3> handle_positions_right(); + /** + * Get writable access to the handle position. + * + * \param write_only: pass true for an uninitialized spline, this prevents accessing + * uninitialized memory while auto-generating handles. + */ + blender::MutableSpan<blender::float3> handle_positions_right(bool write_only = false); void ensure_auto_handles() const; void translate(const blender::float3 &translation) override; @@ -338,7 +348,7 @@ class BezierSpline final : public Spline { }; InterpolationData interpolation_data_from_index_factor(const float index_factor) const; - virtual blender::fn::GVArrayPtr interpolate_to_evaluated( + virtual blender::fn::GVArray interpolate_to_evaluated( const blender::fn::GVArray &src) const override; void evaluate_segment(const int index, @@ -475,7 +485,7 @@ class NURBSpline final : public Spline { blender::Span<blender::float3> evaluated_positions() const final; - blender::fn::GVArrayPtr interpolate_to_evaluated(const blender::fn::GVArray &src) const final; + blender::fn::GVArray interpolate_to_evaluated(const blender::fn::GVArray &src) const final; protected: void correct_end_tangents() const final; @@ -526,7 +536,7 @@ class PolySpline final : public Spline { blender::Span<blender::float3> evaluated_positions() const final; - blender::fn::GVArrayPtr interpolate_to_evaluated(const blender::fn::GVArray &src) const final; + blender::fn::GVArray interpolate_to_evaluated(const blender::fn::GVArray &src) const final; protected: void correct_end_tangents() const final; @@ -570,6 +580,9 @@ struct CurveEval { blender::Array<int> evaluated_point_offsets() const; blender::Array<float> accumulated_spline_lengths() const; + float total_length() const; + int total_control_point_size() const; + void mark_cache_invalid(); void assert_valid_point_attributes() const; diff --git a/source/blender/blenkernel/BKE_volume_to_mesh.hh b/source/blender/blenkernel/BKE_volume_to_mesh.hh index 9532da8c23c..dd8ae7ea554 100644 --- a/source/blender/blenkernel/BKE_volume_to_mesh.hh +++ b/source/blender/blenkernel/BKE_volume_to_mesh.hh @@ -14,6 +14,8 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#pragma once + #include "BLI_span.hh" #include "DNA_modifier_types.h" diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index b2418d0539c..a08f1b81dbe 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -100,6 +100,7 @@ set(SRC intern/blender_undo.c intern/blender_user_menu.c intern/blendfile.c + intern/blendfile_link_append.c intern/boids.c intern/bpath.c intern/brush.c @@ -326,6 +327,7 @@ set(SRC BKE_blender_user_menu.h BKE_blender_version.h BKE_blendfile.h + BKE_blendfile_link_append.h BKE_boids.h BKE_bpath.h BKE_brush.h diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index cae72ddf68c..2cc1cba99cd 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -51,6 +51,7 @@ #include "BKE_anim_visualization.h" #include "BKE_animsys.h" #include "BKE_armature.h" +#include "BKE_asset.h" #include "BKE_constraint.h" #include "BKE_deform.h" #include "BKE_fcurve.h" @@ -286,6 +287,30 @@ static void action_blend_read_expand(BlendExpander *expander, ID *id) } } +static IDProperty *action_asset_type_property(const bAction *action) +{ + const bool is_single_frame = !BKE_action_has_single_frame(action); + + IDPropertyTemplate idprop = {0}; + idprop.i = is_single_frame; + + IDProperty *property = IDP_New(IDP_INT, &idprop, "is_single_frame"); + return property; +} + +static void action_asset_pre_save(void *asset_ptr, struct AssetMetaData *asset_data) +{ + bAction *action = (bAction *)asset_ptr; + BLI_assert(GS(action->id.name) == ID_AC); + + IDProperty *action_type = action_asset_type_property(action); + BKE_asset_metadata_idprop_ensure(asset_data, action_type); +} + +AssetTypeInfo AssetType_AC = { + /* pre_save_fn */ action_asset_pre_save, +}; + IDTypeInfo IDType_ID_AC = { .id_code = ID_AC, .id_filter = FILTER_ID_AC, @@ -312,6 +337,8 @@ 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 ************** */ @@ -1418,6 +1445,47 @@ bool action_has_motion(const bAction *act) return false; } +bool BKE_action_has_single_frame(const struct bAction *act) +{ + if (act == NULL || BLI_listbase_is_empty(&act->curves)) { + return false; + } + + bool found_key = false; + float found_key_frame = 0.0f; + + LISTBASE_FOREACH (FCurve *, fcu, &act->curves) { + switch (fcu->totvert) { + case 0: + /* No keys, so impossible to come to a conclusion on this curve alone. */ + continue; + case 1: + /* Single key, which is the complex case, so handle below. */ + break; + default: + /* Multiple keys, so there is animation. */ + return false; + } + + const float this_key_frame = fcu->bezt != NULL ? fcu->bezt[0].vec[1][0] : fcu->fpt[0].vec[0]; + if (!found_key) { + found_key = true; + found_key_frame = this_key_frame; + continue; + } + + /* The graph editor rounds to 1/1000th of a frame, so it's not necessary to be really precise + * with these comparisons. */ + if (!compare_ff(found_key_frame, this_key_frame, 0.001f)) { + /* This key differs from the already-found key, so this Action represents animation. */ + return false; + } + } + + /* There is only a single frame if we found at least one key. */ + return found_key; +} + /* Calculate the extents of given action */ void calc_action_range(const bAction *act, float *start, float *end, short incl_modifiers) { diff --git a/source/blender/blenkernel/intern/action_test.cc b/source/blender/blenkernel/intern/action_test.cc index c02eca966ad..8423bc923f3 100644 --- a/source/blender/blenkernel/intern/action_test.cc +++ b/source/blender/blenkernel/intern/action_test.cc @@ -24,6 +24,8 @@ #include "BLI_listbase.h" +#include "MEM_guardedalloc.h" + #include "testing/testing.h" namespace blender::bke::tests { @@ -141,4 +143,97 @@ TEST(action_groups, ReconstructGroupsWithReordering) EXPECT_EQ(groupDcurve2.next, nullptr); } +namespace { + +/* Allocate fcu->bezt, and also return a unique_ptr to it for easily freeing the memory. */ +std::unique_ptr<BezTriple[]> allocate_keyframes(FCurve *fcu, const size_t num_keyframes) +{ + auto bezt_uptr = std::make_unique<BezTriple[]>(num_keyframes); + fcu->bezt = bezt_uptr.get(); + return bezt_uptr; +} + +/* Append keyframe, assumes that fcu->bezt is allocated and has enough space. */ +void add_keyframe(FCurve *fcu, float x, float y) +{ + /* The insert_keyframe functions are in the editors, so we cannot link to those here. */ + BezTriple the_keyframe; + memset(&the_keyframe, 0, sizeof(the_keyframe)); + + /* Copied from insert_vert_fcurve() in keyframing.c. */ + the_keyframe.vec[0][0] = x - 1.0f; + the_keyframe.vec[0][1] = y; + the_keyframe.vec[1][0] = x; + the_keyframe.vec[1][1] = y; + the_keyframe.vec[2][0] = x + 1.0f; + the_keyframe.vec[2][1] = y; + + memcpy(&fcu->bezt[fcu->totvert], &the_keyframe, sizeof(the_keyframe)); + fcu->totvert++; +} + +} // namespace + +TEST(action_assets, BKE_action_has_single_frame) +{ + /* NULL action. */ + EXPECT_FALSE(BKE_action_has_single_frame(nullptr)) << "NULL Action cannot have a single frame."; + + /* No FCurves. */ + { + const bAction empty = {{nullptr}}; + EXPECT_FALSE(BKE_action_has_single_frame(&empty)) + << "Action without FCurves cannot have a single frame."; + } + + /* One curve with one key. */ + { + FCurve fcu = {nullptr}; + std::unique_ptr<BezTriple[]> bezt = allocate_keyframes(&fcu, 1); + add_keyframe(&fcu, 1.0f, 2.0f); + + bAction action = {{nullptr}}; + BLI_addtail(&action.curves, &fcu); + + EXPECT_TRUE(BKE_action_has_single_frame(&action)) + << "Action with one FCurve and one key should have single frame."; + } + + /* Two curves with one key each. */ + { + FCurve fcu1 = {nullptr}; + FCurve fcu2 = {nullptr}; + std::unique_ptr<BezTriple[]> bezt1 = allocate_keyframes(&fcu1, 1); + std::unique_ptr<BezTriple[]> bezt2 = allocate_keyframes(&fcu2, 1); + add_keyframe(&fcu1, 1.0f, 327.0f); + add_keyframe(&fcu2, 1.0f, 47.0f); /* Same X-coordinate as the other one. */ + + bAction action = {{nullptr}}; + BLI_addtail(&action.curves, &fcu1); + BLI_addtail(&action.curves, &fcu2); + + EXPECT_TRUE(BKE_action_has_single_frame(&action)) + << "Two FCurves with keys on the same frame should have single frame."; + + /* Modify the 2nd curve so it's keyed on a different frame. */ + fcu2.bezt[0].vec[1][0] = 2.0f; + EXPECT_FALSE(BKE_action_has_single_frame(&action)) + << "Two FCurves with keys on different frames should have animation."; + } + + /* One curve with two keys. */ + { + FCurve fcu = {nullptr}; + std::unique_ptr<BezTriple[]> bezt = allocate_keyframes(&fcu, 2); + add_keyframe(&fcu, 1.0f, 2.0f); + add_keyframe(&fcu, 2.0f, 2.5f); + + bAction action = {{nullptr}}; + BLI_addtail(&action.curves, &fcu); + + EXPECT_FALSE(BKE_action_has_single_frame(&action)) + << "Action with one FCurve and two keys must have animation."; + } +} + } // namespace blender::bke::tests diff --git a/source/blender/blenkernel/intern/asset_catalog.cc b/source/blender/blenkernel/intern/asset_catalog.cc index 03043f3b784..9ef66d23aea 100644 --- a/source/blender/blenkernel/intern/asset_catalog.cc +++ b/source/blender/blenkernel/intern/asset_catalog.cc @@ -98,6 +98,14 @@ bool AssetCatalogService::has_unsaved_changes() const return catalog_collection_->has_unsaved_changes_; } +void AssetCatalogService::tag_all_catalogs_as_unsaved_changes() +{ + for (auto &catalog : catalog_collection_->catalogs_.values()) { + catalog->flags.has_unsaved_changes = true; + } + catalog_collection_->has_unsaved_changes_ = true; +} + bool AssetCatalogService::is_empty() const { BLI_assert(catalog_collection_); @@ -486,6 +494,24 @@ bool AssetCatalogService::write_to_disk_ex(const CatalogFilePath &blend_file_pat return catalog_collection_->catalog_definition_file_->write_to_disk(); } +void AssetCatalogService::prepare_to_merge_on_write() +{ + /* TODO(Sybren): expand to support multiple CDFs. */ + + if (!catalog_collection_->catalog_definition_file_) { + /* There is no CDF connected, so it's a no-op. */ + return; + } + + /* Remove any association with the CDF, so that a new location will be chosen + * when the blend file is saved. */ + catalog_collection_->catalog_definition_file_.reset(); + + /* Mark all in-memory catalogs as "dirty", to force them to be kept around on + * the next "load-merge-write" cycle. */ + tag_all_catalogs_as_unsaved_changes(); +} + CatalogFilePath AssetCatalogService::find_suitable_cdf_path_for_writing( const CatalogFilePath &blend_file_path) { 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/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_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 dc3c2a8e55e..a682489b7cd 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -2475,7 +2475,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/constraint.c b/source/blender/blenkernel/intern/constraint.c index b2b03d28483..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); @@ -6022,7 +6022,6 @@ bConstraint *BKE_constraint_duplicate_ex(bConstraint *src, const int flag, const bConstraint *dst = MEM_dupallocN(src); constraint_copy_data_ex(dst, src, flag, do_extern); dst->next = dst->prev = NULL; - dst->flag |= CONSTRAINT_OVERRIDE_LIBRARY_LOCAL; return dst; } @@ -6057,7 +6056,9 @@ void BKE_constraints_copy_ex(ListBase *dst, const ListBase *src, const int flag, for (con = dst->first, srccon = src->first; con && srccon; srccon = srccon->next, con = con->next) { constraint_copy_data_ex(con, srccon, flag, do_extern); - con->flag |= CONSTRAINT_OVERRIDE_LIBRARY_LOCAL; + if ((flag & LIB_ID_COPY_NO_LIB_OVERRIDE_LOCAL_DATA_FLAG) == 0) { + con->flag |= CONSTRAINT_OVERRIDE_LIBRARY_LOCAL; + } } } diff --git a/source/blender/blenkernel/intern/curve_eval.cc b/source/blender/blenkernel/intern/curve_eval.cc index bb745d5b20d..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 @@ -225,8 +243,8 @@ static SplinePtr spline_from_dna_bezier(const Nurb &nurb) Span<const BezTriple> src_points{nurb.bezt, nurb.pntsu}; spline->resize(src_points.size()); MutableSpan<float3> positions = spline->positions(); - MutableSpan<float3> handle_positions_left = spline->handle_positions_left(); - MutableSpan<float3> handle_positions_right = spline->handle_positions_right(); + MutableSpan<float3> handle_positions_left = spline->handle_positions_left(true); + MutableSpan<float3> handle_positions_right = spline->handle_positions_right(true); MutableSpan<BezierSpline::HandleType> handle_types_left = spline->handle_types_left(); MutableSpan<BezierSpline::HandleType> handle_types_right = spline->handle_types_right(); MutableSpan<float> radii = spline->radii(); 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_driver.c b/source/blender/blenkernel/intern/fcurve_driver.c index 6e03f362160..3ac64dbf84b 100644 --- a/source/blender/blenkernel/intern/fcurve_driver.c +++ b/source/blender/blenkernel/intern/fcurve_driver.c @@ -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 d3c3fcc1e67..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()); } @@ -563,7 +555,8 @@ static void point_attribute_materialize(Span<Span<T>> data, else { int spline_index = 0; for (const int dst_index : mask) { - while (offsets[spline_index] < dst_index) { + /* Skip splines that don't have any control points in the mask. */ + while (dst_index >= offsets[spline_index + 1]) { spline_index++; } @@ -607,7 +600,8 @@ static void point_attribute_materialize_to_uninitialized(Span<Span<T>> data, else { int spline_index = 0; for (const int dst_index : mask) { - while (offsets[spline_index] < dst_index) { + /* Skip splines that don't have any control points in the mask. */ + while (dst_index >= offsets[spline_index + 1]) { spline_index++; } @@ -623,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: @@ -634,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 {}; @@ -691,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); @@ -723,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); } @@ -754,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]; @@ -786,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)); } /** @@ -820,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]; @@ -852,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]; @@ -885,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_; @@ -907,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) @@ -929,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_); } @@ -976,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_; @@ -998,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]; @@ -1026,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]; @@ -1049,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); @@ -1097,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) { @@ -1110,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(); @@ -1119,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 @@ -1144,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)}; } @@ -1156,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 @@ -1248,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}; } @@ -1273,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) { @@ -1285,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 @@ -1303,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 @@ -1387,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 = {}; @@ -1399,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; } @@ -1440,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 = {}; @@ -1452,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 c3e39c0b2cb..86a52b420b6 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 @@ -1184,7 +1177,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(); @@ -1197,8 +1190,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); @@ -1207,7 +1199,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_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_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/icons.cc b/source/blender/blenkernel/intern/icons.cc index ffc39028400..c2250dd04f9 100644 --- a/source/blender/blenkernel/intern/icons.cc +++ b/source/blender/blenkernel/intern/icons.cc @@ -360,31 +360,23 @@ void BKE_previewimg_id_copy(ID *new_id, const ID *old_id) PreviewImage **BKE_previewimg_id_get_p(const ID *id) { switch (GS(id->name)) { - case ID_OB: { - Object *ob = (Object *)id; - /* Currently, only object types with real geometry can be rendered as preview. */ - if (!OB_TYPE_IS_GEOMETRY(ob->type)) { - return nullptr; - } - return &ob->preview; - } - #define ID_PRV_CASE(id_code, id_struct) \ case id_code: { \ return &((id_struct *)id)->preview; \ } \ ((void)0) - ID_PRV_CASE(ID_MA, Material); - ID_PRV_CASE(ID_TE, Tex); - ID_PRV_CASE(ID_WO, World); - ID_PRV_CASE(ID_LA, Light); - ID_PRV_CASE(ID_IM, Image); - ID_PRV_CASE(ID_BR, Brush); - ID_PRV_CASE(ID_GR, Collection); - ID_PRV_CASE(ID_SCE, Scene); - ID_PRV_CASE(ID_SCR, bScreen); - ID_PRV_CASE(ID_AC, bAction); - ID_PRV_CASE(ID_NT, bNodeTree); + ID_PRV_CASE(ID_OB, Object); + ID_PRV_CASE(ID_MA, Material); + ID_PRV_CASE(ID_TE, Tex); + ID_PRV_CASE(ID_WO, World); + ID_PRV_CASE(ID_LA, Light); + ID_PRV_CASE(ID_IM, Image); + ID_PRV_CASE(ID_BR, Brush); + ID_PRV_CASE(ID_GR, Collection); + 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 8472ad5d8aa..1ef5659855b 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -1323,6 +1323,9 @@ void BKE_image_print_memlist(Main *bmain) static bool imagecache_check_dirty(ImBuf *ibuf, void *UNUSED(userkey), void *UNUSED(userdata)) { + if (ibuf == NULL) { + return false; + } return (ibuf->userflags & IB_BITMAPDIRTY) == 0; } @@ -1366,6 +1369,9 @@ void BKE_image_free_all_textures(Main *bmain) static bool imagecache_check_free_anim(ImBuf *ibuf, void *UNUSED(userkey), void *userdata) { + if (ibuf == NULL) { + return true; + } int except_frame = *(int *)userdata; return (ibuf->userflags & IB_BITMAPDIRTY) == 0 && (ibuf->index != IMA_NO_INDEX) && (except_frame != IMA_INDEX_ENTRY(ibuf->index)); @@ -4227,13 +4233,16 @@ static int image_num_files(Image *ima) return BLI_listbase_count(&ima->views); } -static ImBuf *load_sequence_single(Image *ima, ImageUser *iuser, int frame, const int view_id) +static ImBuf *load_sequence_single( + Image *ima, ImageUser *iuser, int frame, const int view_id, bool *r_cache_ibuf) { struct ImBuf *ibuf; char name[FILE_MAX]; int flag; ImageUser iuser_t = {0}; + *r_cache_ibuf = true; + ima->lastframe = frame; if (iuser) { @@ -4273,6 +4282,9 @@ static ImBuf *load_sequence_single(Image *ima, ImageUser *iuser, int frame, cons ima->type = IMA_TYPE_MULTILAYER; IMB_freeImBuf(ibuf); ibuf = NULL; + /* NULL ibuf in the cache means the image failed to load. However for multilayer we load + * pixels into RenderResult instead and intentionally leave ibuf NULL. */ + *r_cache_ibuf = false; } } else { @@ -4293,17 +4305,21 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int entry, const int totfiles = image_num_files(ima); if (!is_multiview) { - ibuf = load_sequence_single(ima, iuser, frame, 0); - image_assign_ibuf(ima, ibuf, 0, entry); + bool put_in_cache; + ibuf = load_sequence_single(ima, iuser, frame, 0, &put_in_cache); + if (put_in_cache) { + image_assign_ibuf(ima, ibuf, 0, entry); + } } else { const int totviews = BLI_listbase_count(&ima->views); struct ImBuf **ibuf_arr; ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * totviews, "Image Views Imbufs"); + bool *cache_ibuf_arr = MEM_mallocN(sizeof(bool) * totviews, "Image View Put In Cache"); for (int i = 0; i < totfiles; i++) { - ibuf_arr[i] = load_sequence_single(ima, iuser, frame, i); + ibuf_arr[i] = load_sequence_single(ima, iuser, frame, i, cache_ibuf_arr + i); } if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D) { @@ -4314,7 +4330,9 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int entry, ibuf = ibuf_arr[(iuser ? iuser->multi_index : 0)]; for (int i = 0; i < totviews; i++) { - image_assign_ibuf(ima, ibuf_arr[i], i, entry); + if (cache_ibuf_arr[i]) { + image_assign_ibuf(ima, ibuf_arr[i], i, entry); + } } /* "remove" the others (decrease their refcount) */ @@ -4326,6 +4344,7 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int entry, /* cleanup */ MEM_freeN(ibuf_arr); + MEM_freeN(cache_ibuf_arr); } return ibuf; @@ -4487,13 +4506,19 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame) return ibuf; } -static ImBuf *load_image_single( - Image *ima, ImageUser *iuser, int cfra, const int view_id, const bool has_packed) +static ImBuf *load_image_single(Image *ima, + ImageUser *iuser, + int cfra, + const int view_id, + const bool has_packed, + bool *r_cache_ibuf) { char filepath[FILE_MAX]; struct ImBuf *ibuf = NULL; int flag; + *r_cache_ibuf = true; + /* is there a PackedFile with this image ? */ if (has_packed) { ImagePackedFile *imapf; @@ -4544,6 +4569,9 @@ static ImBuf *load_image_single( ima->type = IMA_TYPE_MULTILAYER; IMB_freeImBuf(ibuf); ibuf = NULL; + /* NULL ibuf in the cache means the image failed to load. However for multilayer we load + * pixels into RenderResult instead and intentionally leave ibuf NULL. */ + *r_cache_ibuf = false; } } else @@ -4588,8 +4616,11 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra) } if (!is_multiview) { - ibuf = load_image_single(ima, iuser, cfra, 0, has_packed); - image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); + bool put_in_cache; + ibuf = load_image_single(ima, iuser, cfra, 0, has_packed, &put_in_cache); + if (put_in_cache) { + image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); + } } else { struct ImBuf **ibuf_arr; @@ -4597,9 +4628,10 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra) BLI_assert(totviews > 0); ibuf_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Image Views Imbufs"); + bool *cache_ibuf_arr = MEM_mallocN(sizeof(bool) * totviews, "Image Views Put In Cache"); for (int i = 0; i < totfiles; i++) { - ibuf_arr[i] = load_image_single(ima, iuser, cfra, i, has_packed); + ibuf_arr[i] = load_image_single(ima, iuser, cfra, i, has_packed, cache_ibuf_arr + i); } /* multi-views/multi-layers OpenEXR files directly populate ima, and return NULL ibuf... */ @@ -4613,7 +4645,9 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra) ibuf = ibuf_arr[i]; for (i = 0; i < totviews; i++) { - image_assign_ibuf(ima, ibuf_arr[i], i, 0); + if (cache_ibuf_arr[i]) { + image_assign_ibuf(ima, ibuf_arr[i], i, 0); + } } /* "remove" the others (decrease their refcount) */ @@ -4625,6 +4659,7 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra) /* cleanup */ MEM_freeN(ibuf_arr); + MEM_freeN(cache_ibuf_arr); } 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/layer.c b/source/blender/blenkernel/intern/layer.c index e51442b705d..6aa8e78c4f6 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -183,6 +183,7 @@ static ViewLayer *view_layer_add(const char *name) view_layer->passflag = SCE_PASS_COMBINED; view_layer->pass_alpha_threshold = 0.5f; view_layer->cryptomatte_levels = 6; + view_layer->cryptomatte_flag = VIEW_LAYER_CRYPTOMATTE_ACCURATE; BKE_freestyle_config_init(&view_layer->freestyle_config); return view_layer; diff --git a/source/blender/blenkernel/intern/layer_test.cc b/source/blender/blenkernel/intern/layer_test.cc index b5f800dd181..c8e5de75bfa 100644 --- a/source/blender/blenkernel/intern/layer_test.cc +++ b/source/blender/blenkernel/intern/layer_test.cc @@ -33,6 +33,8 @@ #include "RNA_access.h" +#include "GHOST_Path-api.h" + namespace blender::bke::tests { TEST(view_layer, aov_unique_names) @@ -94,6 +96,7 @@ TEST(view_layer, aov_unique_names) IMB_exit(); BKE_appdir_exit(); CLG_exit(); + GHOST_DisposeSystemPaths(); } static void test_render_pass_conflict(Scene *scene, @@ -173,6 +176,7 @@ TEST(view_layer, aov_conflict) IMB_exit(); BKE_appdir_exit(); CLG_exit(); + GHOST_DisposeSystemPaths(); } } // namespace blender::bke::tests diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index 5117c8bd64c..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. */ @@ -2874,7 +2874,10 @@ void BKE_lib_override_library_update(Main *bmain, ID *local) * Not impossible to do, but would rather see first if extra useless usual user handling * is actually a (performances) issue here. */ - ID *tmp_id = BKE_id_copy(bmain, local->override_library->reference); + ID *tmp_id = BKE_id_copy_ex(bmain, + local->override_library->reference, + NULL, + LIB_ID_COPY_DEFAULT | LIB_ID_COPY_NO_LIB_OVERRIDE_LOCAL_DATA_FLAG); if (tmp_id == NULL) { return; diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 3a4e39812ab..1fac83c5665 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -902,7 +902,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/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index a5eafcae839..73e0c2cfa74 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -88,7 +88,7 @@ static void mesh_init_data(ID *id) CustomData_reset(&mesh->pdata); CustomData_reset(&mesh->ldata); - BKE_mesh_runtime_reset(mesh); + BKE_mesh_runtime_init_data(mesh); mesh->face_sets_color_seed = BLI_hash_int(PIL_check_seconds_timer_i() & UINT_MAX); } @@ -168,7 +168,7 @@ static void mesh_free_data(ID *id) mesh->edit_mesh = nullptr; } - BKE_mesh_runtime_clear_cache(mesh); + BKE_mesh_runtime_free_data(mesh); mesh_clear_geometry(mesh); MEM_SAFE_FREE(mesh->mat); } @@ -308,7 +308,9 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id) mesh->texflag &= ~ME_AUTOSPACE_EVALUATED; mesh->edit_mesh = nullptr; - BKE_mesh_runtime_reset(mesh); + + memset(&mesh->runtime, 0, sizeof(mesh->runtime)); + BKE_mesh_runtime_init_data(mesh); /* happens with old files */ if (mesh->mselect == nullptr) { diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index adfbe4b8c94..1769be54211 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -1277,10 +1277,16 @@ static void add_shapekey_layers(Mesh *mesh_dest, Mesh *mesh_src) } } +/** + * \param use_virtual_modifiers: When enabled calculate virtual-modifiers before applying `md_eval` + * support this since virtual-modifiers are not modifiers from a user perspective, + * allowing shape keys to be included with the modifier being applied, see: T91923. + */ Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph, Scene *scene, Object *ob_eval, ModifierData *md_eval, + const bool use_virtual_modifiers, const bool build_shapekey_layers) { Mesh *me = ob_eval->runtime.data_orig ? (Mesh *)ob_eval->runtime.data_orig : @@ -1303,22 +1309,49 @@ Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph, BKE_keyblock_convert_to_mesh(kb, me); } - if (mti->type == eModifierTypeType_OnlyDeform) { - int numVerts; - float(*deformedVerts)[3] = BKE_mesh_vert_coords_alloc(me, &numVerts); + Mesh *mesh_temp = (Mesh *)BKE_id_copy_ex(nullptr, &me->id, nullptr, LIB_ID_COPY_LOCALIZE); + int numVerts = 0; + float(*deformedVerts)[3] = nullptr; + + if (use_virtual_modifiers) { + VirtualModifierData virtualModifierData; + for (ModifierData *md_eval_virt = + BKE_modifiers_get_virtual_modifierlist(ob_eval, &virtualModifierData); + md_eval_virt && (md_eval_virt != ob_eval->modifiers.first); + md_eval_virt = md_eval_virt->next) { + if (!BKE_modifier_is_enabled(scene, md_eval_virt, eModifierMode_Realtime)) { + continue; + } + /* All virtual modifiers are deform modifiers. */ + const ModifierTypeInfo *mti_virt = BKE_modifier_get_info((ModifierType)md_eval_virt->type); + BLI_assert(mti_virt->type == eModifierTypeType_OnlyDeform); + if (mti_virt->type != eModifierTypeType_OnlyDeform) { + continue; + } + + if (deformedVerts == nullptr) { + deformedVerts = BKE_mesh_vert_coords_alloc(me, &numVerts); + } + mti_virt->deformVerts(md_eval_virt, &mectx, mesh_temp, deformedVerts, numVerts); + } + } - result = (Mesh *)BKE_id_copy_ex(nullptr, &me->id, nullptr, LIB_ID_COPY_LOCALIZE); + if (mti->type == eModifierTypeType_OnlyDeform) { + if (deformedVerts == nullptr) { + deformedVerts = BKE_mesh_vert_coords_alloc(me, &numVerts); + } + result = mesh_temp; mti->deformVerts(md_eval, &mectx, result, deformedVerts, numVerts); BKE_mesh_vert_coords_apply(result, deformedVerts); if (build_shapekey_layers) { add_shapekey_layers(result, me); } - - MEM_freeN(deformedVerts); } else { - Mesh *mesh_temp = (Mesh *)BKE_id_copy_ex(nullptr, &me->id, nullptr, LIB_ID_COPY_LOCALIZE); + if (deformedVerts != nullptr) { + BKE_mesh_vert_coords_apply(mesh_temp, deformedVerts); + } if (build_shapekey_layers) { add_shapekey_layers(mesh_temp, me); @@ -1332,6 +1365,10 @@ Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph, } } + if (deformedVerts != nullptr) { + MEM_freeN(deformedVerts); + } + return result; } diff --git a/source/blender/blenkernel/intern/mesh_mirror.c b/source/blender/blenkernel/intern/mesh_mirror.c index b20d81e7b9c..6df13e71e72 100644 --- a/source/blender/blenkernel/intern/mesh_mirror.c +++ b/source/blender/blenkernel/intern/mesh_mirror.c @@ -260,10 +260,16 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, mul_m4_v3(mtx, mv->co); if (do_vtargetmap) { - /* compare location of the original and mirrored vertex, to see if they - * should be mapped for merging */ + /* Compare location of the original and mirrored vertex, + * to see if they should be mapped for merging. + * + * Always merge from the copied into the original vertices so it's possible to + * generate a 1:1 mapping by scanning vertices from the beginning of the array + * as is done in #BKE_editmesh_vert_coords_when_deformed. Without this, + * the coordinates returned will sometimes point to the copied vertex locations, see: T91444. + */ if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) { - *vtmap_a = maxVerts + i; + *vtmap_b = i; tot_vtargetmap++; /* average location */ @@ -271,10 +277,11 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, copy_v3_v3(mv_prev->co, mv->co); } else { - *vtmap_a = -1; + *vtmap_b = -1; } - *vtmap_b = -1; /* fill here to avoid 2x loops */ + /* Fill here to avoid 2x loops. */ + *vtmap_a = -1; vtmap_a++; vtmap_b++; diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c index 1c8646a4bdd..7b1d5140421 100644 --- a/source/blender/blenkernel/intern/mesh_runtime.c +++ b/source/blender/blenkernel/intern/mesh_runtime.c @@ -45,17 +45,54 @@ * \{ */ /** - * Default values defined at read time. + * \brief Initialize the runtime mutexes of the given mesh. + * + * Any existing mutexes will be overridden. */ -void BKE_mesh_runtime_reset(Mesh *mesh) +static void mesh_runtime_init_mutexes(Mesh *mesh) { - memset(&mesh->runtime, 0, sizeof(mesh->runtime)); mesh->runtime.eval_mutex = MEM_mallocN(sizeof(ThreadMutex), "mesh runtime eval_mutex"); BLI_mutex_init(mesh->runtime.eval_mutex); mesh->runtime.render_mutex = MEM_mallocN(sizeof(ThreadMutex), "mesh runtime render_mutex"); BLI_mutex_init(mesh->runtime.render_mutex); } +/** + * \brief free the mutexes of the given mesh runtime. + */ +static void mesh_runtime_free_mutexes(Mesh *mesh) +{ + if (mesh->runtime.eval_mutex != NULL) { + BLI_mutex_end(mesh->runtime.eval_mutex); + MEM_freeN(mesh->runtime.eval_mutex); + mesh->runtime.eval_mutex = NULL; + } + if (mesh->runtime.render_mutex != NULL) { + BLI_mutex_end(mesh->runtime.render_mutex); + MEM_freeN(mesh->runtime.render_mutex); + mesh->runtime.render_mutex = NULL; + } +} + +/** + * \brief Initialize the runtime of the given mesh. + * + * Function expects that the runtime is already cleared. + */ +void BKE_mesh_runtime_init_data(Mesh *mesh) +{ + mesh_runtime_init_mutexes(mesh); +} + +/** + * \brief Free all data (and mutexes) inside the runtime of the given mesh. + */ +void BKE_mesh_runtime_free_data(Mesh *mesh) +{ + BKE_mesh_runtime_clear_cache(mesh); + mesh_runtime_free_mutexes(mesh); +} + /* Clear all pointers which we don't want to be shared on copying the datablock. * However, keep all the flags which defines what the mesh is (for example, that * it's deformed only, or that its custom data layers are out of date.) */ @@ -71,25 +108,16 @@ void BKE_mesh_runtime_reset_on_copy(Mesh *mesh, const int UNUSED(flag)) runtime->bvh_cache = NULL; runtime->shrinkwrap_data = NULL; - mesh->runtime.eval_mutex = MEM_mallocN(sizeof(ThreadMutex), "mesh runtime eval_mutex"); - BLI_mutex_init(mesh->runtime.eval_mutex); - - mesh->runtime.render_mutex = MEM_mallocN(sizeof(ThreadMutex), "mesh runtime render_mutex"); - BLI_mutex_init(mesh->runtime.render_mutex); + mesh_runtime_init_mutexes(mesh); } +/** + * \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) { - if (mesh->runtime.eval_mutex != NULL) { - BLI_mutex_end(mesh->runtime.eval_mutex); - MEM_freeN(mesh->runtime.eval_mutex); - mesh->runtime.eval_mutex = NULL; - } - if (mesh->runtime.render_mutex != NULL) { - BLI_mutex_end(mesh->runtime.render_mutex); - MEM_freeN(mesh->runtime.render_mutex); - mesh->runtime.render_mutex = NULL; - } if (mesh->runtime.mesh_eval != NULL) { mesh->runtime.mesh_eval->edit_mesh = NULL; BKE_id_free(NULL, mesh->runtime.mesh_eval); 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 f4db81fffc5..34fb9f71bd9 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -1925,6 +1925,11 @@ void BKE_movieclip_build_proxy_frame_for_ibuf(MovieClip *clip, } } +bool BKE_movieclip_proxy_enabled(MovieClip *clip) +{ + return clip->flag & MCLIP_USE_PROXY; +} + float BKE_movieclip_remap_scene_to_clip_frame(const MovieClip *clip, float framenr) { return framenr - (float)clip->start_frame + 1.0f; diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index eb2b125e7e6..e02ea3f7e37 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -130,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) { @@ -246,7 +242,7 @@ 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); } @@ -301,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) { @@ -490,8 +486,10 @@ static void write_node_socket_default_value(BlendWriter *writer, bNodeSocket *so case SOCK_MATERIAL: BLO_write_struct(writer, bNodeSocketValueMaterial, sock->default_value); break; - case __SOCK_MESH: case SOCK_CUSTOM: + /* Custom node sockets where default_value is defined uses custom properties for storage. */ + break; + case __SOCK_MESH: case SOCK_SHADER: case SOCK_GEOMETRY: BLI_assert_unreachable(); @@ -1542,7 +1540,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; @@ -3994,8 +3992,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; } @@ -4546,18 +4546,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) @@ -4778,6 +4766,9 @@ static OutputFieldDependency find_group_output_dependencies( /* Propagate search further to the left. */ for (const InputSocketRef *origin_input_socket : gather_input_socket_dependencies(field_dependency, origin_node)) { + if (!origin_input_socket->is_available()) { + continue; + } if (!field_state_by_socket_id[origin_input_socket->id()].is_single) { if (handled_sockets.add(origin_input_socket)) { sockets_to_check.push(origin_input_socket); @@ -4826,6 +4817,9 @@ static void propagate_data_requirements_from_right_to_left( const Vector<const InputSocketRef *> connected_inputs = gather_input_socket_dependencies( field_dependency, *node); for (const InputSocketRef *input_socket : connected_inputs) { + if (!input_socket->is_available()) { + continue; + } if (inferencing_interface.inputs[input_socket->index()] == InputSocketFieldType::Implicit) { if (!input_socket->is_logically_linked()) { @@ -5243,9 +5237,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); } } @@ -5510,12 +5503,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), diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc index d650003afe2..b2dd4b40bae 100644 --- a/source/blender/blenkernel/intern/object.cc +++ b/source/blender/blenkernel/intern/object.cc @@ -4573,10 +4573,11 @@ Mesh *BKE_object_get_evaluated_mesh(const Object *object) * object types either store it there or add a reference to it if it's owned elsewhere. */ GeometrySet *geometry_set_eval = object->runtime.geometry_set_eval; if (geometry_set_eval) { - /* Some areas expect to be able to modify the evaluated mesh. Theoretically this should be - * avoided, or at least protected with a lock, so a const mesh could be returned from this - * function. */ - Mesh *mesh = geometry_set_eval->get_mesh_for_write(); + /* Some areas expect to be able to modify the evaluated mesh in limited ways. Theoretically + * this should be avoided, or at least protected with a lock, so a const mesh could be returned + * from this function. We use a const_cast instead of #get_mesh_for_write, because that might + * result in a copy of the mesh when it is shared. */ + Mesh *mesh = const_cast<Mesh *>(geometry_set_eval->get_mesh_for_read()); if (mesh) { return mesh; } diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc index 666a31a9e3f..442755be15d 100644 --- a/source/blender/blenkernel/intern/object_dupli.cc +++ b/source/blender/blenkernel/intern/object_dupli.cc @@ -166,6 +166,10 @@ static void copy_dupli_context( r_ctx->persistent_id[r_ctx->level] = index; ++r_ctx->level; + if (r_ctx->level == MAX_DUPLI_RECUR - 1) { + std::cerr << "Warning: Maximum instance recursion level reached.\n"; + } + r_ctx->gen = get_dupli_generator(r_ctx); } diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 5b62761bd91..b158633294e 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -1149,7 +1149,27 @@ void psys_copy_particles(ParticleSystem *psys_dst, ParticleSystem *psys_src) /* Copy particles and children. */ psys_dst->particles = MEM_dupallocN(psys_src->particles); psys_dst->child = MEM_dupallocN(psys_src->child); - if (psys_dst->part->type == PART_HAIR) { + + /* Ideally this should only be performed if `(psys_dst->part->type == PART_HAIR)`. + * + * But #ParticleData (`psys_dst`) is some sub-data of the #Object ID, while #ParticleSettings + * (`psys_dst->part`) is another ID. In case the particle settings is a linked ID that gets + * missing, it will be replaced (in readfile code) by a place-holder, which defaults to a + * `PART_EMITTER` type of particle settings. + * + * This leads to a situation where each particle of `psys_dst` still has a valid allocated `hair` + * data, which should still be preserved in case the missing particle settings ID becomes valid + * again. + * + * Furthermore, #free_hair() always frees `pa->hair` if it's not NULL, regardless of the + * particle type. So *not* copying here would cause a double free (or more), e.g. freeing the + * copy-on-write copy and the original data will crash Blender. + * In any case, sharing pointers between `psys_src` and `psys_dst` should be forbidden. + * + * So while we could in theory 'sanitize' the situation by setting `pa->hair` to NULL in the new + * copy (in case of non-`PART_HAIR` type), it is probably safer for now to systematically + * duplicate the `hair` data if available. */ + { ParticleData *pa; int p; for (p = 0, pa = psys_dst->particles; p < psys_dst->totpart; p++, pa++) { 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/preferences.c b/source/blender/blenkernel/intern/preferences.c index 0a10601f751..41046563f98 100644 --- a/source/blender/blenkernel/intern/preferences.c +++ b/source/blender/blenkernel/intern/preferences.c @@ -24,6 +24,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_fileops.h" #include "BLI_listbase.h" #include "BLI_path_util.h" #include "BLI_string.h" @@ -83,6 +84,18 @@ void BKE_preferences_asset_library_name_set(UserDef *userdef, sizeof(library->name)); } +/* Set the library path, ensuring it is pointing to a directory. + * Single blend files can only act as "Current File" library; libraries on disk + * should always be directories. If the path does not exist, that's fine; it can + * created as directory if necessary later. */ +void BKE_preferences_asset_library_path_set(bUserAssetLibrary *library, const char *path) +{ + BLI_strncpy_utf8(library->path, path, sizeof(library->path)); + if (BLI_is_file(library->path)) { + BLI_path_parent_dir(library->path); + } +} + bUserAssetLibrary *BKE_preferences_asset_library_find_from_index(const UserDef *userdef, int index) { return BLI_findlink(&userdef->asset_libraries, index); diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 04106e6f42a..a0bd3abbc1a 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -1071,7 +1071,7 @@ static void link_recurs_seq(BlendDataReader *reader, ListBase *lb) /* Sanity check. */ if (!SEQ_valid_strip_channel(seq)) { BLI_freelinkN(lb, seq); - BLO_read_data_reports(reader)->count.vse_strips_skipped++; + BLO_read_data_reports(reader)->count.sequence_strips_skipped++; } else if (seq->seqbase.first) { link_recurs_seq(reader, &seq->seqbase); 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/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 e760bf3495e..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 { @@ -142,11 +141,14 @@ Span<float3> BezierSpline::handle_positions_left() const this->ensure_auto_handles(); return handle_positions_left_; } -MutableSpan<float3> BezierSpline::handle_positions_left() +MutableSpan<float3> BezierSpline::handle_positions_left(const bool write_only) { - this->ensure_auto_handles(); + if (!write_only) { + this->ensure_auto_handles(); + } return handle_positions_left_; } + Span<BezierSpline::HandleType> BezierSpline::handle_types_right() const { return handle_types_right_; @@ -160,9 +162,11 @@ Span<float3> BezierSpline::handle_positions_right() const this->ensure_auto_handles(); return handle_positions_right_; } -MutableSpan<float3> BezierSpline::handle_positions_right() +MutableSpan<float3> BezierSpline::handle_positions_right(const bool write_only) { - this->ensure_auto_handles(); + if (!write_only) { + this->ensure_auto_handles(); + } return handle_positions_right_; } @@ -594,7 +598,10 @@ Span<float> BezierSpline::evaluated_mappings() const Span<int> offsets = this->control_point_offsets(); - calculate_mappings_linear_resolution(offsets, size, resolution_, is_cyclic_, mappings); + blender::threading::isolate_task([&]() { + /* Isolate the task, since this is function is multi-threaded and holds a lock. */ + calculate_mappings_linear_resolution(offsets, size, resolution_, is_cyclic_, mappings); + }); mapping_cache_dirty_ = false; return mappings; @@ -630,10 +637,13 @@ Span<float3> BezierSpline::evaluated_positions() const Span<int> offsets = this->control_point_offsets(); const int grain_size = std::max(512 / resolution_, 1); - blender::threading::parallel_for(IndexRange(size - 1), grain_size, [&](IndexRange range) { - for (const int i : range) { - this->evaluate_segment(i, i + 1, positions.slice(offsets[i], offsets[i + 1] - offsets[i])); - } + blender::threading::isolate_task([&]() { + /* Isolate the task, since this is function is multi-threaded and holds a lock. */ + blender::threading::parallel_for(IndexRange(size - 1), grain_size, [&](IndexRange range) { + for (const int i : range) { + this->evaluate_segment(i, i + 1, positions.slice(offsets[i], offsets[i + 1] - offsets[i])); + } + }); }); if (is_cyclic_) { this->evaluate_segment( @@ -697,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/text.c b/source/blender/blenkernel/intern/text.c index 0cb2218e7e0..7ac9e20d1a7 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -1977,7 +1977,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/blenlib/BLI_any.hh b/source/blender/blenlib/BLI_any.hh new file mode 100644 index 00000000000..0fc5de5540f --- /dev/null +++ b/source/blender/blenlib/BLI_any.hh @@ -0,0 +1,319 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#pragma once + +/** \file + * \ingroup bli + * + * A #blender::Any is a type-safe container for single values of any copy constructible type. + * It is similar to #std::any but provides the following two additional features: + * - Adjustable inline buffer capacity and alignment. #std::any has a small inline buffer in most + * implementations as well, but its size is not guaranteed. + * - Can store additional user-defined type information without increasing the stack size of #Any. + */ + +#include <algorithm> +#include <utility> + +#include "BLI_memory_utils.hh" + +namespace blender { + +namespace detail { + +/** + * Contains function pointers that manage the memory in an #Any. + * Additional type specific #ExtraInfo can be embedded here as well. + */ +template<typename ExtraInfo> struct AnyTypeInfo { + void (*copy_construct)(void *dst, const void *src); + void (*move_construct)(void *dst, void *src); + void (*destruct)(void *src); + const void *(*get)(const void *src); + ExtraInfo extra_info; + + /** + * Used when #T is stored directly in the inline buffer of the #Any. + */ + template<typename T> static const AnyTypeInfo &get_for_inline() + { + static AnyTypeInfo funcs = {[](void *dst, const void *src) { new (dst) T(*(const T *)src); }, + [](void *dst, void *src) { new (dst) T(std::move(*(T *)src)); }, + [](void *src) { ((T *)src)->~T(); }, + [](const void *src) { return src; }, + ExtraInfo::template get<T>()}; + return funcs; + } + + /** + * Used when #T can't be stored directly in the inline buffer and is stored in a #std::unique_ptr + * instead. In this scenario, the #std::unique_ptr is stored in the inline buffer. + */ + template<typename T> static const AnyTypeInfo &get_for_unique_ptr() + { + using Ptr = std::unique_ptr<T>; + static AnyTypeInfo funcs = { + [](void *dst, const void *src) { new (dst) Ptr(new T(**(const Ptr *)src)); }, + [](void *dst, void *src) { new (dst) Ptr(new T(std::move(**(Ptr *)src))); }, + [](void *src) { ((Ptr *)src)->~Ptr(); }, + [](const void *src) -> const void * { return &**(const Ptr *)src; }, + ExtraInfo::template get<T>()}; + return funcs; + } + + /** + * Used when the #Any does not contain any type currently. + */ + static const AnyTypeInfo &get_for_empty() + { + static AnyTypeInfo funcs = {[](void *UNUSED(dst), const void *UNUSED(src)) {}, + [](void *UNUSED(dst), void *UNUSED(src)) {}, + [](void *UNUSED(src)) {}, + [](const void *UNUSED(src)) -> const void * { return nullptr; }, + ExtraInfo{}}; + return funcs; + } +}; + +/** + * Dummy extra info that is used when no additional type information should be stored in the #Any. + */ +struct NoExtraInfo { + template<typename T> static NoExtraInfo get() + { + return {}; + } +}; + +} // namespace detail + +template< + /** + * Either void or a struct that contains data members for additional type information. + * The struct has to have a static `ExtraInfo get<T>()` method that initializes the struct + * based on a type. + */ + typename ExtraInfo = void, + /** + * Size of the inline buffer. This allows types that are small enough to be stored directly + * inside the #Any without an additional allocation. + */ + size_t InlineBufferCapacity = 8, + /** + * Required minimum alignment of the inline buffer. If this is smaller than the alignment + * requirement of a used type, a separate allocation is necessary. + */ + size_t Alignment = 8> +class Any { + private: + /* Makes it possible to use void in the template parameters. */ + using RealExtraInfo = + std::conditional_t<std::is_void_v<ExtraInfo>, detail::NoExtraInfo, ExtraInfo>; + using Info = detail::AnyTypeInfo<RealExtraInfo>; + + /** + * Inline buffer that either contains nothing, the stored value directly, or a #std::unique_ptr + * to the value. + */ + AlignedBuffer<std::max(InlineBufferCapacity, sizeof(std::unique_ptr<int>)), Alignment> buffer_{}; + + /** + * Information about the type that is currently stored. + */ + const Info *info_ = &Info::get_for_empty(); + + public: + /** Only copy constructible types can be stored in #Any. */ + template<typename T> static constexpr inline bool is_allowed_v = std::is_copy_constructible_v<T>; + + /** + * Checks if the type will be stored in the inline buffer or if it requires a separate + * allocation. + */ + template<typename T> + static constexpr inline bool is_inline_v = std::is_nothrow_move_constructible_v<T> && + sizeof(T) <= InlineBufferCapacity && + alignof(T) <= Alignment; + + /** + * Checks if #T is the same type as this #Any, because in this case the behavior of e.g. the + * assignment operator is different. + */ + template<typename T> + static constexpr inline bool is_same_any_v = std::is_same_v<std::decay_t<T>, Any>; + + private: + template<typename T> const Info &get_info() const + { + using DecayT = std::decay_t<T>; + static_assert(is_allowed_v<DecayT>); + if constexpr (is_inline_v<DecayT>) { + return Info::template get_for_inline<DecayT>(); + } + else { + return Info::template get_for_unique_ptr<DecayT>(); + } + } + + public: + Any() = default; + + Any(const Any &other) : info_(other.info_) + { + info_->copy_construct(&buffer_, &other.buffer_); + } + + /** + * \note The #other #Any will not be empty afterwards if it was not before. Just its value is in + * a moved-from state. + */ + Any(Any &&other) noexcept : info_(other.info_) + { + info_->move_construct(&buffer_, &other.buffer_); + } + + /** + * Constructs a new #Any that contains the given type #T from #args. The #std::in_place_type_t is + * used to disambiguate this and the copy/move constructors. + */ + template<typename T, typename... Args> explicit Any(std::in_place_type_t<T>, Args &&...args) + { + using DecayT = std::decay_t<T>; + static_assert(is_allowed_v<DecayT>); + info_ = &this->template get_info<DecayT>(); + if constexpr (is_inline_v<DecayT>) { + /* Construct the value directly in the inline buffer. */ + new (&buffer_) DecayT(std::forward<Args>(args)...); + } + else { + /* Construct the value in a new allocation and store a #std::unique_ptr to it in the inline + * buffer. */ + new (&buffer_) std::unique_ptr<DecayT>(new DecayT(std::forward<Args>(args)...)); + } + } + + /** + * Constructs a new #Any that contains the given value. + */ + template<typename T, typename X = std::enable_if_t<!is_same_any_v<T>, void>> + Any(T &&value) : Any(std::in_place_type<T>, std::forward<T>(value)) + { + } + + ~Any() + { + info_->destruct(&buffer_); + } + + /** + * \note: Only needed because the template below does not count as copy assignment operator. + */ + Any &operator=(const Any &other) + { + if (this == &other) { + return *this; + } + this->~Any(); + new (this) Any(other); + return *this; + } + + /** Assign any value to the #Any. */ + template<typename T> Any &operator=(T &&other) + { + if constexpr (is_same_any_v<T>) { + if (this == &other) { + return *this; + } + } + this->~Any(); + new (this) Any(std::forward<T>(other)); + return *this; + } + + /** Destruct any existing value to make it empty. */ + void reset() + { + info_->destruct(&buffer_); + info_ = &Info::get_for_empty(); + } + + operator bool() const + { + return this->has_value(); + } + + bool has_value() const + { + return info_ != &Info::get_for_empty(); + } + + template<typename T, typename... Args> std::decay_t<T> &emplace(Args &&...args) + { + this->~Any(); + new (this) Any(std::in_place_type<T>, std::forward<Args>(args)...); + return this->get<T>(); + } + + /** Return true when the value that is currently stored is a #T. */ + template<typename T> bool is() const + { + return info_ == &this->template get_info<T>(); + } + + /** Get a pointer to the stored value. */ + void *get() + { + return const_cast<void *>(info_->get(&buffer_)); + } + + /** Get a pointer to the stored value. */ + const void *get() const + { + return info_->get(&buffer_); + } + + /** + * Get a reference to the stored value. This invokes undefined behavior when #T does not have the + * correct type. + */ + template<typename T> std::decay_t<T> &get() + { + BLI_assert(this->is<T>()); + return *static_cast<std::decay_t<T> *>(this->get()); + } + + /** + * Get a reference to the stored value. This invokes undefined behavior when #T does not have the + * correct type. + */ + template<typename T> const std::decay_t<T> &get() const + { + BLI_assert(this->is<T>()); + return *static_cast<const std::decay_t<T> *>(this->get()); + } + + /** + * Get extra information that has been stored for the contained type. + */ + const RealExtraInfo &extra_info() const + { + return info_->extra_info; + } +}; + +} // namespace blender diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h index 345d9d93d03..cf525d1c2af 100644 --- a/source/blender/blenlib/BLI_listbase.h +++ b/source/blender/blenlib/BLI_listbase.h @@ -55,6 +55,10 @@ void *BLI_listbase_bytes_find(const ListBase *listbase, const void *bytes, const size_t bytes_size, const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2); +void *BLI_listbase_string_or_index_find(const struct ListBase *listbase, + const char *string, + const size_t string_offset, + const int index) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); /* find backwards */ void *BLI_rfindlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT diff --git a/source/blender/blenlib/BLI_virtual_array.hh b/source/blender/blenlib/BLI_virtual_array.hh index 1c02bce8411..d9f83d3e1cb 100644 --- a/source/blender/blenlib/BLI_virtual_array.hh +++ b/source/blender/blenlib/BLI_virtual_array.hh @@ -37,148 +37,98 @@ * see of the increased compile time and binary size is worth it. */ +#include "BLI_any.hh" #include "BLI_array.hh" #include "BLI_index_mask.hh" #include "BLI_span.hh" namespace blender { -/* An immutable virtual array. */ -template<typename T> class VArray { +/* Forward declarations for generic virtual arrays. */ +namespace fn { +class GVArray; +class GVMutableArray; +}; // namespace fn + +/** + * Implements the specifics of how the elements of a virtual array are accessed. It contains a + * bunch of virtual methods that are wrapped by #VArray. + */ +template<typename T> class VArrayImpl { protected: + /** + * Number of elements in the virtual array. All virtual arrays have a size, but in some cases it + * may make sense to set it to the max value. + */ int64_t size_; public: - VArray(const int64_t size) : size_(size) + VArrayImpl(const int64_t size) : size_(size) { BLI_assert(size_ >= 0); } - virtual ~VArray() = default; - - T get(const int64_t index) const - { - BLI_assert(index >= 0); - BLI_assert(index < size_); - return this->get_impl(index); - } + virtual ~VArrayImpl() = default; int64_t size() const { return size_; } - bool is_empty() const - { - return size_ == 0; - } - - IndexRange index_range() const - { - return IndexRange(size_); - } - - /* Returns true when the virtual array is stored as a span internally. */ - bool is_span() const - { - if (size_ == 0) { - return true; - } - return this->is_span_impl(); - } - - /* Returns the internally used span of the virtual array. This invokes undefined behavior is the - * virtual array is not stored as a span internally. */ - Span<T> get_internal_span() const - { - BLI_assert(this->is_span()); - if (size_ == 0) { - return {}; - } - return this->get_internal_span_impl(); - } + /** + * Get the element at #index. This does not return a reference, because the value may be computed + * on the fly. + */ + virtual T get(const int64_t index) const = 0; - /* Returns true when the virtual array returns the same value for every index. */ - bool is_single() const - { - if (size_ == 1) { - return true; - } - return this->is_single_impl(); - } - - /* Returns the value that is returned for every index. This invokes undefined behavior if the - * virtual array would not return the same value for every index. */ - T get_internal_single() const - { - BLI_assert(this->is_single()); - if (size_ == 1) { - return this->get(0); - } - return this->get_internal_single_impl(); - } - - /* Get the element at a specific index. Note that this operator cannot be used to assign values - * to an index, because the return value is not a reference. */ - T operator[](const int64_t index) const - { - return this->get(index); - } - - /* Copy the entire virtual array into a span. */ - void materialize(MutableSpan<T> r_span) const - { - this->materialize(IndexMask(size_), r_span); - } - - /* Copy some indices of the virtual array into a span. */ - void materialize(IndexMask mask, MutableSpan<T> r_span) const - { - BLI_assert(mask.min_array_size() <= size_); - this->materialize_impl(mask, r_span); - } - - void materialize_to_uninitialized(MutableSpan<T> r_span) const - { - this->materialize_to_uninitialized(IndexMask(size_), r_span); - } - - void materialize_to_uninitialized(IndexMask mask, MutableSpan<T> r_span) const - { - BLI_assert(mask.min_array_size() <= size_); - this->materialize_to_uninitialized_impl(mask, r_span); - } - - protected: - virtual T get_impl(const int64_t index) const = 0; - - virtual bool is_span_impl() const + /** + * Return true when the virtual array is a plain array internally. + */ + virtual bool is_span() const { return false; } - virtual Span<T> get_internal_span_impl() const + /** + * Return the span of the virtual array. + * This invokes undefined behavior when #is_span returned false. + */ + virtual Span<T> get_internal_span() const { + /* Provide a default implementation, so that subclasses don't have to provide it. This method + * should never be called because #is_span returns false by default. */ BLI_assert_unreachable(); return {}; } - virtual bool is_single_impl() const + /** + * Return true when the virtual array has the same value at every index. + */ + virtual bool is_single() const { return false; } - virtual T get_internal_single_impl() const + /** + * Return the value that is used at every index. + * This invokes undefined behavior when #is_single returned false. + */ + virtual T get_internal_single() const { /* Provide a default implementation, so that subclasses don't have to provide it. This method - * should never be called because `is_single_impl` returns false by default. */ + * should never be called because #is_single returns false by default. */ BLI_assert_unreachable(); return T(); } - virtual void materialize_impl(IndexMask mask, MutableSpan<T> r_span) const + /** + * Copy values from the virtual array into the provided span. The index of the value in the + * virtual is the same as the index in the span. + */ + virtual void materialize(IndexMask mask, MutableSpan<T> r_span) const { T *dst = r_span.data(); + /* Optimize for a few different common cases. */ if (this->is_span()) { const T *src = this->get_internal_span().data(); mask.foreach_index([&](const int64_t i) { dst[i] = src[i]; }); @@ -192,9 +142,13 @@ template<typename T> class VArray { } } - virtual void materialize_to_uninitialized_impl(IndexMask mask, MutableSpan<T> r_span) const + /** + * Same as #materialize but #r_span is expected to be uninitialized. + */ + virtual void materialize_to_uninitialized(IndexMask mask, MutableSpan<T> r_span) const { T *dst = r_span.data(); + /* Optimize for a few different common cases. */ if (this->is_span()) { const T *src = this->get_internal_span().data(); mask.foreach_index([&](const int64_t i) { new (dst + i) T(src[i]); }); @@ -207,43 +161,48 @@ template<typename T> class VArray { mask.foreach_index([&](const int64_t i) { new (dst + i) T(this->get(i)); }); } } -}; -/* Similar to VArray, but the elements are mutable. */ -template<typename T> class VMutableArray : public VArray<T> { - public: - VMutableArray(const int64_t size) : VArray<T>(size) + /** + * If this virtual wraps another #GVArray, this method should assign the wrapped array to the + * provided reference. This allows losslessly converting between generic and typed virtual + * arrays in all cases. + * Return true when the virtual array was assigned and false when nothing was done. + */ + virtual bool try_assign_GVArray(fn::GVArray &UNUSED(varray)) const { + return false; } - void set(const int64_t index, T value) + /** + * Return true when this virtual array may own any of the memory it references. This can be used + * for optimization purposes when converting or copying the virtual array. + */ + virtual bool may_have_ownership() const { - BLI_assert(index >= 0); - BLI_assert(index < this->size_); - this->set_impl(index, std::move(value)); + /* Use true by default to be on the safe side. Subclasses that know for sure that they don't + * own anything can overwrite this with false. */ + return true; } +}; - /* Copy the values from the source span to all elements in the virtual array. */ - void set_all(Span<T> src) - { - BLI_assert(src.size() == this->size_); - this->set_all_impl(src); - } +/* Similar to #VArrayImpl, but adds methods that allow modifying the referenced elements. */ +template<typename T> class VMutableArrayImpl : public VArrayImpl<T> { + public: + using VArrayImpl<T>::VArrayImpl; - MutableSpan<T> get_internal_span() - { - BLI_assert(this->is_span()); - Span<T> span = static_cast<const VArray<T> *>(this)->get_internal_span(); - return MutableSpan<T>(const_cast<T *>(span.data()), span.size()); - } + /** + * Assign the provided #value to the #index. + */ + virtual void set(const int64_t index, T value) = 0; - protected: - virtual void set_impl(const int64_t index, T value) = 0; - - virtual void set_all_impl(Span<T> src) + /** + * Copy all elements from the provided span into the virtual array. + */ + virtual void set_all(Span<T> src) { if (this->is_span()) { - const MutableSpan<T> span = this->get_internal_span(); + const Span<T> const_span = this->get_internal_span(); + const MutableSpan<T> span{(T *)const_span.data(), const_span.size()}; initialized_copy_n(src.data(), this->size_, span.data()); } else { @@ -253,95 +212,133 @@ template<typename T> class VMutableArray : public VArray<T> { } } } -}; -template<typename T> using VArrayPtr = std::unique_ptr<VArray<T>>; -template<typename T> using VMutableArrayPtr = std::unique_ptr<VMutableArray<T>>; + /** + * Similar to #VArrayImpl::try_assign_GVArray but for mutable virtual arrays. + */ + virtual bool try_assign_GVMutableArray(fn::GVMutableArray &UNUSED(varray)) const + { + return false; + } +}; /** * A virtual array implementation for a span. Methods in this class are final so that it can be * devirtualized by the compiler in some cases (e.g. when #devirtualize_varray is used). */ -template<typename T> class VArray_For_Span : public VArray<T> { +template<typename T> class VArrayImpl_For_Span : public VArrayImpl<T> { protected: const T *data_ = nullptr; public: - VArray_For_Span(const Span<T> data) : VArray<T>(data.size()), data_(data.data()) + VArrayImpl_For_Span(const Span<T> data) : VArrayImpl<T>(data.size()), data_(data.data()) { } protected: - VArray_For_Span(const int64_t size) : VArray<T>(size) + VArrayImpl_For_Span(const int64_t size) : VArrayImpl<T>(size) { } - T get_impl(const int64_t index) const final + T get(const int64_t index) const final { return data_[index]; } - bool is_span_impl() const final + bool is_span() const final { return true; } - Span<T> get_internal_span_impl() const final + Span<T> get_internal_span() const final { return Span<T>(data_, this->size_); } }; -template<typename T> class VMutableArray_For_MutableSpan : public VMutableArray<T> { +/** + * A version of #VArrayImpl_For_Span that can not be subclassed. This allows safely overwriting the + * #may_have_ownership method. + */ +template<typename T> class VArrayImpl_For_Span_final final : public VArrayImpl_For_Span<T> { + public: + using VArrayImpl_For_Span<T>::VArrayImpl_For_Span; + + private: + bool may_have_ownership() const override + { + return false; + } +}; + +/** + * Like #VArrayImpl_For_Span but for mutable data. + */ +template<typename T> class VMutableArrayImpl_For_MutableSpan : public VMutableArrayImpl<T> { protected: T *data_ = nullptr; public: - VMutableArray_For_MutableSpan(const MutableSpan<T> data) - : VMutableArray<T>(data.size()), data_(data.data()) + VMutableArrayImpl_For_MutableSpan(const MutableSpan<T> data) + : VMutableArrayImpl<T>(data.size()), data_(data.data()) { } protected: - VMutableArray_For_MutableSpan(const int64_t size) : VMutableArray<T>(size) + VMutableArrayImpl_For_MutableSpan(const int64_t size) : VMutableArrayImpl<T>(size) { } - T get_impl(const int64_t index) const final + T get(const int64_t index) const final { return data_[index]; } - void set_impl(const int64_t index, T value) final + void set(const int64_t index, T value) final { data_[index] = value; } - bool is_span_impl() const override + bool is_span() const override { return true; } - Span<T> get_internal_span_impl() const override + Span<T> get_internal_span() const override { return Span<T>(data_, this->size_); } }; /** - * A variant of `VArray_For_Span` that owns the underlying data. + * Like #VArrayImpl_For_Span_final but for mutable data. + */ +template<typename T> +class VMutableArrayImpl_For_MutableSpan_final final : public VMutableArrayImpl_For_MutableSpan<T> { + public: + using VMutableArrayImpl_For_MutableSpan<T>::VMutableArrayImpl_For_MutableSpan; + + private: + bool may_have_ownership() const override + { + return false; + } +}; + +/** + * A variant of `VArrayImpl_For_Span` that owns the underlying data. * The `Container` type has to implement a `size()` and `data()` method. * The `data()` method has to return a pointer to the first element in the continuous array of * elements. */ template<typename Container, typename T = typename Container::value_type> -class VArray_For_ArrayContainer : public VArray_For_Span<T> { +class VArrayImpl_For_ArrayContainer : public VArrayImpl_For_Span<T> { private: Container container_; public: - VArray_For_ArrayContainer(Container container) - : VArray_For_Span<T>((int64_t)container.size()), container_(std::move(container)) + VArrayImpl_For_ArrayContainer(Container container) + : VArrayImpl_For_Span<T>((int64_t)container.size()), container_(std::move(container)) { this->data_ = container_.data(); } @@ -352,43 +349,671 @@ class VArray_For_ArrayContainer : public VArray_For_Span<T> { * so that it can be devirtualized by the compiler in some cases (e.g. when #devirtualize_varray is * used). */ -template<typename T> class VArray_For_Single final : public VArray<T> { +template<typename T> class VArrayImpl_For_Single final : public VArrayImpl<T> { private: T value_; public: - VArray_For_Single(T value, const int64_t size) : VArray<T>(size), value_(std::move(value)) + VArrayImpl_For_Single(T value, const int64_t size) + : VArrayImpl<T>(size), value_(std::move(value)) { } protected: - T get_impl(const int64_t UNUSED(index)) const override + T get(const int64_t UNUSED(index)) const override { return value_; } - bool is_span_impl() const override + bool is_span() const override { return this->size_ == 1; } - Span<T> get_internal_span_impl() const override + Span<T> get_internal_span() const override { return Span<T>(&value_, 1); } - bool is_single_impl() const override + bool is_single() const override { return true; } - T get_internal_single_impl() const override + T get_internal_single() const override { return value_; } }; /** + * This class makes it easy to create a virtual array for an existing function or lambda. The + * `GetFunc` should take a single `index` argument and return the value at that index. + */ +template<typename T, typename GetFunc> class VArrayImpl_For_Func final : public VArrayImpl<T> { + private: + GetFunc get_func_; + + public: + VArrayImpl_For_Func(const int64_t size, GetFunc get_func) + : VArrayImpl<T>(size), get_func_(std::move(get_func)) + { + } + + private: + T get(const int64_t index) const override + { + return get_func_(index); + } + + void materialize(IndexMask mask, MutableSpan<T> r_span) const override + { + T *dst = r_span.data(); + mask.foreach_index([&](const int64_t i) { dst[i] = get_func_(i); }); + } + + void materialize_to_uninitialized(IndexMask mask, MutableSpan<T> r_span) const override + { + T *dst = r_span.data(); + mask.foreach_index([&](const int64_t i) { new (dst + i) T(get_func_(i)); }); + } +}; + +/** + * \note: This is `final` so that #may_have_ownership can be implemented reliably. + */ +template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)> +class VArrayImpl_For_DerivedSpan final : public VArrayImpl<ElemT> { + private: + const StructT *data_; + + public: + VArrayImpl_For_DerivedSpan(const Span<StructT> data) + : VArrayImpl<ElemT>(data.size()), data_(data.data()) + { + } + + private: + ElemT get(const int64_t index) const override + { + return GetFunc(data_[index]); + } + + void materialize(IndexMask mask, MutableSpan<ElemT> r_span) const override + { + ElemT *dst = r_span.data(); + mask.foreach_index([&](const int64_t i) { dst[i] = GetFunc(data_[i]); }); + } + + void materialize_to_uninitialized(IndexMask mask, MutableSpan<ElemT> r_span) const override + { + ElemT *dst = r_span.data(); + mask.foreach_index([&](const int64_t i) { new (dst + i) ElemT(GetFunc(data_[i])); }); + } + + bool may_have_ownership() const override + { + return false; + } +}; + +/** + * \note: This is `final` so that #may_have_ownership can be implemented reliably. + */ +template<typename StructT, + typename ElemT, + ElemT (*GetFunc)(const StructT &), + void (*SetFunc)(StructT &, ElemT)> +class VMutableArrayImpl_For_DerivedSpan final : public VMutableArrayImpl<ElemT> { + private: + StructT *data_; + + public: + VMutableArrayImpl_For_DerivedSpan(const MutableSpan<StructT> data) + : VMutableArrayImpl<ElemT>(data.size()), data_(data.data()) + { + } + + private: + ElemT get(const int64_t index) const override + { + return GetFunc(data_[index]); + } + + void set(const int64_t index, ElemT value) override + { + SetFunc(data_[index], std::move(value)); + } + + void materialize(IndexMask mask, MutableSpan<ElemT> r_span) const override + { + ElemT *dst = r_span.data(); + mask.foreach_index([&](const int64_t i) { dst[i] = GetFunc(data_[i]); }); + } + + void materialize_to_uninitialized(IndexMask mask, MutableSpan<ElemT> r_span) const override + { + ElemT *dst = r_span.data(); + mask.foreach_index([&](const int64_t i) { new (dst + i) ElemT(GetFunc(data_[i])); }); + } + + bool may_have_ownership() const override + { + return false; + } +}; + +namespace detail { + +/** + * Struct that can be passed as `ExtraInfo` into an #Any. + * This struct is only intended to be used by #VArrayCommon. + */ +template<typename T> struct VArrayAnyExtraInfo { + /** + * Gets the virtual array that is stored at the given pointer. + */ + const VArrayImpl<T> *(*get_varray)(const void *buffer) = + [](const void *UNUSED(buffer)) -> const VArrayImpl<T> * { return nullptr; }; + + template<typename StorageT> static VArrayAnyExtraInfo get() + { + /* These are the only allowed types in the #Any. */ + static_assert(std::is_base_of_v<VArrayImpl<T>, StorageT> || + std::is_same_v<StorageT, const VArrayImpl<T> *> || + std::is_same_v<StorageT, std::shared_ptr<const VArrayImpl<T>>>); + + /* Depending on how the virtual array implementation is stored in the #Any, a different + * #get_varray function is required. */ + if constexpr (std::is_base_of_v<VArrayImpl<T>, StorageT>) { + return {[](const void *buffer) { + return static_cast<const VArrayImpl<T> *>((const StorageT *)buffer); + }}; + } + else if constexpr (std::is_same_v<StorageT, const VArrayImpl<T> *>) { + return {[](const void *buffer) { return *(const StorageT *)buffer; }}; + } + else if constexpr (std::is_same_v<StorageT, std::shared_ptr<const VArrayImpl<T>>>) { + return {[](const void *buffer) { return ((const StorageT *)buffer)->get(); }}; + } + else { + BLI_assert_unreachable(); + return {}; + } + } +}; + +} // namespace detail + +/** + * Utility class to reduce code duplication for methods available on #VArray and #VMutableArray. + * Deriving #VMutableArray from #VArray would have some issues: + * - Static methods on #VArray would also be available on #VMutableArray. + * - It would allow assigning a #VArray to a #VMutableArray under some circumstances which is not + * allowed and could result in hard to find bugs. + */ +template<typename T> class VArrayCommon { + protected: + /** + * Store the virtual array implementation in an #Any. This makes it easy to avoid a memory + * allocation if the implementation is small enough and is copyable. This is the case for the + * most common virtual arrays. + * Other virtual array implementations are typically stored as #std::shared_ptr. That works even + * when the implementation itself is not copyable and makes copying #VArrayCommon cheaper. + */ + using Storage = Any<detail::VArrayAnyExtraInfo<T>, 24, 8>; + + /** + * Pointer to the currently contained virtual array implementation. This is allowed to be null. + */ + const VArrayImpl<T> *impl_ = nullptr; + /** + * Does the memory management for the virtual array implementation. It contains one of the + * following: + * - Inlined subclass of #VArrayImpl. + * - Non-owning pointer to a #VArrayImpl. + * - Shared pointer to a #VArrayImpl. + */ + Storage storage_; + + protected: + VArrayCommon() = default; + + /** Copy constructor. */ + VArrayCommon(const VArrayCommon &other) : storage_(other.storage_) + { + impl_ = this->impl_from_storage(); + } + + /** Move constructor. */ + VArrayCommon(VArrayCommon &&other) noexcept : storage_(std::move(other.storage_)) + { + impl_ = this->impl_from_storage(); + other.storage_.reset(); + other.impl_ = nullptr; + } + + /** + * Wrap an existing #VArrayImpl and don't take ownership of it. This should rarely be used in + * practice. + */ + VArrayCommon(const VArrayImpl<T> *impl) : impl_(impl) + { + storage_ = impl_; + } + + /** + * Wrap an existing #VArrayImpl that is contained in a #std::shared_ptr. This takes ownership. + */ + VArrayCommon(std::shared_ptr<const VArrayImpl<T>> impl) : impl_(impl.get()) + { + if (impl) { + storage_ = std::move(impl); + } + } + + /** + * Replace the contained #VArrayImpl. + */ + template<typename ImplT, typename... Args> void emplace(Args &&...args) + { + /* Make sure we are actually constructing a #VArrayImpl. */ + static_assert(std::is_base_of_v<VArrayImpl<T>, ImplT>); + if constexpr (std::is_copy_constructible_v<ImplT> && Storage::template is_inline_v<ImplT>) { + /* Only inline the implementatiton when it is copyable and when it fits into the inline + * buffer of the storage. */ + impl_ = &storage_.template emplace<ImplT>(std::forward<Args>(args)...); + } + else { + /* If it can't be inlined, create a new #std::shared_ptr instead and store that in the + * storage. */ + std::shared_ptr<const VArrayImpl<T>> ptr = std::make_shared<ImplT>( + std::forward<Args>(args)...); + impl_ = &*ptr; + storage_ = std::move(ptr); + } + } + + /** Utility to implement a copy assignment operator in a subclass. */ + void copy_from(const VArrayCommon &other) + { + if (this == &other) { + return; + } + storage_ = other.storage_; + impl_ = this->impl_from_storage(); + } + + /** Utility to implement a move assignment operator in a subclass. */ + void move_from(VArrayCommon &&other) noexcept + { + if (this == &other) { + return; + } + storage_ = std::move(other.storage_); + impl_ = this->impl_from_storage(); + other.storage_.reset(); + other.impl_ = nullptr; + } + + /** Get a pointer to the virtual array implementation that is currently stored in #storage_, or + * null. */ + const VArrayImpl<T> *impl_from_storage() const + { + return storage_.extra_info().get_varray(storage_.get()); + } + + public: + /** Return false when there is no virtual array implementation currently. */ + operator bool() const + { + return impl_ != nullptr; + } + + /** + * Get the element at a specific index. + * \note: This can't return a reference because the value may be computed on the fly. This also + * implies that one can not use this method for assignments. + */ + T operator[](const int64_t index) const + { + BLI_assert(*this); + BLI_assert(index >= 0); + BLI_assert(index < this->size()); + return impl_->get(index); + } + + /** + * Same as the #operator[] but is sometimes easier to use when one has a pointer to a virtual + * array. + */ + T get(const int64_t index) const + { + return (*this)[index]; + } + + /** + * Return the size of the virtual array. It's allowed to call this method even when there is no + * virtual array. In this case 0 is returned. + */ + int64_t size() const + { + if (impl_ == nullptr) { + return 0; + } + return impl_->size(); + } + + /** True when the size is zero or when there is no virtual array. */ + bool is_empty() const + { + return this->size() == 0; + } + + IndexRange index_range() const + { + return IndexRange(this->size()); + } + + /** Return true when the virtual array is stored as a span internally. */ + bool is_span() const + { + BLI_assert(*this); + if (this->is_empty()) { + return true; + } + return impl_->is_span(); + } + + /** + * Returns the internally used span of the virtual array. This invokes undefined behavior is the + * virtual array is not stored as a span internally. + */ + Span<T> get_internal_span() const + { + BLI_assert(this->is_span()); + if (this->is_empty()) { + return {}; + } + return impl_->get_internal_span(); + } + + /** Return true when the virtual array returns the same value for every index. */ + bool is_single() const + { + BLI_assert(*this); + if (impl_->size() == 1) { + return true; + } + return impl_->is_single(); + } + + /** + * Return the value that is returned for every index. This invokes undefined behavior if the + * virtual array would not return the same value for every index. + */ + T get_internal_single() const + { + BLI_assert(this->is_single()); + if (impl_->size() == 1) { + return impl_->get(0); + } + return impl_->get_internal_single(); + } + + /** Copy the entire virtual array into a span. */ + void materialize(MutableSpan<T> r_span) const + { + this->materialize(IndexMask(this->size()), r_span); + } + + /** Copy some indices of the virtual array into a span. */ + void materialize(IndexMask mask, MutableSpan<T> r_span) const + { + BLI_assert(mask.min_array_size() <= this->size()); + impl_->materialize(mask, r_span); + } + + void materialize_to_uninitialized(MutableSpan<T> r_span) const + { + this->materialize_to_uninitialized(IndexMask(this->size()), r_span); + } + + void materialize_to_uninitialized(IndexMask mask, MutableSpan<T> r_span) const + { + BLI_assert(mask.min_array_size() <= this->size()); + impl_->materialize_to_uninitialized(mask, r_span); + } + + /** See #GVArrayImpl::try_assign_GVArray. */ + bool try_assign_GVArray(fn::GVArray &varray) const + { + return impl_->try_assign_GVArray(varray); + } + + /** See #GVArrayImpl::may_have_ownership. */ + bool may_have_ownership() const + { + return impl_->may_have_ownership(); + } +}; + +template<typename T> class VMutableArray; + +/** + * A #VArray wraps a virtual array implementation and provides easy access to its elements. It can + * be copied and moved. While it is relatively small, it should still be passed by reference if + * possible (other than e.g. #Span). + */ +template<typename T> class VArray : public VArrayCommon<T> { + friend VMutableArray<T>; + + public: + VArray() = default; + VArray(const VArray &other) = default; + VArray(VArray &&other) noexcept = default; + + VArray(const VArrayImpl<T> *impl) : VArrayCommon<T>(impl) + { + } + + VArray(std::shared_ptr<const VArrayImpl<T>> impl) : VArrayCommon<T>(std::move(impl)) + { + } + + /** + * Construct a new virtual array for a custom #VArrayImpl. + */ + template<typename ImplT, typename... Args> static VArray For(Args &&...args) + { + static_assert(std::is_base_of_v<VArrayImpl<T>, ImplT>); + VArray varray; + varray.template emplace<ImplT>(std::forward<Args>(args)...); + return varray; + } + + /** + * Construct a new virtual array that has the same value at every index. + */ + static VArray ForSingle(T value, const int64_t size) + { + return VArray::For<VArrayImpl_For_Single<T>>(std::move(value), size); + } + + /** + * Construct a new virtual array for an existing span. This does not take ownership of the + * underlying memory. + */ + static VArray ForSpan(Span<T> values) + { + return VArray::For<VArrayImpl_For_Span_final<T>>(values); + } + + /** + * Construct a new virtual that will invoke the provided function whenever an element is + * accessed. + */ + template<typename GetFunc> static VArray ForFunc(const int64_t size, GetFunc get_func) + { + return VArray::For<VArrayImpl_For_Func<T, decltype(get_func)>>(size, std::move(get_func)); + } + + /** + * Construct a new virtual array for an existing span with a mapping function. This does not take + * ownership of the span. + */ + template<typename StructT, T (*GetFunc)(const StructT &)> + static VArray ForDerivedSpan(Span<StructT> values) + { + return VArray::For<VArrayImpl_For_DerivedSpan<StructT, T, GetFunc>>(values); + } + + /** + * Construct a new virtual array for an existing container. Every container that lays out the + * elements in a plain array works. This takes ownership of the passed in container. If that is + * not desired, use #ForSpan instead. + */ + template<typename ContainerT> static VArray ForContainer(ContainerT container) + { + return VArray::For<VArrayImpl_For_ArrayContainer<ContainerT>>(std::move(container)); + } + + VArray &operator=(const VArray &other) + { + this->copy_from(other); + return *this; + } + + VArray &operator=(VArray &&other) noexcept + { + this->move_from(std::move(other)); + return *this; + } +}; + +/** + * Similar to #VArray but references a virtual array that can be modified. + */ +template<typename T> class VMutableArray : public VArrayCommon<T> { + public: + VMutableArray() = default; + VMutableArray(const VMutableArray &other) = default; + VMutableArray(VMutableArray &&other) noexcept = default; + + VMutableArray(const VMutableArrayImpl<T> *impl) : VArrayCommon<T>(impl) + { + } + + VMutableArray(std::shared_ptr<const VMutableArrayImpl<T>> impl) + : VArrayCommon<T>(std::move(impl)) + { + } + + /** + * Construct a new virtual array for a custom #VMutableArrayImpl. + */ + template<typename ImplT, typename... Args> static VMutableArray For(Args &&...args) + { + static_assert(std::is_base_of_v<VMutableArrayImpl<T>, ImplT>); + VMutableArray varray; + varray.template emplace<ImplT>(std::forward<Args>(args)...); + return varray; + } + + /** + * Construct a new virtual array for an existing span. This does not take ownership of the span. + */ + static VMutableArray ForSpan(MutableSpan<T> values) + { + return VMutableArray::For<VMutableArrayImpl_For_MutableSpan_final<T>>(values); + } + + /** + * Construct a new virtual array for an existing span with a mapping function. This does not take + * ownership of the span. + */ + template<typename StructT, T (*GetFunc)(const StructT &), void (*SetFunc)(StructT &, T)> + static VMutableArray ForDerivedSpan(MutableSpan<StructT> values) + { + return VMutableArray::For<VMutableArrayImpl_For_DerivedSpan<StructT, T, GetFunc, SetFunc>>( + values); + } + + /** Convert to a #VArray by copying. */ + operator VArray<T>() const & + { + VArray<T> varray; + varray.copy_from(*this); + return varray; + } + + /** Convert to a #VArray by moving. */ + operator VArray<T>() &&noexcept + { + VArray<T> varray; + varray.move_from(std::move(*this)); + return varray; + } + + VMutableArray &operator=(const VMutableArray &other) + { + this->copy_from(other); + return *this; + } + + VMutableArray &operator=(VMutableArray &&other) noexcept + { + this->move_from(std::move(other)); + return *this; + } + + /** + * Get access to the internal span. This invokes undefined behavior if the #is_span returned + * false. + */ + MutableSpan<T> get_internal_span() const + { + BLI_assert(this->is_span()); + const Span<T> span = this->impl_->get_internal_span(); + return MutableSpan<T>(const_cast<T *>(span.data()), span.size()); + } + + /** + * Set the value at the given index. + */ + void set(const int64_t index, T value) + { + BLI_assert(index >= 0); + BLI_assert(index < this->size()); + this->get_impl()->set(index, std::move(value)); + } + + /** + * Copy the values from the source span to all elements in the virtual array. + */ + void set_all(Span<T> src) + { + BLI_assert(src.size() == this->size()); + this->get_impl()->set_all(src); + } + + /** See #GVMutableArrayImpl::try_assign_GVMutableArray. */ + bool try_assign_GVMutableArray(fn::GVMutableArray &varray) const + { + return this->get_impl()->try_assign_GVMutableArray(varray); + } + + private: + /** Utility to get the pointer to the wrapped #VMutableArrayImpl. */ + VMutableArrayImpl<T> *get_impl() const + { + /* This cast is valid by the invariant that a #VMutableArray->impl_ is always a + * #VMutableArrayImpl. */ + return (VMutableArrayImpl<T> *)this->impl_; + } +}; + +/** * In many cases a virtual array is a span internally. In those cases, access to individual could * be much more efficient than calling a virtual method. When the underlying virtual array is not a * span, this class allocates a new array and copies the values over. @@ -401,11 +1026,11 @@ template<typename T> class VArray_For_Single final : public VArray<T> { */ template<typename T> class VArray_Span final : public Span<T> { private: - const VArray<T> &varray_; + VArray<T> varray_; Array<T> owned_data_; public: - VArray_Span(const VArray<T> &varray) : Span<T>(), varray_(varray) + VArray_Span(VArray<T> varray) : Span<T>(), varray_(std::move(varray)) { this->size_ = varray_.size(); if (varray_.is_span()) { @@ -421,7 +1046,7 @@ template<typename T> class VArray_Span final : public Span<T> { }; /** - * Same as VArray_Span, but for a mutable span. + * Same as #VArray_Span, but for a mutable span. * The important thing to note is that when changing this span, the results might not be * immediately reflected in the underlying virtual array (only when the virtual array is a span * internally). The #save method can be used to write all changes to the underlying virtual array, @@ -429,7 +1054,7 @@ template<typename T> class VArray_Span final : public Span<T> { */ template<typename T> class VMutableArray_Span final : public MutableSpan<T> { private: - VMutableArray<T> &varray_; + VMutableArray<T> varray_; Array<T> owned_data_; bool save_has_been_called_ = false; bool show_not_saved_warning_ = true; @@ -437,8 +1062,8 @@ template<typename T> class VMutableArray_Span final : public MutableSpan<T> { public: /* Create a span for any virtual array. This is cheap when the virtual array is a span itself. If * not, a new array has to be allocated as a wrapper for the underlying virtual array. */ - VMutableArray_Span(VMutableArray<T> &varray, const bool copy_values_to_span = true) - : MutableSpan<T>(), varray_(varray) + VMutableArray_Span(VMutableArray<T> varray, const bool copy_values_to_span = true) + : MutableSpan<T>(), varray_(std::move(varray)) { this->size_ = varray_.size(); if (varray_.is_span()) { @@ -483,106 +1108,6 @@ template<typename T> class VMutableArray_Span final : public MutableSpan<T> { }; /** - * This class makes it easy to create a virtual array for an existing function or lambda. The - * `GetFunc` should take a single `index` argument and return the value at that index. - */ -template<typename T, typename GetFunc> class VArray_For_Func final : public VArray<T> { - private: - GetFunc get_func_; - - public: - VArray_For_Func(const int64_t size, GetFunc get_func) - : VArray<T>(size), get_func_(std::move(get_func)) - { - } - - private: - T get_impl(const int64_t index) const override - { - return get_func_(index); - } - - void materialize_impl(IndexMask mask, MutableSpan<T> r_span) const override - { - T *dst = r_span.data(); - mask.foreach_index([&](const int64_t i) { dst[i] = get_func_(i); }); - } - - void materialize_to_uninitialized_impl(IndexMask mask, MutableSpan<T> r_span) const override - { - T *dst = r_span.data(); - mask.foreach_index([&](const int64_t i) { new (dst + i) T(get_func_(i)); }); - } -}; - -template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)> -class VArray_For_DerivedSpan : public VArray<ElemT> { - private: - const StructT *data_; - - public: - VArray_For_DerivedSpan(const Span<StructT> data) : VArray<ElemT>(data.size()), data_(data.data()) - { - } - - private: - ElemT get_impl(const int64_t index) const override - { - return GetFunc(data_[index]); - } - - void materialize_impl(IndexMask mask, MutableSpan<ElemT> r_span) const override - { - ElemT *dst = r_span.data(); - mask.foreach_index([&](const int64_t i) { dst[i] = GetFunc(data_[i]); }); - } - - void materialize_to_uninitialized_impl(IndexMask mask, MutableSpan<ElemT> r_span) const override - { - ElemT *dst = r_span.data(); - mask.foreach_index([&](const int64_t i) { new (dst + i) ElemT(GetFunc(data_[i])); }); - } -}; - -template<typename StructT, - typename ElemT, - ElemT (*GetFunc)(const StructT &), - void (*SetFunc)(StructT &, ElemT)> -class VMutableArray_For_DerivedSpan : public VMutableArray<ElemT> { - private: - StructT *data_; - - public: - VMutableArray_For_DerivedSpan(const MutableSpan<StructT> data) - : VMutableArray<ElemT>(data.size()), data_(data.data()) - { - } - - private: - ElemT get_impl(const int64_t index) const override - { - return GetFunc(data_[index]); - } - - void set_impl(const int64_t index, ElemT value) override - { - SetFunc(data_[index], std::move(value)); - } - - void materialize_impl(IndexMask mask, MutableSpan<ElemT> r_span) const override - { - ElemT *dst = r_span.data(); - mask.foreach_index([&](const int64_t i) { dst[i] = GetFunc(data_[i]); }); - } - - void materialize_to_uninitialized_impl(IndexMask mask, MutableSpan<ElemT> r_span) const override - { - ElemT *dst = r_span.data(); - mask.foreach_index([&](const int64_t i) { new (dst + i) ElemT(GetFunc(data_[i])); }); - } -}; - -/** * Generate multiple versions of the given function optimized for different virtual arrays. * One has to be careful with nesting multiple devirtualizations, because that results in an * exponential number of function instantiations (increasing compile time and binary size). @@ -596,15 +1121,14 @@ inline void devirtualize_varray(const VArray<T> &varray, const Func &func, bool /* Support disabling the devirtualization to simplify benchmarking. */ if (enable) { if (varray.is_single()) { - /* `VArray_For_Single` can be used for devirtualization, because it is declared `final`. */ - const VArray_For_Single<T> varray_single{varray.get_internal_single(), varray.size()}; - func(varray_single); + /* `VArrayImpl_For_Single` can be used for devirtualization, because it is declared `final`. + */ + func(VArray<T>::ForSingle(varray.get_internal_single(), varray.size())); return; } if (varray.is_span()) { - /* `VArray_For_Span` can be used for devirtualization, because it is declared `final`. */ - const VArray_For_Span<T> varray_span{varray.get_internal_span()}; - func(varray_span); + /* `VArrayImpl_For_Span` can be used for devirtualization, because it is declared `final`. */ + func(VArray<T>::ForSpan(varray.get_internal_span())); return; } } @@ -629,27 +1153,23 @@ inline void devirtualize_varray2(const VArray<T1> &varray1, const bool is_single1 = varray1.is_single(); const bool is_single2 = varray2.is_single(); if (is_span1 && is_span2) { - const VArray_For_Span<T1> varray1_span{varray1.get_internal_span()}; - const VArray_For_Span<T2> varray2_span{varray2.get_internal_span()}; - func(varray1_span, varray2_span); + func(VArray<T1>::ForSpan(varray1.get_internal_span()), + VArray<T2>::ForSpan(varray2.get_internal_span())); return; } if (is_span1 && is_single2) { - const VArray_For_Span<T1> varray1_span{varray1.get_internal_span()}; - const VArray_For_Single<T2> varray2_single{varray2.get_internal_single(), varray2.size()}; - func(varray1_span, varray2_single); + func(VArray<T1>::ForSpan(varray1.get_internal_span()), + VArray<T2>::ForSingle(varray2.get_internal_single(), varray2.size())); return; } if (is_single1 && is_span2) { - const VArray_For_Single<T1> varray1_single{varray1.get_internal_single(), varray1.size()}; - const VArray_For_Span<T2> varray2_span{varray2.get_internal_span()}; - func(varray1_single, varray2_span); + func(VArray<T1>::ForSingle(varray1.get_internal_single(), varray1.size()), + VArray<T2>::ForSpan(varray2.get_internal_span())); return; } if (is_single1 && is_single2) { - const VArray_For_Single<T1> varray1_single{varray1.get_internal_single(), varray1.size()}; - const VArray_For_Single<T2> varray2_single{varray2.get_internal_single(), varray2.size()}; - func(varray1_single, varray2_single); + func(VArray<T1>::ForSingle(varray1.get_internal_single(), varray1.size()), + VArray<T2>::ForSingle(varray2.get_internal_single(), varray2.size())); return; } } diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 7db984aef5c..29493c799b3 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -165,6 +165,7 @@ set(SRC BLI_alloca.h BLI_allocator.hh + BLI_any.hh BLI_args.h BLI_array.h BLI_array.hh @@ -411,6 +412,7 @@ blender_add_lib(bf_blenlib "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") if(WITH_GTESTS) set(TEST_SRC + tests/BLI_any_test.cc tests/BLI_array_store_test.cc tests/BLI_array_test.cc tests/BLI_array_utils_test.cc diff --git a/source/blender/blenlib/intern/BLI_mempool.c b/source/blender/blenlib/intern/BLI_mempool.c index f968799326a..bd6a124c7cb 100644 --- a/source/blender/blenlib/intern/BLI_mempool.c +++ b/source/blender/blenlib/intern/BLI_mempool.c @@ -126,7 +126,7 @@ struct BLI_mempool { uint flag; /* keeps aligned to 16 bits */ - /** Free element list. Interleaved into chunk datas. */ + /** Free element list. Interleaved into chunk data. */ BLI_freenode *free; /** Use to know how many chunks to keep for #BLI_mempool_clear. */ uint maxchunks; diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c index 1b16f6b0aee..443bef42cc2 100644 --- a/source/blender/blenlib/intern/listbase.c +++ b/source/blender/blenlib/intern/listbase.c @@ -826,6 +826,37 @@ void *BLI_listbase_bytes_rfind(const ListBase *listbase, } /** + * Find the first item in the list that matches the given string, or the given index as fallback. + * + * \note The string is only used is non-NULL and non-empty. + * + * \return The found item, or NULL. + */ +void *BLI_listbase_string_or_index_find(const ListBase *listbase, + const char *string, + const size_t string_offset, + const int index) +{ + Link *link = NULL; + Link *link_at_index = NULL; + + int index_iter; + for (link = listbase->first, index_iter = 0; link; link = link->next, index_iter++) { + if (string != NULL && string[0] != '\0') { + const char *string_iter = ((const char *)link) + string_offset; + + if (string[0] == string_iter[0] && STREQ(string, string_iter)) { + return link; + } + } + if (index_iter == index) { + link_at_index = link; + } + } + return link_at_index; +} + +/** * Returns the 0-based index of the first element of listbase which contains the specified * null-terminated string at the specified offset, or -1 if not found. */ diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c index e8be674b6c1..62c8625378d 100644 --- a/source/blender/blenlib/intern/string.c +++ b/source/blender/blenlib/intern/string.c @@ -1346,9 +1346,8 @@ void BLI_str_format_byte_unit(char dst[15], long long int bytes, const bool base } /** - * Format a attribute domain to a up to 6 places (plus '\0' terminator) string using long number - * names abbreviations. This function is designed to produce a compact representation of large - * numbers. + * Format a count to up to 6 places (plus '\0' terminator) string using long number + * names abbreviations. Used to produce a compact representation of large numbers. * * 1 -> 1 * 15 -> 15 @@ -1362,8 +1361,7 @@ void BLI_str_format_byte_unit(char dst[15], long long int bytes, const bool base * 1000000000 -> 1B * ... * - * Dimension of 7 is the maximum length of the resulting string - * A combination with 7 places would be -15.5K\0 + * Length of 7 is the maximum of the resulting string, for example, `-15.5K\0`. */ void BLI_str_format_attribute_domain_size(char dst[7], int number_to_format) { diff --git a/source/blender/blenlib/tests/BLI_any_test.cc b/source/blender/blenlib/tests/BLI_any_test.cc new file mode 100644 index 00000000000..226088cf3c7 --- /dev/null +++ b/source/blender/blenlib/tests/BLI_any_test.cc @@ -0,0 +1,108 @@ +/* Apache License, Version 2.0 */ + +#include "BLI_any.hh" +#include "BLI_map.hh" + +#include "testing/testing.h" + +namespace blender::tests { + +TEST(any, DefaultConstructor) +{ + Any a; + EXPECT_FALSE(a.has_value()); +} + +TEST(any, AssignInt) +{ + Any<> a = 5; + EXPECT_TRUE(a.has_value()); + EXPECT_TRUE(a.is<int>()); + EXPECT_FALSE(a.is<float>()); + const int &value = a.get<int>(); + EXPECT_EQ(value, 5); + a = 10; + EXPECT_EQ(value, 10); + + Any b = a; + EXPECT_TRUE(b.has_value()); + EXPECT_EQ(b.get<int>(), 10); + + Any c = std::move(a); + EXPECT_TRUE(c); + EXPECT_EQ(c.get<int>(), 10); + + EXPECT_EQ(a.get<int>(), 10); /* NOLINT: bugprone-use-after-move */ + + a.reset(); + EXPECT_FALSE(a); +} + +TEST(any, AssignMap) +{ + Any<> a = Map<int, int>(); + EXPECT_TRUE(a.has_value()); + EXPECT_TRUE((a.is<Map<int, int>>())); + EXPECT_FALSE((a.is<Map<int, float>>())); + Map<int, int> &map = a.get<Map<int, int>>(); + map.add(4, 2); + EXPECT_EQ((a.get<Map<int, int>>().lookup(4)), 2); + + Any b = a; + EXPECT_TRUE(b); + EXPECT_EQ((b.get<Map<int, int>>().lookup(4)), 2); + + Any c = std::move(a); + c = c; + EXPECT_TRUE(b); + EXPECT_EQ((c.get<Map<int, int>>().lookup(4)), 2); + + EXPECT_TRUE((a.get<Map<int, int>>().is_empty())); /* NOLINT: bugprone-use-after-move */ +} + +TEST(any, AssignAny) +{ + Any<> a = 5; + Any<> b = std::string("hello"); + Any c; + + Any z; + EXPECT_FALSE(z.has_value()); + + z = a; + EXPECT_TRUE(z.has_value()); + EXPECT_EQ(z.get<int>(), 5); + + z = b; + EXPECT_EQ(z.get<std::string>(), "hello"); + + z = c; + EXPECT_FALSE(z.has_value()); + + z = Any(std::in_place_type<Any<>>, a); + EXPECT_FALSE(z.is<int>()); + EXPECT_TRUE(z.is<Any<>>()); + EXPECT_EQ(z.get<Any<>>().get<int>(), 5); +} + +struct ExtraSizeInfo { + size_t size; + + template<typename T> static ExtraSizeInfo get() + { + return {sizeof(T)}; + } +}; + +TEST(any, ExtraInfo) +{ + using MyAny = Any<ExtraSizeInfo>; + + MyAny a = 5; + EXPECT_EQ(a.extra_info().size, sizeof(int)); + + a = std::string("hello"); + EXPECT_EQ(a.extra_info().size, sizeof(std::string)); +} + +} // namespace blender::tests diff --git a/source/blender/blenlib/tests/BLI_listbase_test.cc b/source/blender/blenlib/tests/BLI_listbase_test.cc index 0ba08a0cd48..d66eb214902 100644 --- a/source/blender/blenlib/tests/BLI_listbase_test.cc +++ b/source/blender/blenlib/tests/BLI_listbase_test.cc @@ -96,6 +96,64 @@ TEST(listbase, FindLinkOrIndex) BLI_freelistN(&lb); } +TEST(listbase, FindLinkFromStringOrPointer) +{ + struct TestLink { + struct TestLink *prev, *next; + char name[64]; + const void *ptr; + }; + + const char *const link1_name = "Link1"; + const char *const link2_name = "Link2"; + const void *const link1_ptr = nullptr; + const void *const link2_ptr = link2_name; + + const size_t name_offset = offsetof(struct TestLink, name); + const size_t ptr_offset = offsetof(struct TestLink, ptr); + + ListBase lb; + struct TestLink *link1 = (struct TestLink *)MEM_callocN(sizeof(TestLink), "link1"); + BLI_strncpy(link1->name, link1_name, sizeof(link1->name)); + link1->ptr = link1_ptr; + struct TestLink *link2 = (struct TestLink *)MEM_callocN(sizeof(TestLink), "link2"); + BLI_strncpy(link2->name, link2_name, sizeof(link2->name)); + link2->ptr = link2_ptr; + + /* Empty list */ + BLI_listbase_clear(&lb); + EXPECT_EQ(BLI_findptr(&lb, link1_ptr, ptr_offset), (void *)nullptr); + EXPECT_EQ(BLI_findstring(&lb, link1_name, name_offset), (void *)nullptr); + EXPECT_EQ(BLI_rfindptr(&lb, link1_ptr, ptr_offset), (void *)nullptr); + EXPECT_EQ(BLI_rfindstring(&lb, link1_name, name_offset), (void *)nullptr); + EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, link1_name, name_offset, 0), (void *)nullptr); + + /* One link */ + BLI_addtail(&lb, link1); + EXPECT_EQ(BLI_findptr(&lb, link1_ptr, ptr_offset), (void *)link1); + EXPECT_EQ(BLI_findstring(&lb, link1_name, name_offset), (void *)link1); + EXPECT_EQ(BLI_rfindptr(&lb, link1_ptr, ptr_offset), (void *)link1); + EXPECT_EQ(BLI_rfindstring(&lb, link1_name, name_offset), (void *)link1); + EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, link1_name, name_offset, 0), (void *)link1); + EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, "", name_offset, 0), (void *)link1); + EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, nullptr, name_offset, 0), (void *)link1); + EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, nullptr, name_offset, 1), (void *)nullptr); + + /* Two links */ + BLI_addtail(&lb, link2); + EXPECT_EQ(BLI_findptr(&lb, link1_ptr, ptr_offset), (void *)link1); + EXPECT_EQ(BLI_findstring(&lb, link1_name, name_offset), (void *)link1); + EXPECT_EQ(BLI_rfindptr(&lb, link1_ptr, ptr_offset), (void *)link1); + EXPECT_EQ(BLI_rfindstring(&lb, link1_name, name_offset), (void *)link1); + EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, link1_name, name_offset, 0), (void *)link1); + EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, link2_name, name_offset, 0), (void *)link2); + EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, nullptr, name_offset, 0), (void *)link1); + EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, nullptr, name_offset, 1), (void *)link2); + EXPECT_EQ(BLI_listbase_string_or_index_find(&lb, nullptr, name_offset, -1), (void *)nullptr); + + BLI_freelistN(&lb); +} + /* -------------------------------------------------------------------- */ /* Sort utilities & test */ diff --git a/source/blender/blenlib/tests/BLI_virtual_array_test.cc b/source/blender/blenlib/tests/BLI_virtual_array_test.cc index a6d2ca10315..7a548e7c434 100644 --- a/source/blender/blenlib/tests/BLI_virtual_array_test.cc +++ b/source/blender/blenlib/tests/BLI_virtual_array_test.cc @@ -12,7 +12,7 @@ namespace blender::tests { TEST(virtual_array, Span) { std::array<int, 5> data = {3, 4, 5, 6, 7}; - VArray_For_Span<int> varray{data}; + VArray<int> varray = VArray<int>::ForSpan(data); EXPECT_EQ(varray.size(), 5); EXPECT_EQ(varray.get(0), 3); EXPECT_EQ(varray.get(4), 7); @@ -23,7 +23,7 @@ TEST(virtual_array, Span) TEST(virtual_array, Single) { - VArray_For_Single<int> varray{10, 4}; + VArray<int> varray = VArray<int>::ForSingle(10, 4); EXPECT_EQ(varray.size(), 4); EXPECT_EQ(varray.get(0), 10); EXPECT_EQ(varray.get(3), 10); @@ -35,7 +35,7 @@ TEST(virtual_array, Array) { Array<int> array = {1, 2, 3, 5, 8}; { - VArray_For_ArrayContainer varray{array}; + VArray<int> varray = VArray<int>::ForContainer(array); EXPECT_EQ(varray.size(), 5); EXPECT_EQ(varray[0], 1); EXPECT_EQ(varray[2], 3); @@ -43,7 +43,7 @@ TEST(virtual_array, Array) EXPECT_TRUE(varray.is_span()); } { - VArray_For_ArrayContainer varray{std::move(array)}; + VArray<int> varray = VArray<int>::ForContainer(std::move(array)); EXPECT_EQ(varray.size(), 5); EXPECT_EQ(varray[0], 1); EXPECT_EQ(varray[2], 3); @@ -51,7 +51,7 @@ TEST(virtual_array, Array) EXPECT_TRUE(varray.is_span()); } { - VArray_For_ArrayContainer varray{array}; /* NOLINT: bugprone-use-after-move */ + VArray<int> varray = VArray<int>::ForContainer(array); /* NOLINT: bugprone-use-after-move */ EXPECT_TRUE(varray.is_empty()); } } @@ -59,7 +59,7 @@ TEST(virtual_array, Array) TEST(virtual_array, Vector) { Vector<int> vector = {9, 8, 7, 6}; - VArray_For_ArrayContainer varray{std::move(vector)}; + VArray<int> varray = VArray<int>::ForContainer(std::move(vector)); EXPECT_EQ(varray.size(), 4); EXPECT_EQ(varray[0], 9); EXPECT_EQ(varray[3], 6); @@ -68,7 +68,7 @@ TEST(virtual_array, Vector) TEST(virtual_array, StdVector) { std::vector<int> vector = {5, 6, 7, 8}; - VArray_For_ArrayContainer varray{std::move(vector)}; + VArray<int> varray = VArray<int>::ForContainer(std::move(vector)); EXPECT_EQ(varray.size(), 4); EXPECT_EQ(varray[0], 5); EXPECT_EQ(varray[1], 6); @@ -77,7 +77,7 @@ TEST(virtual_array, StdVector) TEST(virtual_array, StdArray) { std::array<int, 4> array = {2, 3, 4, 5}; - VArray_For_ArrayContainer varray{array}; + VArray<int> varray = VArray<int>::ForContainer(std::move(array)); EXPECT_EQ(varray.size(), 4); EXPECT_EQ(varray[0], 2); EXPECT_EQ(varray[1], 3); @@ -86,7 +86,7 @@ TEST(virtual_array, StdArray) TEST(virtual_array, VectorSet) { VectorSet<int> vector_set = {5, 3, 7, 3, 3, 5, 1}; - VArray_For_ArrayContainer varray{std::move(vector_set)}; + VArray<int> varray = VArray<int>::ForContainer(std::move(vector_set)); EXPECT_TRUE(vector_set.is_empty()); /* NOLINT: bugprone-use-after-move. */ EXPECT_EQ(varray.size(), 4); EXPECT_EQ(varray[0], 5); @@ -98,7 +98,7 @@ TEST(virtual_array, VectorSet) TEST(virtual_array, Func) { auto func = [](int64_t index) { return (int)(index * index); }; - VArray_For_Func<int, decltype(func)> varray{10, func}; + VArray<int> varray = VArray<int>::ForFunc(10, func); EXPECT_EQ(varray.size(), 10); EXPECT_EQ(varray[0], 0); EXPECT_EQ(varray[3], 9); @@ -108,7 +108,7 @@ TEST(virtual_array, Func) TEST(virtual_array, AsSpan) { auto func = [](int64_t index) { return (int)(10 * index); }; - VArray_For_Func<int, decltype(func)> func_varray{10, func}; + VArray<int> func_varray = VArray<int>::ForFunc(10, func); VArray_Span span_varray{func_varray}; EXPECT_EQ(span_varray.size(), 10); Span<int> span = span_varray; @@ -134,13 +134,14 @@ TEST(virtual_array, DerivedSpan) vector.append({3, 4, 5}); vector.append({1, 1, 1}); { - VArray_For_DerivedSpan<std::array<int, 3>, int, get_x> varray{vector}; + VArray<int> varray = VArray<int>::ForDerivedSpan<std::array<int, 3>, get_x>(vector); EXPECT_EQ(varray.size(), 2); EXPECT_EQ(varray[0], 3); EXPECT_EQ(varray[1], 1); } { - VMutableArray_For_DerivedSpan<std::array<int, 3>, int, get_x, set_x> varray{vector}; + VMutableArray<int> varray = + VMutableArray<int>::ForDerivedSpan<std::array<int, 3>, get_x, set_x>(vector); EXPECT_EQ(varray.size(), 2); EXPECT_EQ(varray[0], 3); EXPECT_EQ(varray[1], 1); @@ -151,4 +152,32 @@ TEST(virtual_array, DerivedSpan) } } +TEST(virtual_array, MutableToImmutable) +{ + std::array<int, 4> array = {4, 2, 6, 4}; + { + VMutableArray<int> mutable_varray = VMutableArray<int>::ForSpan(array); + VArray<int> varray = mutable_varray; + EXPECT_TRUE(varray.is_span()); + EXPECT_EQ(varray.size(), 4); + EXPECT_EQ(varray[1], 2); + EXPECT_EQ(mutable_varray.size(), 4); + } + { + VMutableArray<int> mutable_varray = VMutableArray<int>::ForSpan(array); + EXPECT_EQ(mutable_varray.size(), 4); + VArray<int> varray = std::move(mutable_varray); + EXPECT_TRUE(varray.is_span()); + EXPECT_EQ(varray.size(), 4); + EXPECT_EQ(varray[1], 2); + EXPECT_EQ(mutable_varray.size(), 0); + } + { + VArray<int> varray = VMutableArray<int>::ForSpan(array); + EXPECT_TRUE(varray.is_span()); + EXPECT_EQ(varray.size(), 4); + EXPECT_EQ(varray[1], 2); + } +} + } // namespace blender::tests diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h index 5a919ae3605..e3a8fd2bf3f 100644 --- a/source/blender/blenloader/BLO_readfile.h +++ b/source/blender/blenloader/BLO_readfile.h @@ -124,7 +124,7 @@ typedef struct BlendFileReadReport { /* Number of proxies that failed to convert to library overrides. */ int proxies_to_lib_overrides_failures; /* Number of sequencer strips that were not read because were in non-supported channels. */ - int vse_strips_skipped; + int sequence_strips_skipped; } count; /* Number of libraries which had overrides that needed to be resynced, and a single linked list @@ -241,7 +241,7 @@ typedef enum eBLOLibLinkFlags { * #BLO_library_link_begin, #BLO_library_link_named_part & #BLO_library_link_end. * Wrap these in parameters since it's important both functions receive matching values. */ -struct LibraryLink_Params { +typedef struct LibraryLink_Params { /** The current main database, e.g. #G_MAIN or `CTX_data_main(C)`. */ struct Main *bmain; /** Options for linking, used for instantiating. */ @@ -257,7 +257,7 @@ struct LibraryLink_Params { /** The active 3D viewport (only used to define local-view). */ const struct View3D *v3d; } context; -}; +} LibraryLink_Params; void BLO_library_link_params_init(struct LibraryLink_Params *params, struct Main *bmain, diff --git a/source/blender/blenloader/BLO_writefile.h b/source/blender/blenloader/BLO_writefile.h index 746c663926d..bac0119a368 100644 --- a/source/blender/blenloader/BLO_writefile.h +++ b/source/blender/blenloader/BLO_writefile.h @@ -24,6 +24,10 @@ * \brief external writefile function prototypes. */ +#ifdef __cplusplus +extern "C" { +#endif + struct BlendThumbnail; struct Main; struct MemFile; @@ -72,3 +76,7 @@ extern bool BLO_write_file_mem(struct Main *mainvar, int write_flags); /** \} */ + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt index 89631588ed0..b3df5c8aa67 100644 --- a/source/blender/blenloader/CMakeLists.txt +++ b/source/blender/blenloader/CMakeLists.txt @@ -34,6 +34,7 @@ set(INC ../sequencer ../windowmanager ../../../intern/clog + ../../../intern/ghost ../../../intern/guardedalloc # for writefile.c: dna_type_offsets.h diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index f82b7970a60..888bd244007 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -1435,6 +1435,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { view_layer->cryptomatte_levels = 6; + view_layer->cryptomatte_flag = VIEW_LAYER_CRYPTOMATTE_ACCURATE; } } } diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c index 47d919c151f..125f3be0dd1 100644 --- a/source/blender/blenloader/intern/versioning_300.c +++ b/source/blender/blenloader/intern/versioning_300.c @@ -22,6 +22,8 @@ #include <string.h> +#include "CLG_log.h" + #include "MEM_guardedalloc.h" #include "BLI_listbase.h" @@ -46,6 +48,7 @@ #include "DNA_workspace_types.h" #include "BKE_action.h" +#include "BKE_anim_data.h" #include "BKE_animsys.h" #include "BKE_armature.h" #include "BKE_asset.h" @@ -55,6 +58,7 @@ #include "BKE_fcurve_driver.h" #include "BKE_idprop.h" #include "BKE_lib_id.h" +#include "BKE_lib_override.h" #include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_node.h" @@ -68,11 +72,14 @@ #include "SEQ_iterator.h" #include "SEQ_sequencer.h" +#include "SEQ_time.h" #include "RNA_access.h" #include "versioning_common.h" +static CLG_LogRef LOG = {"blo.readfile.doversion"}; + static IDProperty *idproperty_find_ui_container(IDProperty *idprop_group) { LISTBASE_FOREACH (IDProperty *, prop, &idprop_group->data.group) { @@ -645,6 +652,10 @@ void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports)) } } + if (!MAIN_VERSION_ATLEAST(bmain, 300, 25)) { + version_node_socket_index_animdata(bmain, NTREE_SHADER, SH_NODE_BSDF_PRINCIPLED, 4, 2, 25); + } + if (!MAIN_VERSION_ATLEAST(bmain, 300, 26)) { LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { ToolSettings *tool_settings = scene->toolsettings; @@ -779,8 +790,6 @@ void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports)) */ { /* Keep this block, even when empty. */ - - version_node_socket_index_animdata(bmain, NTREE_SHADER, SH_NODE_BSDF_PRINCIPLED, 4, 2, 25); } } @@ -1270,6 +1279,161 @@ static void version_geometry_nodes_set_position_node_offset(bNodeTree *ntree) } } +static void version_node_tree_socket_id_delim(bNodeTree *ntree) +{ + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { + version_node_socket_id_delim(socket); + } + LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) { + version_node_socket_id_delim(socket); + } + } +} + +static bool version_fix_seq_meta_range(Sequence *seq, void *user_data) +{ + Scene *scene = (Scene *)user_data; + if (seq->type == SEQ_TYPE_META) { + SEQ_time_update_meta_strip_range(scene, seq); + } + return true; +} + +/* Those `version_liboverride_rnacollections_*` functions mimic the old, pre-3.0 code to find + * anchor and source items in the given list of modifiers, constraints etc., using only the + * `subitem_local` data of the override property operation. + * + * Then they convert it into the new, proper `subitem_reference` data for the anchor, and + * `subitem_local` for the source. + * + * NOTE: Here only the stored override ID is available, unlike in the `override_apply` functions. + */ + +static void version_liboverride_rnacollections_insertion_object_constraints( + ListBase *constraints, IDOverrideLibraryProperty *op) +{ + LISTBASE_FOREACH_MUTABLE (IDOverrideLibraryPropertyOperation *, opop, &op->operations) { + if (opop->operation != IDOVERRIDE_LIBRARY_OP_INSERT_AFTER) { + continue; + } + bConstraint *constraint_anchor = BLI_listbase_string_or_index_find(constraints, + opop->subitem_local_name, + offsetof(bConstraint, name), + opop->subitem_local_index); + if (constraint_anchor == NULL || constraint_anchor->next == NULL) { + /* Invalid case, just remove that override property operation. */ + CLOG_ERROR(&LOG, "Could not find anchor or source constraints in stored override data"); + BKE_lib_override_library_property_operation_delete(op, opop); + continue; + } + bConstraint *constraint_src = constraint_anchor->next; + opop->subitem_reference_name = opop->subitem_local_name; + opop->subitem_local_name = BLI_strdup(constraint_src->name); + opop->subitem_reference_index = opop->subitem_local_index; + opop->subitem_local_index++; + } +} + +static void version_liboverride_rnacollections_insertion_object(Object *object) +{ + IDOverrideLibrary *liboverride = object->id.override_library; + IDOverrideLibraryProperty *op; + + op = BKE_lib_override_library_property_find(liboverride, "modifiers"); + if (op != NULL) { + LISTBASE_FOREACH_MUTABLE (IDOverrideLibraryPropertyOperation *, opop, &op->operations) { + if (opop->operation != IDOVERRIDE_LIBRARY_OP_INSERT_AFTER) { + continue; + } + ModifierData *mod_anchor = BLI_listbase_string_or_index_find(&object->modifiers, + opop->subitem_local_name, + offsetof(ModifierData, name), + opop->subitem_local_index); + if (mod_anchor == NULL || mod_anchor->next == NULL) { + /* Invalid case, just remove that override property operation. */ + CLOG_ERROR(&LOG, "Could not find anchor or source modifiers in stored override data"); + BKE_lib_override_library_property_operation_delete(op, opop); + continue; + } + ModifierData *mod_src = mod_anchor->next; + opop->subitem_reference_name = opop->subitem_local_name; + opop->subitem_local_name = BLI_strdup(mod_src->name); + opop->subitem_reference_index = opop->subitem_local_index; + opop->subitem_local_index++; + } + } + + op = BKE_lib_override_library_property_find(liboverride, "grease_pencil_modifiers"); + if (op != NULL) { + LISTBASE_FOREACH_MUTABLE (IDOverrideLibraryPropertyOperation *, opop, &op->operations) { + if (opop->operation != IDOVERRIDE_LIBRARY_OP_INSERT_AFTER) { + continue; + } + GpencilModifierData *gp_mod_anchor = BLI_listbase_string_or_index_find( + &object->greasepencil_modifiers, + opop->subitem_local_name, + offsetof(GpencilModifierData, name), + opop->subitem_local_index); + if (gp_mod_anchor == NULL || gp_mod_anchor->next == NULL) { + /* Invalid case, just remove that override property operation. */ + CLOG_ERROR(&LOG, "Could not find anchor GP modifier in stored override data"); + BKE_lib_override_library_property_operation_delete(op, opop); + continue; + } + GpencilModifierData *gp_mod_src = gp_mod_anchor->next; + opop->subitem_reference_name = opop->subitem_local_name; + opop->subitem_local_name = BLI_strdup(gp_mod_src->name); + opop->subitem_reference_index = opop->subitem_local_index; + opop->subitem_local_index++; + } + } + + op = BKE_lib_override_library_property_find(liboverride, "constraints"); + if (op != NULL) { + version_liboverride_rnacollections_insertion_object_constraints(&object->constraints, op); + } + + if (object->pose != NULL) { + LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { + char rna_path[FILE_MAXFILE]; + BLI_snprintf(rna_path, sizeof(rna_path), "pose.bones[\"%s\"].constraints", pchan->name); + op = BKE_lib_override_library_property_find(liboverride, rna_path); + if (op != NULL) { + version_liboverride_rnacollections_insertion_object_constraints(&pchan->constraints, op); + } + } + } +} + +static void version_liboverride_rnacollections_insertion_animdata(ID *id) +{ + AnimData *anim_data = BKE_animdata_from_id(id); + if (anim_data == NULL) { + return; + } + + IDOverrideLibrary *liboverride = id->override_library; + IDOverrideLibraryProperty *op; + + op = BKE_lib_override_library_property_find(liboverride, "animation_data.nla_tracks"); + if (op != NULL) { + LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &op->operations) { + if (opop->operation != IDOVERRIDE_LIBRARY_OP_INSERT_AFTER) { + continue; + } + /* NLA tracks are only referenced by index, which limits possibilities, basically they are + * always added at the end of the list, see #rna_NLA_tracks_override_apply. + * + * This makes things simple here. */ + opop->subitem_reference_name = opop->subitem_local_name; + opop->subitem_local_name = NULL; + opop->subitem_reference_index = opop->subitem_local_index; + opop->subitem_local_index++; + } + } +} + /* NOLINTNEXTLINE: readability-function-size */ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) { @@ -2146,6 +2310,81 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } } + if (!MAIN_VERSION_ATLEAST(bmain, 300, 42)) { + /* Use consistent socket identifiers for the math node. + * The code to make unique identifiers from the names was inconsistent. */ + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + if (ntree->type != NTREE_CUSTOM) { + version_node_tree_socket_id_delim(ntree); + } + } + FOREACH_NODETREE_END; + + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + if (sl->spacetype == SPACE_SEQ) { + ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase : + &sl->regionbase; + LISTBASE_FOREACH (ARegion *, region, regionbase) { + if (region->regiontype == RGN_TYPE_WINDOW) { + region->v2d.min[1] = 1.0f; + } + } + } + } + } + } + + /* Change minimum zoom to 0.05f in the node editor. */ + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + if (sl->spacetype == SPACE_NODE) { + ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase : + &sl->regionbase; + LISTBASE_FOREACH (ARegion *, region, regionbase) { + if (region->regiontype == RGN_TYPE_WINDOW) { + if (region->v2d.minzoom > 0.05f) { + region->v2d.minzoom = 0.05f; + } + } + } + } + } + } + } + + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + Editing *ed = SEQ_editing_get(scene); + /* Make sure range of meta strips is correct. + * It was possible to save .blend file with incorrect state of meta strip + * range. The root cause is expected to be fixed, but need to ensure files + * with invalid meta strip range are corrected. */ + if (ed != NULL) { + SEQ_for_each_callback(&ed->seqbase, version_fix_seq_meta_range, scene); + } + } + } + + /* Special case to handle older in-dev 3.1 files, before change from 3.0 branch gets merged in + * master. */ + if (!MAIN_VERSION_ATLEAST(bmain, 300, 42) || + (bmain->versionfile == 301 && !MAIN_VERSION_ATLEAST(bmain, 301, 3))) { + /* Update LibOverride operations regarding insertions in RNA collections (i.e. modifiers, + * constraints and NLA tracks). */ + ID *id_iter; + FOREACH_MAIN_ID_BEGIN (bmain, id_iter) { + if (ID_IS_OVERRIDE_LIBRARY_REAL(id_iter)) { + version_liboverride_rnacollections_insertion_animdata(id_iter); + if (GS(id_iter->name) == ID_OB) { + version_liboverride_rnacollections_insertion_object((Object *)id_iter); + } + } + } + FOREACH_MAIN_ID_END; + } + /** * Versioning code until next subversion bump goes here. * diff --git a/source/blender/blenloader/intern/versioning_common.cc b/source/blender/blenloader/intern/versioning_common.cc index c7ff496fa20..af765be619f 100644 --- a/source/blender/blenloader/intern/versioning_common.cc +++ b/source/blender/blenloader/intern/versioning_common.cc @@ -27,6 +27,7 @@ #include "BLI_listbase.h" #include "BLI_string.h" +#include "BLI_string_ref.hh" #include "BKE_animsys.h" #include "BKE_lib_id.h" @@ -37,6 +38,8 @@ #include "versioning_common.h" +using blender::StringRef; + ARegion *do_versions_add_region_if_not_found(ListBase *regionbase, int region_type, const char *name, @@ -101,6 +104,30 @@ static void change_node_socket_name(ListBase *sockets, const char *old_name, con } } +/** + * Convert `SocketName.001` unique name format to `SocketName_001`. Previously both were used. + */ +void version_node_socket_id_delim(bNodeSocket *socket) +{ + StringRef name = socket->name; + StringRef id = socket->identifier; + + if (!id.startswith(name)) { + /* We only need to affect the case where the identifier starts with the name. */ + return; + } + + StringRef id_number = id.drop_known_prefix(name); + if (id_number.is_empty()) { + /* The name was already unique, and didn't need numbers at the end for the id. */ + return; + } + + if (id_number.startswith(".")) { + socket->identifier[name.size()] = '_'; + } +} + void version_node_socket_name(bNodeTree *ntree, const int node_type, const char *old_name, @@ -127,9 +154,9 @@ void version_node_input_socket_name(bNodeTree *ntree, } void version_node_output_socket_name(bNodeTree *ntree, - const int node_type, - const char *old_name, - const char *new_name) + const int node_type, + const char *old_name, + const char *new_name) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->type == node_type) { diff --git a/source/blender/blenloader/intern/versioning_common.h b/source/blender/blenloader/intern/versioning_common.h index ed1cafdca33..7f179800ddd 100644 --- a/source/blender/blenloader/intern/versioning_common.h +++ b/source/blender/blenloader/intern/versioning_common.h @@ -62,6 +62,8 @@ void version_node_socket_index_animdata( void version_node_id(struct bNodeTree *ntree, const int node_type, const char *new_name); +void version_node_socket_id_delim(bNodeSocket *socket); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index 2d5d6479234..0e5e0b76f43 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -334,6 +334,9 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme) memcpy(btheme, &U_theme_default, sizeof(*btheme)); } + if (!USER_VERSION_ATLEAST(301, 2)) { + FROM_DEFAULT_V4_UCHAR(space_sequencer.mask); + } /** * Versioning code until next subversion bump goes here. * diff --git a/source/blender/blenloader/tests/blendfile_loading_base_test.cc b/source/blender/blenloader/tests/blendfile_loading_base_test.cc index f06f6f7d329..a4a5ced070d 100644 --- a/source/blender/blenloader/tests/blendfile_loading_base_test.cc +++ b/source/blender/blenloader/tests/blendfile_loading_base_test.cc @@ -48,6 +48,8 @@ #include "WM_api.h" #include "wm.h" +#include "GHOST_Path-api.h" + #include "CLG_log.h" void BlendfileLoadingBaseTest::SetUpTestCase() @@ -92,6 +94,7 @@ void BlendfileLoadingBaseTest::TearDownTestCase() RNA_exit(); DEG_free_node_types(); + GHOST_DisposeSystemPaths(); DNA_sdna_current_free(); BLI_threadapi_exit(); diff --git a/source/blender/bmesh/intern/bmesh_mesh_normals.c b/source/blender/bmesh/intern/bmesh_mesh_normals.c index 186c85abe58..8119d9eb57d 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_normals.c +++ b/source/blender/bmesh/intern/bmesh_mesh_normals.c @@ -404,16 +404,13 @@ void BM_normals_loops_edges_tag(BMesh *bm, const bool do_edges) */ static void bm_mesh_edges_sharp_tag(BMesh *bm, const float (*fnos)[3], - const float split_angle, + float split_angle_cos, const bool do_sharp_edges_tag) { BMIter eiter; BMEdge *e; int i; - const bool check_angle = (split_angle < (float)M_PI); - const float split_angle_cos = check_angle ? cosf(split_angle) : -1.0f; - if (fnos) { BM_mesh_elem_index_ensure(bm, BM_FACE); } @@ -451,7 +448,7 @@ void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle) return; } - bm_mesh_edges_sharp_tag(bm, NULL, split_angle, true); + bm_mesh_edges_sharp_tag(bm, NULL, cosf(split_angle), true); } /** \} */ @@ -1110,11 +1107,13 @@ static void bm_mesh_loops_calc_normals__single_threaded(BMesh *bm, const short (*clnors_data)[2], const int cd_loop_clnors_offset, const bool do_rebuild, - const float split_angle) + const float split_angle_cos) { BMIter fiter; BMFace *f_curr; const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1); + /* When false the caller must have already tagged the edges. */ + const bool do_edge_tag = (split_angle_cos != EDGE_TAG_FROM_SPLIT_ANGLE_BYPASS); MLoopNorSpaceArray _lnors_spacearr = {NULL}; @@ -1155,7 +1154,9 @@ static void bm_mesh_loops_calc_normals__single_threaded(BMesh *bm, /* Always tag edges based on winding & sharp edge flag * (even when the auto-smooth angle doesn't need to be calculated). */ - bm_mesh_edges_sharp_tag(bm, fnos, has_clnors ? (float)M_PI : split_angle, false); + if (do_edge_tag) { + bm_mesh_edges_sharp_tag(bm, fnos, has_clnors ? -1.0f : split_angle_cos, false); + } /* We now know edges that can be smoothed (they are tagged), * and edges that will be hard (they aren't). @@ -1308,12 +1309,9 @@ static void bm_mesh_loops_calc_normals__multi_threaded(BMesh *bm, const short (*clnors_data)[2], const int cd_loop_clnors_offset, const bool do_rebuild, - const float split_angle) + const float split_angle_cos) { const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1); - const bool check_angle = (split_angle < (float)M_PI); - const float split_angle_cos = check_angle ? cosf(split_angle) : -1.0f; - MLoopNorSpaceArray _lnors_spacearr = {NULL}; { @@ -1387,7 +1385,7 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, const short (*clnors_data)[2], const int cd_loop_clnors_offset, const bool do_rebuild, - const float split_angle) + const float split_angle_cos) { if (bm->totloop < BM_OMP_LIMIT) { bm_mesh_loops_calc_normals__single_threaded(bm, @@ -1398,7 +1396,7 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, clnors_data, cd_loop_clnors_offset, do_rebuild, - split_angle); + split_angle_cos); } else { bm_mesh_loops_calc_normals__multi_threaded(bm, @@ -1409,7 +1407,7 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, clnors_data, cd_loop_clnors_offset, do_rebuild, - split_angle); + split_angle_cos); } } @@ -1620,7 +1618,7 @@ static void bm_mesh_loops_custom_normals_set(BMesh *bm, /* Tag smooth edges and set lnos from vnos when they might be completely smooth... * When using custom loop normals, disable the angle feature! */ - bm_mesh_edges_sharp_tag(bm, fnos, (float)M_PI, false); + bm_mesh_edges_sharp_tag(bm, fnos, -1.0f, false); /* Finish computing lnos by accumulating face normals * in each fan of faces defined by sharp edges. */ @@ -1751,7 +1749,7 @@ void BM_loops_calc_normal_vcos(BMesh *bm, clnors_data, cd_loop_clnors_offset, do_rebuild, - has_clnors ? (float)M_PI : split_angle); + has_clnors ? -1.0f : cosf(split_angle)); } else { BLI_assert(!r_lnors_spacearr); @@ -2266,7 +2264,6 @@ bool BM_custom_loop_normals_to_vector_layer(BMesh *bm) } BM_lnorspace_update(bm); - BM_mesh_elem_index_ensure(bm, BM_LOOP); /* Create a loop normal layer. */ if (!CustomData_has_layer(&bm->ldata, CD_NORMAL)) { @@ -2278,14 +2275,15 @@ bool BM_custom_loop_normals_to_vector_layer(BMesh *bm) const int cd_custom_normal_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); const int cd_normal_offset = CustomData_get_offset(&bm->ldata, CD_NORMAL); + int l_index = 0; BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - const int l_index = BM_elem_index_get(l); const short *clnors_data = BM_ELEM_CD_GET_VOID_P(l, cd_custom_normal_offset); float *normal = BM_ELEM_CD_GET_VOID_P(l, cd_normal_offset); BKE_lnor_space_custom_data_to_normal( bm->lnor_spacearr->lspacearr[l_index], clnors_data, normal); + l_index += 1; } } diff --git a/source/blender/compositor/operations/COM_CompositorOperation.cc b/source/blender/compositor/operations/COM_CompositorOperation.cc index 354997ebd2e..696dbb1807c 100644 --- a/source/blender/compositor/operations/COM_CompositorOperation.cc +++ b/source/blender/compositor/operations/COM_CompositorOperation.cc @@ -155,7 +155,7 @@ void CompositorOperation::execute_region(rcti *rect, unsigned int /*tile_number* if (rd->mode & R_BORDER && rd->mode & R_CROP) { /** * When using cropped render result, need to re-position area of interest, - * so it'll natch bounds of render border within frame. By default, canvas + * so it'll match bounds of render border within frame. By default, canvas * will be centered between full frame and cropped frame, so we use such * scheme to map cropped coordinates to full-frame coordinates * diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c index ec149c6cffa..8a825a7c81f 100644 --- a/source/blender/draw/engines/basic/basic_engine.c +++ b/source/blender/draw/engines/basic/basic_engine.c @@ -38,7 +38,6 @@ #include "basic_engine.h" #include "basic_private.h" - #define BASIC_ENGINE "BLENDER_BASIC" /* *********** LISTS *********** */ @@ -107,14 +106,14 @@ static void basic_cache_init(void *vedata) BASIC_shaders_pointcloud_depth_conservative_sh_get(draw_ctx->sh_cfg) : BASIC_shaders_pointcloud_depth_sh_get(draw_ctx->sh_cfg); DRW_PASS_CREATE(psl->depth_pass_pointcloud[i], state | clip_state | infront_state); - stl->g_data->depth_pointcloud_shgrp[i] = grp = DRW_shgroup_create(sh, psl->depth_pass_pointcloud[i]); + stl->g_data->depth_pointcloud_shgrp[i] = grp = DRW_shgroup_create( + sh, psl->depth_pass_pointcloud[i]); DRW_shgroup_uniform_vec2(grp, "sizeViewport", DRW_viewport_size_get(), 1); DRW_shgroup_uniform_vec2(grp, "sizeViewportInv", DRW_viewport_invert_size_get(), 1); stl->g_data->depth_hair_shgrp[i] = grp = DRW_shgroup_create( BASIC_shaders_depth_sh_get(draw_ctx->sh_cfg), psl->depth_pass[i]); - sh = DRW_state_is_select() ? BASIC_shaders_depth_conservative_sh_get(draw_ctx->sh_cfg) : BASIC_shaders_depth_sh_get(draw_ctx->sh_cfg); state |= DRW_STATE_CULL_BACK; diff --git a/source/blender/draw/engines/eevee/eevee_cryptomatte.c b/source/blender/draw/engines/eevee/eevee_cryptomatte.c index 4c9ce9dbd65..1b8e967e38f 100644 --- a/source/blender/draw/engines/eevee/eevee_cryptomatte.c +++ b/source/blender/draw/engines/eevee/eevee_cryptomatte.c @@ -139,6 +139,8 @@ void EEVEE_cryptomatte_renderpasses_init(EEVEE_Data *vedata) g_data->cryptomatte_session = session; g_data->render_passes |= EEVEE_RENDER_PASS_CRYPTOMATTE | EEVEE_RENDER_PASS_VOLUME_LIGHT; + g_data->cryptomatte_accurate_mode = (view_layer->cryptomatte_flag & + VIEW_LAYER_CRYPTOMATTE_ACCURATE) != 0; } } @@ -403,6 +405,7 @@ void EEVEE_cryptomatte_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EE { EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_StorageList *stl = vedata->stl; + EEVEE_PrivateData *g_data = stl->g_data; EEVEE_EffectsInfo *effects = stl->effects; EEVEE_PassList *psl = vedata->psl; const DRWContextState *draw_ctx = DRW_context_state_get(); @@ -410,9 +413,10 @@ void EEVEE_cryptomatte_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EE const int cryptomatte_levels = view_layer->cryptomatte_levels; const int current_sample = effects->taa_current_sample; - /* Render samples used by cryptomatte are limited to the number of cryptomatte levels. This will - * reduce the overhead of downloading the GPU buffer and integrating it into the accum buffer. */ - if (current_sample < cryptomatte_levels) { + /* In accurate mode all render samples are evaluated. In inaccurate mode this is limited to the + * number of cryptomatte levels. This will reduce the overhead of downloading the GPU buffer and + * integrating it into the accum buffer. */ + if (g_data->cryptomatte_accurate_mode || current_sample < cryptomatte_levels) { static float clear_color[4] = {0.0}; GPU_framebuffer_bind(fbl->cryptomatte_fb); GPU_framebuffer_clear_color(fbl->cryptomatte_fb, clear_color); diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index 68975cff48c..fad9d21b660 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -122,7 +122,7 @@ void EEVEE_cache_populate(void *vedata, Object *ob) } if (DRW_object_is_renderable(ob) && (ob_visibility & OB_VISIBLE_SELF)) { - if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) { + if (ELEM(ob->type, OB_MESH, OB_SURF, OB_MBALL)) { EEVEE_materials_cache_populate(vedata, sldata, ob, &cast_shadow); } else if (ob->type == OB_HAIR) { diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index a627bcd9488..582540529a6 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -820,7 +820,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, !DRW_state_is_image_render(); /* First get materials for this mesh. */ - if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) { + if (ELEM(ob->type, OB_MESH, OB_SURF, OB_MBALL)) { const int materials_len = DRW_cache_object_material_count_get(ob); EeveeMaterialCache *matcache = BLI_array_alloca(matcache, materials_len); diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index eae5d161cc3..f51b4fa0127 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -1042,6 +1042,7 @@ typedef struct EEVEE_PrivateData { int aov_hash; int num_aovs_used; struct CryptomatteSession *cryptomatte_session; + bool cryptomatte_accurate_mode; EEVEE_CryptomatteSample *cryptomatte_accum_buffer; float *cryptomatte_download_buffer; diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c index 1484a480f80..5db0ca70dc9 100644 --- a/source/blender/draw/engines/eevee/eevee_render.c +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -240,7 +240,7 @@ void EEVEE_render_cache(void *vedata, } if (ob_visibility & OB_VISIBLE_SELF) { - if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) { + if (ELEM(ob->type, OB_MESH, OB_SURF, OB_MBALL)) { EEVEE_materials_cache_populate(vedata, sldata, ob, &cast_shadow); if (do_cryptomatte) { EEVEE_cryptomatte_cache_populate(data, sldata, ob); diff --git a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl index 93641443cac..41d6db7f726 100644 --- a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl @@ -56,7 +56,7 @@ vec2 get_ao_noise(void) { vec2 noise = texelfetch_noise_tex(gl_FragCoord.xy).xy; /* Decorrelate noise from AA. */ - /* TODO(fclem) we should use a more general approach for more random number dimentions. */ + /* TODO(fclem) we should use a more general approach for more random number dimensions. */ noise = fract(noise * 6.1803402007); return noise; } @@ -399,7 +399,7 @@ float specular_occlusion( /* Use the right occlusion. */ OcclusionData occlusion_load(vec3 vP, float custom_occlusion) { - /* Default to fully openned cone. */ + /* Default to fully opened cone. */ OcclusionData data = NO_OCCLUSION_DATA; #ifdef ENABLE_DEFERED_AO diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl index e5cbc487e93..311887cf2f5 100644 --- a/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl @@ -172,7 +172,7 @@ /* -------------------------------------------------------------------- */ /** \name Common cl_eval data * - * Eval data not dependant on input parameters. All might not be used but unused ones + * Eval data not dependent on input parameters. All might not be used but unused ones * will be optimized out. * \{ */ @@ -240,7 +240,7 @@ ClosureEvalCommon closure_Common_eval_init(ClosureInputCommon cl_in) /* -------------------------------------------------------------------- */ /** \name Loop data * - * Loop datas are conveniently packed into struct to make it future proof. + * Loop data is conveniently packed into struct to make it future proof. * \{ */ struct ClosureLightData { diff --git a/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl b/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl index c3325ec4286..77a1560f3a7 100644 --- a/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl @@ -79,7 +79,7 @@ vec2 btdf_lut(float cos_theta, float roughness, float ior) /* Baked IOR for GGX BRDF. */ const float specular = 1.0; const float eta_brdf = (2.0 / (1.0 - sqrt(0.08 * specular))) - 1.0; - /* Avoid harsh transition comming from ior == 1. */ + /* Avoid harsh transition coming from ior == 1. */ float f90 = fast_sqrt(saturate(f0 / (f0_from_ior(eta_brdf) * 0.25))); float fresnel = F_brdf_single_scatter(vec3(f0), vec3(f90), split_sum).r; /* Setting the BTDF to one is not really important since it is only used for multiscatter diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl index 39a7e8fb931..c09365cdcb4 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl @@ -2,7 +2,7 @@ /** * Gather pass: Convolve foreground and background parts in separate passes. * - * Using the min&max CoC tile buffer, we select the best apropriate method to blur the scene color. + * Using the min&max CoC tile buffer, we select the best appropriate method to blur the scene color. * A fast gather path is taken if there is not many CoC variation inside the tile. * * We sample using an octaweb sampling pattern. We randomize the kernel center and each ring diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_reduce_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_reduce_frag.glsl index 1b5b305dfc1..d21254003f9 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_dof_reduce_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_dof_reduce_frag.glsl @@ -140,7 +140,7 @@ void main() do_scatter *= dof_scatter_screen_border_rejection(outCoc, uv, halfres); /* Only scatter if neighborhood is different enough. */ do_scatter *= dof_scatter_neighborhood_rejection(outColor.rgb); - /* For debuging. */ + /* For debugging. */ do_scatter *= float(!no_scatter_pass); outScatterColor = mix(vec3(0.0), outColor.rgb, do_scatter); diff --git a/source/blender/draw/engines/eevee/shaders/effect_reflection_resolve_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_reflection_resolve_frag.glsl index 7689e730bf3..7568d70bd14 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_reflection_resolve_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_reflection_resolve_frag.glsl @@ -134,7 +134,7 @@ void raytrace_resolve(ClosureInputGlossy cl_in, vec3 V, P, N; if (planar_index != -1) { PlanarData pd = planars_data[planar_index]; - /* Evaluate everything in refected space. */ + /* Evaluate everything in reflected space. */ P = line_plane_intersect(cl_common.P, cl_common.V, pd.pl_plane_eq); V = reflect(cl_common.V, pd.pl_normal); N = reflect(cl_in.N, pd.pl_normal); diff --git a/source/blender/draw/engines/eevee/shaders/random_lib.glsl b/source/blender/draw/engines/eevee/shaders/random_lib.glsl index 3a4ae257bbe..c2388f61346 100644 --- a/source/blender/draw/engines/eevee/shaders/random_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/random_lib.glsl @@ -1,6 +1,6 @@ /** - * Random numbers and low discrepency sequences utilities. + * Random numbers and low discrepancy sequences utilities. */ #pragma BLENDER_REQUIRE(common_math_lib.glsl) diff --git a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl index 0efa7b80b0b..7d016d57c46 100644 --- a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl @@ -8,7 +8,7 @@ #if defined(STEP_RESOLVE) || defined(STEP_RAYTRACE) /* SSR will set these global variables itself. - * Also make false positive compiler warnings disapear by setting values. */ + * Also make false positive compiler warnings disappear by setting values. */ vec3 worldPosition = vec3(0); vec3 viewPosition = vec3(0); vec3 worldNormal = vec3(0); diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl index c48c3bffaef..777e48fde34 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl @@ -74,7 +74,7 @@ vec3 light_volume(LightData ld, vec4 l_vector) float d = l_vector.w; float d_sqr = sqr(d); float r_sqr = ld.l_volume_radius; - /* Using reformulation that has better numerical percision. */ + /* Using reformulation that has better numerical precision. */ power = 2.0 / (d_sqr + r_sqr + d * sqrt(d_sqr + r_sqr)); if (ld.l_type == AREA_RECT || ld.l_type == AREA_ELLIPSE) { diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h index 674aca29662..328e60cf60b 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.h +++ b/source/blender/draw/engines/gpencil/gpencil_engine.h @@ -106,7 +106,7 @@ typedef struct gpLight { BLI_STATIC_ASSERT_ALIGN(gpMaterial, 16) BLI_STATIC_ASSERT_ALIGN(gpLight, 16) -/* *********** Draw Datas *********** */ +/* *********** Draw Data *********** */ typedef struct GPENCIL_MaterialPool { /* Linklist. */ struct GPENCIL_MaterialPool *next; diff --git a/source/blender/draw/engines/image/image_drawing_mode.hh b/source/blender/draw/engines/image/image_drawing_mode.hh index f2f5bbe554c..d81b0971982 100644 --- a/source/blender/draw/engines/image/image_drawing_mode.hh +++ b/source/blender/draw/engines/image/image_drawing_mode.hh @@ -151,4 +151,3 @@ class DefaultDrawingMode : public AbstractDrawingMode { }; } // namespace blender::draw::image_engine - diff --git a/source/blender/draw/engines/image/image_engine.h b/source/blender/draw/engines/image/image_engine.h index feee599971e..f7e2f53d41b 100644 --- a/source/blender/draw/engines/image/image_engine.h +++ b/source/blender/draw/engines/image/image_engine.h @@ -31,4 +31,3 @@ extern DrawEngineType draw_engine_image_type; #ifdef __cplusplus } #endif - diff --git a/source/blender/draw/engines/image/image_private.hh b/source/blender/draw/engines/image/image_private.hh index 2b3ae7dc3bd..a62cd882e40 100644 --- a/source/blender/draw/engines/image/image_private.hh +++ b/source/blender/draw/engines/image/image_private.hh @@ -194,4 +194,3 @@ void IMAGE_shader_library_ensure(void); void IMAGE_shader_free(void); } // namespace blender::draw::image_engine - diff --git a/source/blender/draw/engines/image/image_space_image.hh b/source/blender/draw/engines/image/image_space_image.hh index 9c868dbcd1a..7728a963254 100644 --- a/source/blender/draw/engines/image/image_space_image.hh +++ b/source/blender/draw/engines/image/image_space_image.hh @@ -180,4 +180,3 @@ class SpaceImageAccessor : public AbstractSpaceAccessor { }; } // namespace blender::draw::image_engine - diff --git a/source/blender/draw/engines/image/image_space_node.hh b/source/blender/draw/engines/image/image_space_node.hh index e70aaaebf84..3ca18eec742 100644 --- a/source/blender/draw/engines/image/image_space_node.hh +++ b/source/blender/draw/engines/image/image_space_node.hh @@ -136,4 +136,3 @@ class SpaceNodeAccessor : public AbstractSpaceAccessor { }; } // namespace blender::draw::image_engine - diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c index 98db7136398..a2362cd8850 100644 --- a/source/blender/draw/engines/overlay/overlay_extra.c +++ b/source/blender/draw/engines/overlay/overlay_extra.c @@ -762,10 +762,7 @@ void OVERLAY_lightprobe_cache_populate(OVERLAY_Data *vedata, Object *ob) instdata.mat[1][3] = prb->grid_resolution_y; instdata.mat[2][3] = prb->grid_resolution_z; /* Put theme id in matrix. */ - if (UNLIKELY(ob->base_flag & BASE_FROM_DUPLI)) { - instdata.mat[3][3] = 0.0; - } - else if (theme_id == TH_ACTIVE) { + if (theme_id == TH_ACTIVE) { instdata.mat[3][3] = 1.0; } else /* TH_SELECT */ { diff --git a/source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl index 3f537eb3db3..d137286c63e 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl @@ -10,9 +10,6 @@ vec4 color_from_id(float color_id) if (isTransform) { return colorTransform; } - else if (color_id == 0.0) { - return colorDupliSelect; - } else if (color_id == 1.0) { return colorActive; } diff --git a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl index df10f3f7ae2..0e4757f8ea8 100644 --- a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl @@ -241,9 +241,6 @@ void main() else if (color_id == 1u) { fragColor = colorSelect; } - else if (color_id == 2u) { - fragColor = colorDupliSelect; - } else if (color_id == 3u) { fragColor = colorActive; } diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl b/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl index 582a7c6cae2..701760dac18 100644 --- a/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl @@ -17,18 +17,8 @@ flat out uint objectId; uint outline_colorid_get(void) { int flag = int(abs(ObjectInfo.w)); - bool is_from_dupli = (flag & DRW_BASE_FROM_DUPLI) != 0; bool is_active = (flag & DRW_BASE_ACTIVE) != 0; - if (is_from_dupli) { - if (isTransform) { - return 0u; /* colorTransform */ - } - else { - return 2u; /* colorDupliSelect */ - } - } - if (isTransform) { return 0u; /* colorTransform */ } diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl index 977bce466b9..fa32ef9e31b 100644 --- a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl @@ -28,27 +28,12 @@ void wire_color_get(out vec3 rim_col, out vec3 wire_col) { int flag = int(abs(ObjectInfo.w)); bool is_selected = (flag & DRW_BASE_SELECTED) != 0; - bool is_from_dupli = (flag & DRW_BASE_FROM_DUPLI) != 0; bool is_from_set = (flag & DRW_BASE_FROM_SET) != 0; bool is_active = (flag & DRW_BASE_ACTIVE) != 0; if (is_from_set) { - rim_col = colorDupli.rgb; - wire_col = colorDupli.rgb; - } - else if (is_from_dupli) { - if (is_selected) { - if (isTransform) { - rim_col = colorTransform.rgb; - } - else { - rim_col = colorDupliSelect.rgb; - } - } - else { - rim_col = colorDupli.rgb; - } - wire_col = colorDupli.rgb; + rim_col = colorWire.rgb; + wire_col = colorWire.rgb; } else if (is_selected && useColoring) { if (isTransform) { diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl index 92d5df1a13a..c4580e6ffc3 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl @@ -95,7 +95,7 @@ void main() /** * ----------------- STEP 0.5 ------------------ - * Custom Coc aware downsampling. Quater res pass. + * Custom Coc aware downsampling. Quarter res pass. */ #ifdef DOWNSAMPLE diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c index a5281427fa8..4706aeb4477 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.c +++ b/source/blender/draw/engines/workbench/workbench_engine.c @@ -379,7 +379,7 @@ void workbench_cache_populate(void *ved, Object *ob) return; } - if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_POINTCLOUD)) { + if (ELEM(ob->type, OB_MESH, OB_SURF, OB_MBALL, OB_POINTCLOUD)) { bool use_sculpt_pbvh, use_texpaint_mode, draw_shadow, has_transp_mat = false; eV3DShadingColorType color_type = workbench_color_type_get( wpd, ob, &use_sculpt_pbvh, &use_texpaint_mode, &draw_shadow); diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c index 62d715460bb..2cbea2ae6d5 100644 --- a/source/blender/draw/intern/draw_common.c +++ b/source/blender/draw/intern/draw_common.c @@ -101,11 +101,6 @@ void DRW_globals_update(void) gb->colorEditMeshMiddle, dot_v3v3(gb->colorEditMeshMiddle, (float[3]){0.3333f, 0.3333f, 0.3333f})); /* Desaturate */ - interp_v4_v4v4(gb->colorDupliSelect, gb->colorBackground, gb->colorSelect, 0.5f); - /* Was 50% in 2.7x since the background was lighter making it easier to tell the color from - * black, with a darker background we need a more faded color. */ - interp_v4_v4v4(gb->colorDupli, gb->colorBackground, gb->colorWire, 0.3f); - #ifdef WITH_FREESTYLE UI_GetThemeColor4fv(TH_FREESTYLE_EDGE_MARK, gb->colorEdgeFreestyle); UI_GetThemeColor4fv(TH_FREESTYLE_FACE_MARK, gb->colorFaceFreestyle); @@ -300,7 +295,11 @@ int DRW_object_wire_theme_get(Object *ob, ViewLayer *view_layer, float **r_color { const DRWContextState *draw_ctx = DRW_context_state_get(); const bool is_edit = (draw_ctx->object_mode & OB_MODE_EDIT) && (ob->mode & OB_MODE_EDIT); - const bool active = (view_layer->basact && view_layer->basact->object == ob); + const bool active = view_layer->basact && + ((ob->base_flag & BASE_FROM_DUPLI) ? + (DRW_object_get_dupli_parent(ob) == view_layer->basact->object) : + (view_layer->basact->object == ob)); + /* confusing logic here, there are 2 methods of setting the color * 'colortab[colindex]' and 'theme_id', colindex overrides theme_id. * @@ -345,21 +344,7 @@ int DRW_object_wire_theme_get(Object *ob, ViewLayer *view_layer, float **r_color if (r_color != NULL) { if (UNLIKELY(ob->base_flag & BASE_FROM_SET)) { - *r_color = G_draw.block.colorDupli; - } - else if (UNLIKELY(ob->base_flag & BASE_FROM_DUPLI)) { - switch (theme_id) { - case TH_ACTIVE: - case TH_SELECT: - *r_color = G_draw.block.colorDupliSelect; - break; - case TH_TRANSFORM: - *r_color = G_draw.block.colorTransform; - break; - default: - *r_color = G_draw.block.colorDupli; - break; - } + *r_color = G_draw.block.colorWire; } else { switch (theme_id) { diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h index 2913877c9c1..48a3fb209ba 100644 --- a/source/blender/draw/intern/draw_common.h +++ b/source/blender/draw/intern/draw_common.h @@ -43,8 +43,6 @@ typedef struct GlobalsUboStorage { float colorWireEdit[4]; float colorActive[4]; float colorSelect[4]; - float colorDupliSelect[4]; - float colorDupli[4]; float colorLibrarySelect[4]; float colorLibrary[4]; float colorTransform[4]; diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index 1da8bcb5b91..42d61c881b0 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -538,7 +538,12 @@ static void drw_call_obinfos_init(DRWObjectInfos *ob_infos, Object *ob) ob_infos->ob_flag += (ob->base_flag & BASE_SELECTED) ? (1 << 1) : 0; ob_infos->ob_flag += (ob->base_flag & BASE_FROM_DUPLI) ? (1 << 2) : 0; ob_infos->ob_flag += (ob->base_flag & BASE_FROM_SET) ? (1 << 3) : 0; - ob_infos->ob_flag += (ob == DST.draw_ctx.obact) ? (1 << 4) : 0; + if (ob->base_flag & BASE_FROM_DUPLI) { + ob_infos->ob_flag += (DRW_object_get_dupli_parent(ob) == DST.draw_ctx.obact) ? (1 << 4) : 0; + } + else { + ob_infos->ob_flag += (ob == DST.draw_ctx.obact) ? (1 << 4) : 0; + } /* Negative scaling. */ ob_infos->ob_flag *= (ob->transflag & OB_NEG_SCALE) ? -1.0f : 1.0f; /* Object Color. */ diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc index 9edefe32fbc..8a5a8134ca7 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc @@ -172,6 +172,18 @@ static void init_vbo_for_attribute(const MeshRenderData *mr, GPUVertFormat format = {0}; GPU_vertformat_deinterleave(&format); GPU_vertformat_attr_add(&format, attr_name, comp_type, comp_size, fetch_mode); + + /* Ensure Sculpt Vertex Colors are properly aliased. */ + if (request.cd_type == CD_PROP_COLOR && request.domain == ATTR_DOMAIN_POINT) { + CustomData *cd_vdata = get_custom_data_for_domain(mr, ATTR_DOMAIN_POINT); + if (request.layer_index == CustomData_get_render_layer(cd_vdata, CD_PROP_COLOR)) { + GPU_vertformat_alias_add(&format, "c"); + } + if (request.layer_index == CustomData_get_active_layer(cd_vdata, CD_PROP_COLOR)) { + GPU_vertformat_alias_add(&format, "ac"); + } + } + GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, static_cast<uint32_t>(mr->loop_len)); } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc index 1f8776fc98e..7a3b2cf49ff 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc @@ -54,11 +54,18 @@ static void extract_tan_ex_init(const MeshRenderData *mr, uint32_t tan_layers = cache->cd_used.tan; float(*orco)[3] = (float(*)[3])CustomData_get_layer(cd_vdata, CD_ORCO); bool orco_allocated = false; - const bool use_orco_tan = cache->cd_used.tan_orco != 0; + bool use_orco_tan = cache->cd_used.tan_orco != 0; int tan_len = 0; char tangent_names[MAX_MTFACE][MAX_CUSTOMDATA_LAYER_NAME]; + /* FIXME(T91838): This is to avoid a crash when orco tangent was requested but there are valid + * uv layers. It would be better to fix the root cause. */ + if (tan_layers == 0 && use_orco_tan && CustomData_get_layer_index(cd_ldata, CD_MLOOPUV) != -1) { + tan_layers = 1; + use_orco_tan = false; + } + for (int i = 0; i < MAX_MTFACE; i++) { if (tan_layers & (1 << i)) { char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; diff --git a/source/blender/draw/intern/shaders/common_globals_lib.glsl b/source/blender/draw/intern/shaders/common_globals_lib.glsl index 3c76c8a5b28..77b34543989 100644 --- a/source/blender/draw/intern/shaders/common_globals_lib.glsl +++ b/source/blender/draw/intern/shaders/common_globals_lib.glsl @@ -7,8 +7,6 @@ layout(std140) uniform globalsBlock vec4 colorWireEdit; vec4 colorActive; vec4 colorSelect; - vec4 colorDupliSelect; - vec4 colorDupli; vec4 colorLibrarySelect; vec4 colorLibrary; vec4 colorTransform; diff --git a/source/blender/draw/tests/shaders_test.cc b/source/blender/draw/tests/shaders_test.cc index 0156615d10c..e955e2edf62 100644 --- a/source/blender/draw/tests/shaders_test.cc +++ b/source/blender/draw/tests/shaders_test.cc @@ -13,12 +13,12 @@ #include "intern/draw_manager_testing.h" +#include "engines/basic/basic_private.h" #include "engines/eevee/eevee_private.h" #include "engines/gpencil/gpencil_engine.h" #include "engines/image/image_private.hh" #include "engines/overlay/overlay_private.h" #include "engines/workbench/workbench_private.h" -#include "engines/basic/basic_private.h" #include "intern/draw_shader.h" namespace blender::draw { diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index e5dc9a83ebb..9f2681fbf7a 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -199,7 +199,7 @@ static void acf_generic_channel_color(bAnimContext *ac, bAnimListElem *ale, floa } /* set color for normal channels - * - use 3 shades of color group/standard color for 3 indention level + * - use 3 shades of color group/standard color for 3 indentation level * - only use group colors if allowed to, and if actually feasible */ if (showGroupColors && (grp) && (grp->customCol)) { diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index e1d046428a8..da5d5543136 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -1900,7 +1900,8 @@ static size_t animdata_filter_gpencil(bAnimContext *ac, if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) { /* Layer visibility - we check both object and base, * since these may not be in sync yet. */ - if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) { + if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0 || + (base->flag & BASE_VISIBLE_VIEWLAYER) == 0) { continue; } diff --git a/source/blender/editors/animation/anim_motion_paths.c b/source/blender/editors/animation/anim_motion_paths.c index 0d812198d04..335034fef6e 100644 --- a/source/blender/editors/animation/anim_motion_paths.c +++ b/source/blender/editors/animation/anim_motion_paths.c @@ -176,11 +176,11 @@ static void motionpaths_calc_bake_targets(ListBase *targets, int cframe) copy_v3_v3(mpv->co, pchan_eval->pose_tail); } - /* result must be in worldspace */ + /* Result must be in world-space. */ mul_m4_v3(ob_eval->obmat, mpv->co); } else { - /* worldspace object location */ + /* World-space object location. */ copy_v3_v3(mpv->co, ob_eval->obmat[3]); } diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index 8232df968ed..1e60a129535 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -149,7 +149,7 @@ static void change_frame_apply(bContext *C, wmOperator *op) bool do_snap = RNA_boolean_get(op->ptr, "snap"); if (do_snap) { - if (CTX_wm_space_seq(C)) { + if (CTX_wm_space_seq(C) && SEQ_editing_get(scene) != NULL) { frame = seq_frame_apply_snap(C, scene, frame); } else { diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index 32fd1c9ad41..b06e4b6a9e7 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -745,6 +745,10 @@ void ARMATURE_OT_separate(wmOperatorType *ot) #define ARM_PAR_CONNECT 1 #define ARM_PAR_OFFSET 2 +/* armature un-parenting options */ +#define ARM_PAR_CLEAR 1 +#define ARM_PAR_CLEAR_DISCONNECT 2 + /* check for null, before calling! */ static void bone_connect_to_existing_parent(EditBone *bone) { @@ -904,19 +908,29 @@ static int armature_parent_set_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { - bool all_childbones = false; + /* False when all selected bones are parented to the active bone. */ + bool enable_offset = false; + /* False when all selected bones are connected to the active bone. */ + bool enable_connect = false; { Object *ob = CTX_data_edit_object(C); bArmature *arm = ob->data; EditBone *actbone = arm->act_edbone; LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) { - if (EBONE_EDITABLE(ebone) && (ebone->flag & BONE_SELECTED)) { - if (ebone != actbone) { - if (ebone->parent != actbone) { - all_childbones = true; - break; - } - } + if (!EBONE_EDITABLE(ebone) || !(ebone->flag & BONE_SELECTED)) { + continue; + } + if (ebone == actbone) { + continue; + } + + if (ebone->parent != actbone) { + enable_offset = true; + enable_connect = true; + break; + } + if (!(ebone->flag & BONE_CONNECTED)) { + enable_connect = true; } } } @@ -924,11 +938,14 @@ static int armature_parent_set_invoke(bContext *C, uiPopupMenu *pup = UI_popup_menu_begin( C, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Make Parent"), ICON_NONE); uiLayout *layout = UI_popup_menu_layout(pup); - uiItemEnumO(layout, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_CONNECT); - if (all_childbones) { - /* Object becomes parent, make the associated menus. */ - uiItemEnumO(layout, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_OFFSET); - } + + uiLayout *row_offset = uiLayoutRow(layout, false); + uiLayoutSetEnabled(row_offset, enable_offset); + uiItemEnumO(row_offset, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_OFFSET); + + uiLayout *row_connect = uiLayoutRow(layout, false); + uiLayoutSetEnabled(row_connect, enable_connect); + uiItemEnumO(row_connect, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_CONNECT); UI_popup_menu_end(C, pup); @@ -955,8 +972,8 @@ void ARMATURE_OT_parent_set(wmOperatorType *ot) } static const EnumPropertyItem prop_editarm_clear_parent_types[] = { - {1, "CLEAR", 0, "Clear Parent", ""}, - {2, "DISCONNECT", 0, "Disconnect Bone", ""}, + {ARM_PAR_CLEAR, "CLEAR", 0, "Clear Parent", ""}, + {ARM_PAR_CLEAR_DISCONNECT, "DISCONNECT", 0, "Disconnect Bone", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -1012,6 +1029,51 @@ static int armature_parent_clear_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static int armature_parent_clear_invoke(bContext *C, + wmOperator *UNUSED(op), + const wmEvent *UNUSED(event)) +{ + /* False when no selected bones are connected to the active bone. */ + bool enable_disconnect = false; + /* False when no selected bones are parented to the active bone. */ + bool enable_clear = false; + { + Object *ob = CTX_data_edit_object(C); + bArmature *arm = ob->data; + LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) { + if (!EBONE_EDITABLE(ebone) || !(ebone->flag & BONE_SELECTED)) { + continue; + } + if (ebone->parent == NULL) { + continue; + } + enable_clear = true; + + if (ebone->flag & BONE_CONNECTED) { + enable_disconnect = true; + break; + } + } + } + + uiPopupMenu *pup = UI_popup_menu_begin( + C, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Parent"), ICON_NONE); + uiLayout *layout = UI_popup_menu_layout(pup); + + uiLayout *row_clear = uiLayoutRow(layout, false); + uiLayoutSetEnabled(row_clear, enable_clear); + uiItemEnumO(row_clear, "ARMATURE_OT_parent_clear", NULL, 0, "type", ARM_PAR_CLEAR); + + uiLayout *row_disconnect = uiLayoutRow(layout, false); + uiLayoutSetEnabled(row_disconnect, enable_disconnect); + uiItemEnumO( + row_disconnect, "ARMATURE_OT_parent_clear", NULL, 0, "type", ARM_PAR_CLEAR_DISCONNECT); + + UI_popup_menu_end(C, pup); + + return OPERATOR_INTERFACE; +} + void ARMATURE_OT_parent_clear(wmOperatorType *ot) { /* identifiers */ @@ -1021,7 +1083,7 @@ void ARMATURE_OT_parent_clear(wmOperatorType *ot) "Remove the parent-child relationship between selected bones and their parents"; /* api callbacks */ - ot->invoke = WM_menu_invoke; + ot->invoke = armature_parent_clear_invoke; ot->exec = armature_parent_clear_exec; ot->poll = ED_operator_editarmature; diff --git a/source/blender/editors/armature/pose_lib_2.c b/source/blender/editors/armature/pose_lib_2.c index 002a4f74037..e7cbde0b239 100644 --- a/source/blender/editors/armature/pose_lib_2.c +++ b/source/blender/editors/armature/pose_lib_2.c @@ -562,7 +562,7 @@ static bool poselib_blend_poll(bContext *C) void POSELIB_OT_apply_pose_asset(wmOperatorType *ot) { /* Identifiers: */ - ot->name = "Apply Pose Library Pose"; + ot->name = "Apply Pose Asset"; ot->idname = "POSELIB_OT_apply_pose_asset"; ot->description = "Apply the given Pose Action to the rig"; @@ -595,7 +595,7 @@ void POSELIB_OT_blend_pose_asset(wmOperatorType *ot) PropertyRNA *prop; /* Identifiers: */ - ot->name = "Blend Pose Library Pose"; + ot->name = "Blend Pose Asset"; ot->idname = "POSELIB_OT_blend_pose_asset"; ot->description = "Blend the given Pose Action to the rig"; diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c index 279f79ac44b..70d6fa93104 100644 --- a/source/blender/editors/armature/pose_transform.c +++ b/source/blender/editors/armature/pose_transform.c @@ -797,13 +797,13 @@ static int pose_copy_exec(bContext *C, wmOperator *op) BLI_addtail(&temp_bmain->objects, &ob_copy); BLI_addtail(&temp_bmain->armatures, &arm_copy); /* begin copy buffer on a temp bmain. */ - BKE_copybuffer_begin(temp_bmain); + BKE_copybuffer_copy_begin(temp_bmain); /* Store the whole object to the copy buffer because pose can't be * existing on its own. */ - BKE_copybuffer_tag_ID(&ob_copy.id); + BKE_copybuffer_copy_tag_ID(&ob_copy.id); BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer_pose.blend"); - BKE_copybuffer_save(temp_bmain, str, op->reports); + BKE_copybuffer_copy_end(temp_bmain, str, op->reports); /* We clear the lists so no datablocks gets freed, * This is required because objects in temp bmain shares same pointers * as the real ones. diff --git a/source/blender/editors/asset/ED_asset_library.h b/source/blender/editors/asset/ED_asset_library.h index 905d097d223..cb055584364 100644 --- a/source/blender/editors/asset/ED_asset_library.h +++ b/source/blender/editors/asset/ED_asset_library.h @@ -28,7 +28,8 @@ extern "C" { int ED_asset_library_reference_to_enum_value(const AssetLibraryReference *library); AssetLibraryReference ED_asset_library_reference_from_enum_value(int value); -const struct EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf(void); +const struct EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf( + bool include_local_library); #ifdef __cplusplus } diff --git a/source/blender/editors/asset/intern/asset_library_reference_enum.cc b/source/blender/editors/asset/intern/asset_library_reference_enum.cc index 1a2d3f5837a..a97af1b1cf4 100644 --- a/source/blender/editors/asset/intern/asset_library_reference_enum.cc +++ b/source/blender/editors/asset/intern/asset_library_reference_enum.cc @@ -98,25 +98,30 @@ AssetLibraryReference ED_asset_library_reference_from_enum_value(int value) * * Since this is meant for UI display, skips non-displayable libraries, that is, libraries with an * empty name or path. + * + * \param include_local_library whether to include the "Current File" library or not. */ -const EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf() +const EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf( + const bool include_local_library) { - const EnumPropertyItem predefined_items[] = { - /* For the future. */ - // {ASSET_REPO_BUNDLED, "BUNDLED", 0, "Bundled", "Show the default user assets"}, - {ASSET_LIBRARY_LOCAL, - "LOCAL", - ICON_BLENDER, - "Current File", - "Show the assets currently available in this Blender session"}, - {0, nullptr, 0, nullptr, nullptr}, - }; - EnumPropertyItem *item = nullptr; int totitem = 0; - /* Add predefined items. */ - RNA_enum_items_add(&item, &totitem, predefined_items); + if (include_local_library) { + const EnumPropertyItem predefined_items[] = { + /* For the future. */ + // {ASSET_REPO_BUNDLED, "BUNDLED", 0, "Bundled", "Show the default user assets"}, + {ASSET_LIBRARY_LOCAL, + "LOCAL", + ICON_BLENDER, + "Current File", + "Show the assets currently available in this Blender session"}, + {0, nullptr, 0, nullptr, nullptr}, + }; + + /* Add predefined items. */ + RNA_enum_items_add(&item, &totitem, predefined_items); + } /* Add separator if needed. */ if (!BLI_listbase_is_empty(&U.asset_libraries)) { diff --git a/source/blender/editors/asset/intern/asset_ops.cc b/source/blender/editors/asset/intern/asset_ops.cc index f7c567c89f6..a228b275558 100644 --- a/source/blender/editors/asset/intern/asset_ops.cc +++ b/source/blender/editors/asset/intern/asset_ops.cc @@ -19,12 +19,19 @@ */ #include "BKE_asset_library.hh" +#include "BKE_bpath.h" #include "BKE_context.h" +#include "BKE_global.h" #include "BKE_lib_id.h" #include "BKE_main.h" +#include "BKE_preferences.h" #include "BKE_report.h" +#include "BLI_fileops.h" +#include "BLI_fnmatch.h" +#include "BLI_path_util.h" #include "ED_asset.h" +#include "ED_util.h" /* XXX needs access to the file list, should all be done via the asset system in future. */ #include "ED_fileselect.h" @@ -33,6 +40,10 @@ #include "WM_api.h" +#include "DNA_space_types.h" + +#include "BLO_writefile.h" + using namespace blender; /* -------------------------------------------------------------------- */ @@ -643,6 +654,240 @@ static void ASSET_OT_catalogs_save(struct wmOperatorType *ot) /* -------------------------------------------------------------------- */ +static bool could_be_asset_bundle(const Main *bmain); +static const bUserAssetLibrary *selected_asset_library(struct wmOperator *op); +static bool is_contained_in_selected_asset_library(struct wmOperator *op, const char *filepath); +static bool set_filepath_for_asset_lib(const Main *bmain, struct wmOperator *op); +static bool has_external_files(Main *bmain, struct ReportList *reports); + +static bool asset_bundle_install_poll(bContext *C) +{ + /* This operator only works when the asset browser is set to Current File. */ + const SpaceFile *sfile = CTX_wm_space_file(C); + if (!ED_fileselect_is_local_asset_library(sfile)) { + return false; + } + + const Main *bmain = CTX_data_main(C); + if (!could_be_asset_bundle(bmain)) { + return false; + } + + /* Check whether this file is already located inside any asset library. */ + const struct bUserAssetLibrary *asset_lib = BKE_preferences_asset_library_containing_path( + &U, bmain->name); + if (asset_lib) { + return false; + } + + return true; +} + +static int asset_bundle_install_invoke(struct bContext *C, + struct wmOperator *op, + const struct wmEvent * /*event*/) +{ + Main *bmain = CTX_data_main(C); + if (has_external_files(bmain, op->reports)) { + return OPERATOR_CANCELLED; + } + + WM_event_add_fileselect(C, op); + + /* Make the "Save As" dialog box default to "${ASSET_LIB_ROOT}/${CURRENT_FILE}.blend". */ + if (!set_filepath_for_asset_lib(bmain, op)) { + return OPERATOR_CANCELLED; + } + + return OPERATOR_RUNNING_MODAL; +} + +static int asset_bundle_install_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + if (has_external_files(bmain, op->reports)) { + return OPERATOR_CANCELLED; + } + + /* Check file path, copied from #wm_file_write(). */ + char filepath[PATH_MAX]; + RNA_string_get(op->ptr, "filepath", filepath); + const size_t len = strlen(filepath); + + if (len == 0) { + BKE_report(op->reports, RPT_ERROR, "Path is empty, cannot save"); + return OPERATOR_CANCELLED; + } + + if (len >= FILE_MAX) { + BKE_report(op->reports, RPT_ERROR, "Path too long, cannot save"); + return OPERATOR_CANCELLED; + } + + /* Check that the destination is actually contained in the selected asset library. */ + if (!is_contained_in_selected_asset_library(op, filepath)) { + BKE_reportf(op->reports, RPT_ERROR, "Selected path is outside of the selected asset library"); + return OPERATOR_CANCELLED; + } + + WM_cursor_wait(true); + bke::AssetCatalogService *cat_service = get_catalog_service(C); + /* Store undo step, such that on a failed save the 'prepare_to_merge_on_write' call can be + * un-done. */ + cat_service->undo_push(); + cat_service->prepare_to_merge_on_write(); + + const int operator_result = WM_operator_name_call( + C, "WM_OT_save_mainfile", WM_OP_EXEC_DEFAULT, op->ptr); + WM_cursor_wait(false); + + if (operator_result != OPERATOR_FINISHED) { + cat_service->undo(); + return operator_result; + } + + const bUserAssetLibrary *lib = selected_asset_library(op); + BLI_assert_msg(lib, "If the asset library is not known, how did we get here?"); + BKE_reportf(op->reports, + RPT_INFO, + R"(Saved "%s" to asset library "%s")", + BLI_path_basename(bmain->name), + lib->name); + return OPERATOR_FINISHED; +} + +static const EnumPropertyItem *rna_asset_library_reference_itemf(bContext *UNUSED(C), + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) +{ + const EnumPropertyItem *items = ED_asset_library_reference_to_rna_enum_itemf(false); + if (!items) { + *r_free = false; + } + + *r_free = true; + return items; +} + +static void ASSET_OT_bundle_install(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Copy to Asset Library"; + ot->description = + "Copy the current .blend file into an Asset Library. Only works on standalone .blend files " + "(i.e. when no other files are referenced)"; + ot->idname = "ASSET_OT_bundle_install"; + + /* api callbacks */ + ot->exec = asset_bundle_install_exec; + ot->invoke = asset_bundle_install_invoke; + ot->poll = asset_bundle_install_poll; + + ot->prop = RNA_def_property(ot->srna, "asset_library_ref", PROP_ENUM, PROP_NONE); + RNA_def_property_flag(ot->prop, PROP_HIDDEN); + RNA_def_enum_funcs(ot->prop, rna_asset_library_reference_itemf); + + WM_operator_properties_filesel(ot, + FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, + FILE_BLENDER, + FILE_SAVE, + WM_FILESEL_FILEPATH, + FILE_DEFAULTDISPLAY, + FILE_SORT_DEFAULT); +} + +/* Cheap check to see if this is an "asset bundle" just by checking main file name. + * A proper check will be done in the exec function, to ensure that no external files will be + * referenced. */ +static bool could_be_asset_bundle(const Main *bmain) +{ + return fnmatch("*_bundle.blend", bmain->name, FNM_CASEFOLD) == 0; +} + +static const bUserAssetLibrary *selected_asset_library(struct wmOperator *op) +{ + const int enum_value = RNA_enum_get(op->ptr, "asset_library_ref"); + const AssetLibraryReference lib_ref = ED_asset_library_reference_from_enum_value(enum_value); + const bUserAssetLibrary *lib = BKE_preferences_asset_library_find_from_index( + &U, lib_ref.custom_library_index); + return lib; +} + +static bool is_contained_in_selected_asset_library(struct wmOperator *op, const char *filepath) +{ + const bUserAssetLibrary *lib = selected_asset_library(op); + if (!lib) { + return false; + } + return BLI_path_contains(lib->path, filepath); +} + +/** + * Set the "filepath" RNA property based on selected "asset_library_ref". + * \return true if ok, false if error. + */ +static bool set_filepath_for_asset_lib(const Main *bmain, struct wmOperator *op) +{ + /* Find the directory path of the selected asset library. */ + const bUserAssetLibrary *lib = selected_asset_library(op); + if (lib == nullptr) { + return false; + } + + /* Concatenate the filename of the current blend file. */ + const char *blend_filename = BLI_path_basename(bmain->name); + if (blend_filename == nullptr || blend_filename[0] == '\0') { + return false; + } + + char file_path[PATH_MAX]; + BLI_join_dirfile(file_path, sizeof(file_path), lib->path, blend_filename); + RNA_string_set(op->ptr, "filepath", file_path); + + return true; +} + +struct FileCheckCallbackInfo { + struct ReportList *reports; + bool external_file_found; +}; + +static bool external_file_check_callback(void *callback_info_ptr, + char * /*path_dst*/, + const char *path_src) +{ + FileCheckCallbackInfo *callback_info = static_cast<FileCheckCallbackInfo *>(callback_info_ptr); + BKE_reportf(callback_info->reports, + RPT_ERROR, + "Unable to install asset bundle, has external dependency \"%s\"", + path_src); + callback_info->external_file_found = true; + return false; +} + +/** + * Do a check on any external files (.blend, textures, etc.) being used. + * The "Install asset bundle" operator only works on standalone .blend files + * (catalog definition files are fine, though). + * + * \return true when there are external files, false otherwise. + */ +static bool has_external_files(Main *bmain, struct ReportList *reports) +{ + struct FileCheckCallbackInfo callback_info = {reports, false}; + + BKE_bpath_traverse_main( + bmain, + &external_file_check_callback, + BKE_BPATH_TRAVERSE_SKIP_PACKED /* Packed files are fine. */ + | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE /* Only report multifiles once, it's enough. */, + &callback_info); + return callback_info.external_file_found; +} + +/* -------------------------------------------------------------------- */ + void ED_operatortypes_asset(void) { WM_operatortype_append(ASSET_OT_mark); @@ -654,6 +899,7 @@ void ED_operatortypes_asset(void) WM_operatortype_append(ASSET_OT_catalog_undo); WM_operatortype_append(ASSET_OT_catalog_redo); WM_operatortype_append(ASSET_OT_catalog_undo_push); + WM_operatortype_append(ASSET_OT_bundle_install); WM_operatortype_append(ASSET_OT_list_refresh); } diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 46bf1f6c9b5..3b05975d22d 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -4909,7 +4909,9 @@ bool ED_curve_editnurb_select_pick( /** \name Spin Operator * \{ */ -/* 'cent' is in object space and 'dvec' in worldspace. +/** + * \param axis: is in world-space. + * \param cent: is in object-space. */ bool ed_editnurb_spin( float viewmat[4][4], View3D *v3d, Object *obedit, const float axis[3], const float cent[3]) diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c index 26906b0ddcd..784f67ac4f1 100644 --- a/source/blender/editors/curve/editcurve_paint.c +++ b/source/blender/editors/curve/editcurve_paint.c @@ -102,7 +102,7 @@ struct CurveDrawData { /* offset projection by this value */ bool use_offset; - float offset[3]; /* worldspace */ + float offset[3]; /* world-space */ float surface_offset; bool use_surface_offset_absolute; } project; diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c index bdb4e485373..bf53241a947 100644 --- a/source/blender/editors/gpencil/annotate_paint.c +++ b/source/blender/editors/gpencil/annotate_paint.c @@ -1195,7 +1195,7 @@ static void annotation_stroke_eraser_dostroke(tGPsdata *p, /* Second Pass: Remove any points that are tagged */ if (do_cull) { BKE_gpencil_stroke_delete_tagged_points( - p->gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, 0); + p->gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, false, 0); } } } diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index 406a7ac77fc..656fec565df 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -1834,7 +1834,7 @@ static int image_to_gpencil_exec(bContext *C, wmOperator *op) /* Delete any selected point. */ LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) { BKE_gpencil_stroke_delete_tagged_points( - gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0); + gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, false, 0); } BKE_reportf(op->reports, RPT_INFO, "Object created"); diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index f6012883e1f..3fc08096ab5 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -2635,7 +2635,7 @@ static int gpencil_delete_selected_points(bContext *C) else { /* delete unwanted points by splitting stroke into several smaller ones */ BKE_gpencil_stroke_delete_tagged_points( - gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0); + gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, false, 0); } changed = true; @@ -4656,11 +4656,11 @@ static int gpencil_stroke_separate_exec(bContext *C, wmOperator *op) /* delete selected points from destination stroke */ BKE_gpencil_stroke_delete_tagged_points( - gpd_dst, gpf_dst, gps_dst, NULL, GP_SPOINT_SELECT, false, 0); + gpd_dst, gpf_dst, gps_dst, NULL, GP_SPOINT_SELECT, false, false, 0); /* delete selected points from origin stroke */ BKE_gpencil_stroke_delete_tagged_points( - gpd_src, gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0); + gpd_src, gpf, gps, gps->next, GP_SPOINT_SELECT, false, false, 0); } } /* selected strokes mode */ @@ -4839,11 +4839,11 @@ static int gpencil_stroke_split_exec(bContext *C, wmOperator *op) /* delete selected points from destination stroke */ BKE_gpencil_stroke_delete_tagged_points( - gpd, gpf, gps_dst, NULL, GP_SPOINT_SELECT, true, 0); + gpd, gpf, gps_dst, NULL, GP_SPOINT_SELECT, true, false, 0); /* delete selected points from origin stroke */ BKE_gpencil_stroke_delete_tagged_points( - gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0); + gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, false, 0); } } } @@ -5039,7 +5039,7 @@ static void gpencil_cutter_dissolve(bGPdata *gpd, } BKE_gpencil_stroke_delete_tagged_points( - gpd, hit_layer->actframe, hit_stroke, gpsn, GP_SPOINT_TAG, false, 1); + gpd, hit_layer->actframe, hit_stroke, gpsn, GP_SPOINT_TAG, false, flat_caps, 1); } } diff --git a/source/blender/editors/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c index 259b2882589..925c2e1cd7f 100644 --- a/source/blender/editors/gpencil/gpencil_merge.c +++ b/source/blender/editors/gpencil/gpencil_merge.c @@ -182,7 +182,8 @@ static void gpencil_dissolve_points(bContext *C) } LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) { - BKE_gpencil_stroke_delete_tagged_points(gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, 0); + BKE_gpencil_stroke_delete_tagged_points( + gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, false, 0); } } CTX_DATA_END; diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 8d72ea72532..f0118988559 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -1699,7 +1699,7 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p, } BKE_gpencil_stroke_delete_tagged_points( - p->gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, 0); + p->gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, false, 0); } gpencil_update_cache(p->gpd); } diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index f3c3aa10632..86df452f49a 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -3372,7 +3372,7 @@ bGPDstroke *ED_gpencil_stroke_join_and_trim( } /* Remove tagged points to trim stroke. */ gps_final = BKE_gpencil_stroke_delete_tagged_points( - gpd, gpf, gps_dst, gps_dst->next, GP_SPOINT_TAG, false, 0); + gpd, gpf, gps_dst, gps_dst->next, GP_SPOINT_TAG, false, false, 0); } /* Join both strokes. */ diff --git a/source/blender/editors/gpencil/gpencil_vertex_ops.c b/source/blender/editors/gpencil/gpencil_vertex_ops.c index 5c3a7cf9e6f..891bd3ca5ec 100644 --- a/source/blender/editors/gpencil/gpencil_vertex_ops.c +++ b/source/blender/editors/gpencil/gpencil_vertex_ops.c @@ -54,7 +54,7 @@ static const EnumPropertyItem gpencil_modesEnumPropertyItem_mode[] = { {GPPAINT_MODE_STROKE, "STROKE", 0, "Stroke", ""}, {GPPAINT_MODE_FILL, "FILL", 0, "Fill", ""}, - {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke and Fill", ""}, + {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke & Fill", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -1142,7 +1142,7 @@ void GPENCIL_OT_stroke_reset_vertex_color(wmOperatorType *ot) static EnumPropertyItem mode_types_items[] = { {GPPAINT_MODE_STROKE, "STROKE", 0, "Stroke", "Reset Vertex Color to Stroke only"}, {GPPAINT_MODE_FILL, "FILL", 0, "Fill", "Reset Vertex Color to Fill only"}, - {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke and Fill", "Reset Vertex Color to Stroke and Fill"}, + {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke & Fill", "Reset Vertex Color to Stroke and Fill"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/editors/include/ED_clip.h b/source/blender/editors/include/ED_clip.h index 21d8a28e2c9..4fa78eddec4 100644 --- a/source/blender/editors/include/ED_clip.h +++ b/source/blender/editors/include/ED_clip.h @@ -65,7 +65,7 @@ struct ImBuf *ED_space_clip_get_stable_buffer(struct SpaceClip *sc, float *angle); bool ED_space_clip_get_position(struct SpaceClip *sc, - struct ARegion *ar, + struct ARegion *region, int mval[2], float fpos[2]); bool ED_space_clip_color_sample(struct SpaceClip *sc, diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h index 68b6e44371c..c1936b2fde5 100644 --- a/source/blender/editors/include/ED_fileselect.h +++ b/source/blender/editors/include/ED_fileselect.h @@ -109,6 +109,7 @@ struct FileSelectParams *ED_fileselect_ensure_active_params(struct SpaceFile *sf struct FileSelectParams *ED_fileselect_get_active_params(const struct SpaceFile *sfile); struct FileSelectParams *ED_fileselect_get_file_params(const struct SpaceFile *sfile); struct FileAssetSelectParams *ED_fileselect_get_asset_params(const struct SpaceFile *sfile); +bool ED_fileselect_is_local_asset_library(const struct SpaceFile *sfile); void ED_fileselect_set_params_from_userdef(struct SpaceFile *sfile); void ED_fileselect_params_to_userdef(struct SpaceFile *sfile, diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 2b73194afb2..22de6ca15bf 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -422,7 +422,8 @@ void ED_mesh_uv_texture_ensure(struct Mesh *me, const char *name); int ED_mesh_uv_texture_add(struct Mesh *me, const char *name, const bool active_set, - const bool do_init); + const bool do_init, + struct ReportList *reports); bool ED_mesh_uv_texture_remove_index(struct Mesh *me, const int n); bool ED_mesh_uv_texture_remove_active(struct Mesh *me); bool ED_mesh_uv_texture_remove_named(struct Mesh *me, const char *name); @@ -432,7 +433,8 @@ bool ED_mesh_color_ensure(struct Mesh *me, const char *name); int ED_mesh_color_add(struct Mesh *me, const char *name, const bool active_set, - const bool do_init); + const bool do_init, + struct ReportList *reports); bool ED_mesh_color_remove_index(struct Mesh *me, const int n); bool ED_mesh_color_remove_active(struct Mesh *me); bool ED_mesh_color_remove_named(struct Mesh *me, const char *name); @@ -441,7 +443,8 @@ bool ED_mesh_sculpt_color_ensure(struct Mesh *me, const char *name); int ED_mesh_sculpt_color_add(struct Mesh *me, const char *name, const bool active_set, - const bool do_init); + const bool do_init, + struct ReportList *reports); bool ED_mesh_sculpt_color_remove_index(struct Mesh *me, const int n); bool ED_mesh_sculpt_color_remove_active(struct Mesh *me); bool ED_mesh_sculpt_color_remove_named(struct Mesh *me, const char *name); diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h index 5cdcbbab42a..2d042b8b0e3 100644 --- a/source/blender/editors/include/ED_render.h +++ b/source/blender/editors/include/ED_render.h @@ -82,6 +82,8 @@ typedef enum ePreviewRenderMethod { void ED_preview_ensure_dbase(void); void ED_preview_free_dbase(void); +bool ED_preview_id_is_supported(const struct ID *id); + void ED_preview_shader_job(const struct bContext *C, void *owner, struct ID *id, diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 38f607dddcb..008ad5b3203 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -588,8 +588,6 @@ float ED_view3d_radius_to_dist(const struct View3D *v3d, const bool use_aspect, const float radius); -void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], unsigned int pos); - /* Back-buffer select and draw support. */ void ED_view3d_backbuf_depth_validate(struct ViewContext *vc); int ED_view3d_backbuf_sample_size_clamp(struct ARegion *region, const float dist); @@ -840,6 +838,7 @@ void ED_view3d_gizmo_mesh_preselect_get_active(struct bContext *C, struct wmGizmo *gz, struct Base **r_base, struct BMElem **r_ele); +void ED_view3d_gizmo_mesh_preselect_clear(struct wmGizmo *gz); /* space_view3d.c */ void ED_view3d_buttons_region_layout_ex(const struct bContext *C, diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index 8a7df5b54ff..c3c296f89ca 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -944,9 +944,7 @@ DEF_ICON_COLOR(GPBRUSH_ERASE_SOFT) DEF_ICON_COLOR(GPBRUSH_ERASE_HARD) DEF_ICON_COLOR(GPBRUSH_ERASE_STROKE) -/* Vector Icons */ -DEF_ICON_VECTOR(SMALL_TRI_RIGHT_VEC) - +/* Vector icons. */ DEF_ICON_VECTOR(KEYTYPE_KEYFRAME_VEC) DEF_ICON_VECTOR(KEYTYPE_BREAKDOWN_VEC) DEF_ICON_VECTOR(KEYTYPE_EXTREME_VEC) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 207318de981..c587425c47f 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -245,10 +245,10 @@ enum { }; /* Default font size for normal text. */ -#define UI_DEFAULT_TEXT_POINTS 11 +#define UI_DEFAULT_TEXT_POINTS 11.0f /* Larger size used for title text. */ -#define UI_DEFAULT_TITLE_POINTS 11 +#define UI_DEFAULT_TITLE_POINTS 11.0f #define UI_PANEL_WIDTH 340 #define UI_COMPACT_PANEL_WIDTH 160 @@ -400,9 +400,8 @@ typedef enum { /** Resize handle (resize uilist). */ UI_BTYPE_GRIP = 57 << 9, UI_BTYPE_DECORATOR = 58 << 9, - UI_BTYPE_DATASETROW = 59 << 9, /* An item in a tree view. Parent items may be collapsible. */ - UI_BTYPE_TREEROW = 60 << 9, + UI_BTYPE_TREEROW = 59 << 9, } eButType; #define BUTTYPE (63 << 9) @@ -732,8 +731,8 @@ bool UI_block_is_search_only(const uiBlock *block); void UI_block_set_search_only(uiBlock *block, bool search_only); void UI_block_free(const struct bContext *C, uiBlock *block); -void UI_blocklist_free(const struct bContext *C, struct ListBase *lb); -void UI_blocklist_free_inactive(const struct bContext *C, struct ListBase *lb); +void UI_blocklist_free(const struct bContext *C, struct ARegion *region); +void UI_blocklist_free_inactive(const struct bContext *C, struct ARegion *region); void UI_screen_free_active_but(const struct bContext *C, struct bScreen *screen); void UI_block_region_set(uiBlock *block, struct ARegion *region); @@ -774,6 +773,7 @@ void UI_block_translate(uiBlock *block, int x, int y); int UI_but_return_value_get(uiBut *but); void UI_but_drag_set_id(uiBut *but, struct ID *id); +void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, const float scale); void UI_but_drag_set_asset(uiBut *but, const struct AssetHandle *asset, const char *path, @@ -1675,11 +1675,7 @@ int UI_searchbox_size_x(void); int UI_search_items_find_index(uiSearchItems *items, const char *name); void UI_but_hint_drawstr_set(uiBut *but, const char *string); -void UI_but_datasetrow_indentation_set(uiBut *but, int indentation); -void UI_but_datasetrow_component_set(uiBut *but, uint8_t geometry_component_type); -void UI_but_datasetrow_domain_set(uiBut *but, uint8_t attribute_domain); -uint8_t UI_but_datasetrow_component_get(uiBut *but); -uint8_t UI_but_datasetrow_domain_get(uiBut *but); + void UI_but_treerow_indentation_set(uiBut *but, int indentation); void UI_but_node_link_set(uiBut *but, struct bNodeSocket *socket, const float draw_color[4]); diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index c3a00bedaf8..61da496d344 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -39,10 +39,6 @@ typedef enum { #define BIFICONID_FIRST (ICON_NONE) -/* Removed icon no longer used, defined so that add-ons don't have to be \ - * updated. */ -#define ICON_SMALL_TRI_RIGHT_VEC (ICON_RIGHTARROW) - /* use to denote intentionally unset theme color */ #define TH_UNDEFINED -1 diff --git a/source/blender/editors/include/UI_tree_view.hh b/source/blender/editors/include/UI_tree_view.hh index 0d18eedeac9..8caf17741a7 100644 --- a/source/blender/editors/include/UI_tree_view.hh +++ b/source/blender/editors/include/UI_tree_view.hh @@ -217,15 +217,11 @@ class AbstractTreeViewItem : public TreeViewItemContainer { friend class TreeViewLayoutBuilder; public: - using IsActiveFn = std::function<bool()>; - private: bool is_open_ = false; bool is_active_ = false; bool is_renaming_ = false; - IsActiveFn is_active_fn_; - protected: /** This label is used for identifying an item (together with its parent's labels). */ std::string label_{}; @@ -239,11 +235,6 @@ class AbstractTreeViewItem : public TreeViewItemContainer { virtual void build_context_menu(bContext &C, uiLayout &column) const; virtual void on_activate(); - /** - * Set a custom callback to check if this item should be active. There's a version without - * arguments for checking if the item is currently in an active state. - */ - virtual void is_active(IsActiveFn is_active_fn); /** * Queries if the tree-view item supports renaming in principle. Renaming may still fail, e.g. if @@ -329,6 +320,17 @@ class AbstractTreeViewItem : public TreeViewItemContainer { */ void activate(); + /** + * If the result is not empty, it controls whether the item should be active or not, + * usually depending on the data that the view represents. + */ + virtual std::optional<bool> should_be_active() const; + + /** + * Return whether the item can be collapsed. Used to disable collapsing for items with children. + */ + virtual bool supports_collapsing() const; + private: static void rename_button_fn(bContext *, void *, char *); static AbstractTreeViewItem *find_tree_item_from_rename_button(const uiBut &but); @@ -416,6 +418,7 @@ class AbstractTreeViewItemDropController { */ class BasicTreeViewItem : public AbstractTreeViewItem { public: + using IsActiveFn = std::function<bool()>; using ActivateFn = std::function<void(BasicTreeViewItem &new_active)>; BIFIconID icon; @@ -423,7 +426,11 @@ class BasicTreeViewItem : public AbstractTreeViewItem { void build_row(uiLayout &row) override; void add_label(uiLayout &layout, StringRefNull label_override = ""); - void on_activate(ActivateFn fn); + void set_on_activate_fn(ActivateFn fn); + /** + * Set a custom callback to check if this item should be active. + */ + void set_is_active_fn(IsActiveFn fn); protected: /** @@ -433,9 +440,12 @@ class BasicTreeViewItem : public AbstractTreeViewItem { */ ActivateFn activate_fn_; + IsActiveFn is_active_fn_; + private: static void tree_row_click_fn(struct bContext *C, void *arg1, void *arg2); + std::optional<bool> should_be_active() const override; void on_activate() override; }; diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt index 84172c7efce..bc3075f9de8 100644 --- a/source/blender/editors/interface/CMakeLists.txt +++ b/source/blender/editors/interface/CMakeLists.txt @@ -66,14 +66,14 @@ set(SRC interface_region_menu_popup.c interface_region_popover.c interface_region_popup.c - interface_region_search.c + interface_region_search.cc interface_region_tooltip.c interface_regions.c interface_style.c interface_template_asset_view.cc interface_template_list.cc interface_template_attribute_search.cc - interface_template_search_menu.c + interface_template_search_menu.cc interface_template_search_operator.c interface_templates.c interface_undo.c diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 82ea218baba..55fab04e9a4 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -37,6 +37,7 @@ #include "DNA_workspace_types.h" #include "BLI_alloca.h" +#include "BLI_ghash.h" #include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_rect.h" @@ -1993,23 +1994,9 @@ void UI_block_end(const bContext *C, uiBlock *block) /* ************** BLOCK DRAWING FUNCTION ************* */ -void ui_fontscale(short *points, float aspect) +void ui_fontscale(float *points, float aspect) { - if (aspect < 0.9f || aspect > 1.1f) { - float pointsf = *points; - - /* For some reason scaling fonts goes too fast compared to widget size. */ - /* XXX(ton): not true anymore? */ - // aspect = sqrt(aspect); - pointsf /= aspect; - - if (aspect > 1.0f) { - *points = ceilf(pointsf); - } - else { - *points = floorf(pointsf); - } - } + *points /= aspect; } /* Project button or block (but==NULL) to pixels in region-space. */ @@ -2022,6 +2009,13 @@ static void ui_but_to_pixelrect(rcti *rect, const ARegion *region, uiBlock *bloc BLI_rcti_translate(rect, -region->winrct.xmin, -region->winrct.ymin); } +static bool ui_but_pixelrect_in_view(const ARegion *region, const rcti *rect) +{ + rcti rect_winspace = *rect; + BLI_rcti_translate(&rect_winspace, region->winrct.xmin, region->winrct.ymin); + return BLI_rcti_isect(®ion->winrct, &rect_winspace, NULL); +} + /* uses local copy of style, to scale things down, and allow widgets to change stuff */ void UI_block_draw(const bContext *C, uiBlock *block) { @@ -2095,14 +2089,20 @@ void UI_block_draw(const bContext *C, uiBlock *block) /* widgets */ LISTBASE_FOREACH (uiBut *, but, &block->buttons) { - if (!(but->flag & (UI_HIDDEN | UI_SCROLLED))) { - ui_but_to_pixelrect(&rect, region, block, but); + if (but->flag & (UI_HIDDEN | UI_SCROLLED)) { + continue; + } - /* XXX: figure out why invalid coordinates happen when closing render window */ - /* and material preview is redrawn in main window (temp fix for bug T23848) */ - if (rect.xmin < rect.xmax && rect.ymin < rect.ymax) { - ui_draw_but(C, region, &style, but, &rect); - } + ui_but_to_pixelrect(&rect, region, block, but); + /* Optimization: Don't draw buttons that are not visible (outside view bounds). */ + if (!ui_but_pixelrect_in_view(region, &rect)) { + continue; + } + + /* XXX: figure out why invalid coordinates happen when closing render window */ + /* and material preview is redrawn in main window (temp fix for bug T23848) */ + if (rect.xmin < rect.xmax && rect.ymin < rect.ymax) { + ui_draw_but(C, region, &style, but, &rect); } } @@ -3522,22 +3522,35 @@ void UI_blocklist_draw(const bContext *C, const ListBase *lb) } /* can be called with C==NULL */ -void UI_blocklist_free(const bContext *C, ListBase *lb) +void UI_blocklist_free(const bContext *C, ARegion *region) { + ListBase *lb = ®ion->uiblocks; uiBlock *block; while ((block = BLI_pophead(lb))) { UI_block_free(C, block); } + if (region->runtime.block_name_map != NULL) { + BLI_ghash_free(region->runtime.block_name_map, NULL, NULL); + region->runtime.block_name_map = NULL; + } } -void UI_blocklist_free_inactive(const bContext *C, ListBase *lb) +void UI_blocklist_free_inactive(const bContext *C, ARegion *region) { + ListBase *lb = ®ion->uiblocks; + LISTBASE_FOREACH_MUTABLE (uiBlock *, block, lb) { if (!block->handle) { if (block->active) { block->active = false; } else { + if (region->runtime.block_name_map != NULL) { + uiBlock *b = BLI_ghash_lookup(region->runtime.block_name_map, block->name); + if (b == block) { + BLI_ghash_remove(region->runtime.block_name_map, b->name, NULL, NULL); + } + } BLI_remlink(lb, block); UI_block_free(C, block); } @@ -3553,7 +3566,10 @@ void UI_block_region_set(uiBlock *block, ARegion *region) /* each listbase only has one block with this name, free block * if is already there so it can be rebuilt from scratch */ if (lb) { - oldblock = BLI_findstring(lb, block->name, offsetof(uiBlock, name)); + if (region->runtime.block_name_map == NULL) { + region->runtime.block_name_map = BLI_ghash_str_new(__func__); + } + oldblock = (uiBlock *)BLI_ghash_lookup(region->runtime.block_name_map, block->name); if (oldblock) { oldblock->active = false; @@ -3563,6 +3579,7 @@ void UI_block_region_set(uiBlock *block, ARegion *region) /* at the beginning of the list! for dynamical menus/blocks */ BLI_addhead(lb, block); + BLI_ghash_reinsert(region->runtime.block_name_map, block->name, block, NULL, NULL); } block->oldblock = oldblock; @@ -3978,10 +3995,6 @@ static void ui_but_alloc_info(const eButType type, alloc_size = sizeof(uiButCurveProfile); alloc_str = "uiButCurveProfile"; break; - case UI_BTYPE_DATASETROW: - alloc_size = sizeof(uiButDatasetRow); - alloc_str = "uiButDatasetRow"; - break; case UI_BTYPE_TREEROW: alloc_size = sizeof(uiButTreeRow); alloc_str = "uiButTreeRow"; @@ -4184,7 +4197,6 @@ static uiBut *ui_def_but(uiBlock *block, UI_BTYPE_BLOCK, UI_BTYPE_BUT_MENU, UI_BTYPE_SEARCH_MENU, - UI_BTYPE_DATASETROW, UI_BTYPE_TREEROW, UI_BTYPE_POPOVER)) { but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT); @@ -6226,6 +6238,16 @@ void UI_but_drag_set_id(uiBut *but, ID *id) } /** + * Set an image to display while dragging. This works for any drag type (`WM_DRAG_XXX`). + * Not to be confused with #UI_but_drag_set_image(), which sets up dragging of an image. + */ +void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, const float scale) +{ + but->imb = imb; + but->imb_scale = scale; +} + +/** * \param asset: May be passed from a temporary variable, drag data only stores a copy of this. */ void UI_but_drag_set_asset(uiBut *but, @@ -6253,8 +6275,7 @@ void UI_but_drag_set_asset(uiBut *but, } but->dragpoin = asset_drag; but->dragflag |= UI_BUT_DRAGPOIN_FREE; - but->imb = imb; - but->imb_scale = scale; + UI_but_drag_attach_image(but, imb, scale); } void UI_but_drag_set_rna(uiBut *but, PointerRNA *ptr) @@ -6309,8 +6330,7 @@ void UI_but_drag_set_image( if (use_free) { but->dragflag |= UI_BUT_DRAGPOIN_FREE; } - but->imb = imb; - but->imb_scale = scale; + UI_but_drag_attach_image(but, imb, scale); } PointerRNA *UI_but_operator_ptr_get(uiBut *but) @@ -6917,15 +6937,6 @@ uiBut *uiDefSearchButO_ptr(uiBlock *block, return but; } -void UI_but_datasetrow_indentation_set(uiBut *but, int indentation) -{ - uiButDatasetRow *but_dataset = (uiButDatasetRow *)but; - BLI_assert(but->type == UI_BTYPE_DATASETROW); - - but_dataset->indentation = indentation; - BLI_assert(indentation >= 0); -} - void UI_but_treerow_indentation_set(uiBut *but, int indentation) { uiButTreeRow *but_row = (uiButTreeRow *)but; @@ -6943,38 +6954,6 @@ void UI_but_hint_drawstr_set(uiBut *but, const char *string) ui_but_add_shortcut(but, string, false); } -void UI_but_datasetrow_component_set(uiBut *but, uint8_t geometry_component_type) -{ - uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but; - BLI_assert(but->type == UI_BTYPE_DATASETROW); - - but_dataset_row->geometry_component_type = geometry_component_type; -} - -void UI_but_datasetrow_domain_set(uiBut *but, uint8_t attribute_domain) -{ - uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but; - BLI_assert(but->type == UI_BTYPE_DATASETROW); - - but_dataset_row->attribute_domain = attribute_domain; -} - -uint8_t UI_but_datasetrow_component_get(uiBut *but) -{ - uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but; - BLI_assert(but->type == UI_BTYPE_DATASETROW); - - return but_dataset_row->geometry_component_type; -} - -uint8_t UI_but_datasetrow_domain_get(uiBut *but) -{ - uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but; - BLI_assert(but->type == UI_BTYPE_DATASETROW); - - return but_dataset_row->attribute_domain; -} - void UI_but_node_link_set(uiBut *but, bNodeSocket *socket, const float draw_color[4]) { but->flag |= UI_BUT_NODE_LINK; diff --git a/source/blender/editors/interface/interface_context_path.cc b/source/blender/editors/interface/interface_context_path.cc index b0f8d186afa..3f5efd187d8 100644 --- a/source/blender/editors/interface/interface_context_path.cc +++ b/source/blender/editors/interface/interface_context_path.cc @@ -82,4 +82,4 @@ void template_breadcrumbs(uiLayout &layout, Span<ContextPathItem> context_path) } // namespace blender::ui -/** \} */
\ No newline at end of file +/** \} */ diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c index c3633e11f83..e45619d89e8 100644 --- a/source/blender/editors/interface/interface_eyedropper_color.c +++ b/source/blender/editors/interface/interface_eyedropper_color.c @@ -268,28 +268,28 @@ static bool eyedropper_cryptomatte_sample_fl( return false; } - ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); - if (!ar) { + ARegion *region = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); + if (!region) { return false; } - int mval[2] = {mx - ar->winrct.xmin, my - ar->winrct.ymin}; + int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin}; float fpos[2] = {-1.0f, -1.0}; switch (sa->spacetype) { case SPACE_IMAGE: { SpaceImage *sima = sa->spacedata.first; - ED_space_image_get_position(sima, ar, mval, fpos); + ED_space_image_get_position(sima, region, mval, fpos); break; } case SPACE_NODE: { Main *bmain = CTX_data_main(C); SpaceNode *snode = sa->spacedata.first; - ED_space_node_get_position(bmain, snode, ar, mval, fpos); + ED_space_node_get_position(bmain, snode, region, mval, fpos); break; } case SPACE_CLIP: { SpaceClip *sc = sa->spacedata.first; - ED_space_clip_get_position(sc, ar, mval, fpos); + ED_space_clip_get_position(sc, region, mval, fpos); break; } default: { diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 35e1526d079..d18b3fdf505 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -397,8 +397,8 @@ typedef struct uiHandleButtonData { float vec[3], origvec[3]; ColorBand *coba; - /* Tool-tip. */ - uint tooltip_force : 1; + /* True when alt is held and the preference for displaying tooltips should be ignored. */ + bool tooltip_force; /* auto open */ bool used_mouse; @@ -2334,9 +2334,6 @@ static void ui_apply_but( case UI_BTYPE_LISTROW: ui_apply_but_LISTROW(C, block, but, data); break; - case UI_BTYPE_DATASETROW: - ui_apply_but_ROW(C, block, but, data); - break; case UI_BTYPE_TAB: ui_apply_but_TAB(C, but, data); break; @@ -8012,7 +8009,6 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * case UI_BTYPE_CHECKBOX: case UI_BTYPE_CHECKBOX_N: case UI_BTYPE_ROW: - case UI_BTYPE_DATASETROW: retval = ui_do_but_TOG(C, but, data, event); break; case UI_BTYPE_TREEROW: @@ -10312,7 +10308,7 @@ static int ui_handle_menu_event(bContext *C, retval = WM_UI_HANDLER_BREAK; break; - /* Smooth scrolling for pocopy_v2_v2_int(&povers. */ + /* Smooth scrolling for popovers. */ case MOUSEPAN: { if (IS_EVENT_MOD(event, shift, ctrl, alt, oskey)) { /* pass */ @@ -11344,8 +11340,7 @@ static void ui_region_handler_remove(bContext *C, void *UNUSED(userdata)) return; } - UI_blocklist_free(C, ®ion->uiblocks); - + UI_blocklist_free(C, region); bScreen *screen = CTX_wm_screen(C); if (screen == NULL) { return; diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index f849ec55e4f..6f119d55d3c 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -1484,7 +1484,7 @@ PreviewImage *UI_icon_to_preview(int icon_id) /** * Version of #icon_draw_rect() that uses the GPU for scaling. This is only used for - * #ICON_TYPE_IMBUF because it's a backported fix for performance issues, see T92922. Only + * #ICON_TYPE_IMBUF because it's a back-ported fix for performance issues, see T92922. Only * File/Asset Browser use #ICON_TYPE_IMBUF right now, which makes implications more predictable. * * TODO(Julian): This code is mostly duplicated. #icon_draw_rect() should be ported to use the GPU @@ -2037,11 +2037,22 @@ void UI_icon_render_id( const bContext *C, Scene *scene, ID *id, const enum eIconSizes size, const bool use_job) { PreviewImage *pi = BKE_previewimg_id_ensure(id); - if (pi == NULL) { return; } + /* For objects, first try if a preview can created via the object data. */ + if (GS(id->name) == ID_OB) { + Object *ob = (Object *)id; + if (ED_preview_id_is_supported(ob->data)) { + id = ob->data; + } + } + + if (!ED_preview_id_is_supported(id)) { + return; + } + ui_id_preview_image_render_size(C, scene, id, pi, size, use_job); } diff --git a/source/blender/editors/interface/interface_icons_event.c b/source/blender/editors/interface/interface_icons_event.c index 3962ff6a702..577db6a0338 100644 --- a/source/blender/editors/interface/interface_icons_event.c +++ b/source/blender/editors/interface/interface_icons_event.c @@ -77,7 +77,7 @@ static void icon_draw_rect_input_text(const rctf *rect, const float color[4], const char *str, - int font_size) + float font_size) { BLF_batch_draw_flush(); const int font_id = BLF_default(); @@ -97,7 +97,7 @@ static void icon_draw_rect_input_symbol(const rctf *rect, const float color[4], BLF_batch_draw_flush(); const int font_id = blf_mono_font; BLF_color4fv(font_id, color); - BLF_size(font_id, 19 * U.pixelsize, U.dpi); + BLF_size(font_id, 19.0f * U.pixelsize, U.dpi); const float x = rect->xmin + (2.0f * U.pixelsize); const float y = rect->ymin + (1.0f * U.pixelsize); BLF_position(font_id, x, y, 0.0f); @@ -152,12 +152,12 @@ void icon_draw_rect_input(float x, if ((event_type >= EVT_AKEY) && (event_type <= EVT_ZKEY)) { const char str[2] = {'A' + (event_type - EVT_AKEY), '\0'}; - icon_draw_rect_input_text(&rect, color, str, 13); + icon_draw_rect_input_text(&rect, color, str, 13.0f); } else if ((event_type >= EVT_F1KEY) && (event_type <= EVT_F12KEY)) { char str[4]; SNPRINTF(str, "F%d", 1 + (event_type - EVT_F1KEY)); - icon_draw_rect_input_text(&rect, color, str, event_type > EVT_F9KEY ? 8 : 10); + icon_draw_rect_input_text(&rect, color, str, event_type > EVT_F9KEY ? 8.0f : 10.0f); } else if (event_type == EVT_LEFTSHIFTKEY) { icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x87, 0xa7, 0x0}); @@ -167,7 +167,7 @@ void icon_draw_rect_input(float x, icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8c, 0x83, 0x0}); } else { - icon_draw_rect_input_text(&rect, color, "Ctrl", 9); + icon_draw_rect_input_text(&rect, color, "Ctrl", 9.0f); } } else if (event_type == EVT_LEFTALTKEY) { @@ -175,7 +175,7 @@ void icon_draw_rect_input(float x, icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8c, 0xa5, 0x0}); } else { - icon_draw_rect_input_text(&rect, color, "Alt", 10); + icon_draw_rect_input_text(&rect, color, "Alt", 10.0f); } } else if (event_type == EVT_OSKEY) { @@ -186,20 +186,20 @@ void icon_draw_rect_input(float x, icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x9d, 0x96, 0x0}); } else { - icon_draw_rect_input_text(&rect, color, "OS", 10); + icon_draw_rect_input_text(&rect, color, "OS", 10.0f); } } else if (event_type == EVT_DELKEY) { - icon_draw_rect_input_text(&rect, color, "Del", 9); + icon_draw_rect_input_text(&rect, color, "Del", 9.0f); } else if (event_type == EVT_TABKEY) { icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0xad, 0xbe, 0x0}); } else if (event_type == EVT_HOMEKEY) { - icon_draw_rect_input_text(&rect, color, "Home", 6); + icon_draw_rect_input_text(&rect, color, "Home", 6.0f); } else if (event_type == EVT_ENDKEY) { - icon_draw_rect_input_text(&rect, color, "End", 8); + icon_draw_rect_input_text(&rect, color, "End", 8.0f); } else if (event_type == EVT_RETKEY) { icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8f, 0x8e, 0x0}); @@ -209,14 +209,14 @@ void icon_draw_rect_input(float x, icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8e, 0x8b, 0x0}); } else { - icon_draw_rect_input_text(&rect, color, "Esc", 8); + icon_draw_rect_input_text(&rect, color, "Esc", 8.0f); } } else if (event_type == EVT_PAGEUPKEY) { - icon_draw_rect_input_text(&rect, color, (const char[]){'P', 0xe2, 0x86, 0x91, 0x0}, 8); + icon_draw_rect_input_text(&rect, color, (const char[]){'P', 0xe2, 0x86, 0x91, 0x0}, 8.0f); } else if (event_type == EVT_PAGEDOWNKEY) { - icon_draw_rect_input_text(&rect, color, (const char[]){'P', 0xe2, 0x86, 0x93, 0x0}, 8); + icon_draw_rect_input_text(&rect, color, (const char[]){'P', 0xe2, 0x86, 0x93, 0x0}, 8.0f); } else if (event_type == EVT_LEFTARROWKEY) { icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x86, 0x90, 0x0}); diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index c7c6a88de01..e0686c1ff7a 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -351,14 +351,6 @@ typedef struct uiButProgressbar { float progress; } uiButProgressbar; -/** Derived struct for #UI_BTYPE_DATASETROW. */ -typedef struct uiButDatasetRow { - uiBut but; - - uint8_t geometry_component_type; - uint8_t attribute_domain; - int indentation; -} uiButDatasetRow; /** Derived struct for #UI_BTYPE_TREEROW. */ typedef struct uiButTreeRow { @@ -609,7 +601,7 @@ typedef struct uiSafetyRct { /* interface.c */ -void ui_fontscale(short *points, float aspect); +void ui_fontscale(float *points, float aspect); extern void ui_block_to_region_fl(const struct ARegion *region, uiBlock *block, diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 072362492d8..6acbaf03476 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -1348,7 +1348,7 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active) const uiStyle *style = UI_style_get(); const uiFontStyle *fstyle = &style->widget; const int fontid = fstyle->uifont_id; - short fstyle_points = fstyle->points; + float fstyle_points = fstyle->points; const float aspect = ((uiBlock *)region->uiblocks.first)->aspect; const float zoom = 1.0f / aspect; const int px = U.pixelsize; diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c index bdf93d7c82e..a07222854d2 100644 --- a/source/blender/editors/interface/interface_query.c +++ b/source/blender/editors/interface/interface_query.c @@ -69,7 +69,6 @@ bool ui_but_is_toggle(const uiBut *but) UI_BTYPE_CHECKBOX, UI_BTYPE_CHECKBOX_N, UI_BTYPE_ROW, - UI_BTYPE_DATASETROW, UI_BTYPE_TREEROW); } diff --git a/source/blender/editors/interface/interface_region_popup.c b/source/blender/editors/interface/interface_region_popup.c index 0e53100f91b..0f903bd4af9 100644 --- a/source/blender/editors/interface/interface_region_popup.c +++ b/source/blender/editors/interface/interface_region_popup.c @@ -743,7 +743,7 @@ uiBlock *ui_popup_block_refresh(bContext *C, if (block_old) { block->oldblock = block_old; UI_block_update_from_old(C, block); - UI_blocklist_free_inactive(C, ®ion->uiblocks); + UI_blocklist_free_inactive(C, region); } /* checks which buttons are visible, sets flags to prevent draw (do after region init) */ diff --git a/source/blender/editors/interface/interface_region_search.c b/source/blender/editors/interface/interface_region_search.cc index b8a19d06be1..eaf1ed3693b 100644 --- a/source/blender/editors/interface/interface_region_search.c +++ b/source/blender/editors/interface/interface_region_search.cc @@ -23,9 +23,9 @@ * Search Box Region & Interaction */ -#include <stdarg.h> -#include <stdlib.h> -#include <string.h> +#include <cstdarg> +#include <cstdlib> +#include <cstring> #include "DNA_ID.h" #include "MEM_guardedalloc.h" @@ -84,7 +84,7 @@ struct uiSearchItems { void *active; }; -typedef struct uiSearchboxData { +struct uiSearchboxData { rcti bbox; uiFontStyle fstyle; uiSearchItems items; @@ -102,7 +102,7 @@ typedef struct uiSearchboxData { * Used so we can show leading text to menu items less prominently (not related to 'use_sep'). */ const char *sep_string; -} uiSearchboxData; +}; #define SEARCH_ITEMS 10 @@ -166,9 +166,9 @@ bool UI_search_item_add(uiSearchItems *items, if (name_prefix_offset != 0) { /* Lazy initialize, as this isn't used often. */ - if (items->name_prefix_offsets == NULL) { - items->name_prefix_offsets = MEM_callocN( - items->maxitem * sizeof(*items->name_prefix_offsets), "search name prefix offsets"); + if (items->name_prefix_offsets == nullptr) { + items->name_prefix_offsets = (uint8_t *)MEM_callocN( + items->maxitem * sizeof(*items->name_prefix_offsets), __func__); } items->name_prefix_offsets[items->totitem] = name_prefix_offset; } @@ -198,7 +198,7 @@ int UI_searchbox_size_x(void) int UI_search_items_find_index(uiSearchItems *items, const char *name) { - if (items->name_prefix_offsets != NULL) { + if (items->name_prefix_offsets != nullptr) { for (int i = 0; i < items->totitem; i++) { if (STREQ(name, items->names[i] + items->name_prefix_offsets[i])) { return i; @@ -218,7 +218,7 @@ int UI_search_items_find_index(uiSearchItems *items, const char *name) /* region is the search box itself */ static void ui_searchbox_select(bContext *C, ARegion *region, uiBut *but, int step) { - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); /* apply step */ data->active += step; @@ -285,14 +285,14 @@ static void ui_searchbox_butrect(rcti *r_rect, uiSearchboxData *data, int itemnr int ui_searchbox_find_index(ARegion *region, const char *name) { - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); return UI_search_items_find_index(&data->items, name); } /* x and y in screen-coords. */ bool ui_searchbox_inside(ARegion *region, const int xy[2]) { - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); return BLI_rcti_isect_pt(&data->bbox, xy[0] - region->winrct.xmin, xy[1] - region->winrct.ymin); } @@ -300,12 +300,12 @@ bool ui_searchbox_inside(ARegion *region, const int xy[2]) /* string validated to be of correct length (but->hardmax) */ bool ui_searchbox_apply(uiBut *but, ARegion *region) { - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); uiButSearch *search_but = (uiButSearch *)but; BLI_assert(but->type == UI_BTYPE_SEARCH_MENU); - search_but->item_active = NULL; + search_but->item_active = nullptr; if (data->active != -1) { const char *name = data->items.names[data->active] + @@ -314,7 +314,7 @@ bool ui_searchbox_apply(uiBut *but, ARegion *region) data->items.name_prefix_offsets[data->active] : 0); - const char *name_sep = data->use_shortcut_sep ? strrchr(name, UI_SEP_CHAR) : NULL; + const char *name_sep = data->use_shortcut_sep ? strrchr(name, UI_SEP_CHAR) : nullptr; /* Search button with dynamic string properties may have their own method of applying * the search results, so only copy the result if there is a proper space for it. */ @@ -356,7 +356,7 @@ static struct ARegion *wm_searchbox_tooltip_init(struct bContext *C, } ARegion *searchbox_region = UI_region_searchbox_region_get(region); - uiSearchboxData *data = searchbox_region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(searchbox_region->regiondata); BLI_assert(data->items.pointers[data->active] == search_but->item_active); @@ -367,13 +367,13 @@ static struct ARegion *wm_searchbox_tooltip_init(struct bContext *C, C, region, &rect, search_but->arg, search_but->item_active); } } - return NULL; + return nullptr; } bool ui_searchbox_event( bContext *C, ARegion *region, uiBut *but, ARegion *butregion, const wmEvent *event) { - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); uiButSearch *search_but = (uiButSearch *)but; int type = event->type, val = event->val; bool handled = false; @@ -481,7 +481,7 @@ static void ui_searchbox_update_fn(bContext *C, void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool reset) { uiButSearch *search_but = (uiButSearch *)but; - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); BLI_assert(but->type == UI_BTYPE_SEARCH_MENU); @@ -499,7 +499,7 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re if (search_but->items_update_fn && search_but->item_active) { data->items.active = search_but->item_active; ui_searchbox_update_fn(C, search_but, but->editstr, &data->items); - data->items.active = NULL; + data->items.active = nullptr; /* found active item, calculate real offset by centering it */ if (data->items.totitem) { @@ -538,7 +538,7 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re /* Never include the prefix in the button. */ (data->items.name_prefix_offsets ? data->items.name_prefix_offsets[a] : 0); - const char *name_sep = data->use_shortcut_sep ? strrchr(name, UI_SEP_CHAR) : NULL; + const char *name_sep = data->use_shortcut_sep ? strrchr(name, UI_SEP_CHAR) : nullptr; if (STREQLEN(but->editstr, name, name_sep ? (name_sep - name) : data->items.maxstrlen)) { data->active = a; break; @@ -558,7 +558,7 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re int ui_searchbox_autocomplete(bContext *C, ARegion *region, uiBut *but, char *str) { uiButSearch *search_but = (uiButSearch *)but; - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); int match = AUTOCOMPLETE_NO_MATCH; BLI_assert(but->type == UI_BTYPE_SEARCH_MENU); @@ -569,7 +569,7 @@ int ui_searchbox_autocomplete(bContext *C, ARegion *region, uiBut *but, char *st ui_searchbox_update_fn(C, search_but, but->editstr, &data->items); match = UI_autocomplete_end(data->items.autocpl, str); - data->items.autocpl = NULL; + data->items.autocpl = nullptr; } return match; @@ -577,7 +577,7 @@ int ui_searchbox_autocomplete(bContext *C, ARegion *region, uiBut *but, char *st static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region) { - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); /* pixel space */ wmOrtho2_region_pixelspace(region); @@ -630,7 +630,7 @@ static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region) const int state = ((a == data->active) ? UI_ACTIVE : 0) | data->items.states[a]; char *name = data->items.names[a]; int icon = data->items.icons[a]; - char *name_sep_test = NULL; + char *name_sep_test = nullptr; uiMenuItemSeparatorType separator_type = UI_MENU_ITEM_SEPARATOR_NONE; if (data->use_shortcut_sep) { @@ -652,15 +652,15 @@ static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region) } /* Simple menu item. */ - ui_draw_menu_item(&data->fstyle, &rect, name, icon, state, separator_type, NULL); + ui_draw_menu_item(&data->fstyle, &rect, name, icon, state, separator_type, nullptr); } else { /* Split menu item, faded text before the separator. */ - char *name_sep = NULL; + char *name_sep = nullptr; do { name_sep = name_sep_test; name_sep_test = strstr(name_sep + search_sep_len, data->sep_string); - } while (name_sep_test != NULL); + } while (name_sep_test != nullptr); name_sep += search_sep_len; const char name_sep_prev = *name_sep; @@ -683,7 +683,7 @@ static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region) } /* The previous menu item draws the active selection. */ - ui_draw_menu_item(&data->fstyle, &rect, name_sep, icon, state, separator_type, NULL); + ui_draw_menu_item(&data->fstyle, &rect, name_sep, icon, state, separator_type, nullptr); } } /* indicate more */ @@ -705,7 +705,7 @@ static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region) static void ui_searchbox_region_free_fn(ARegion *region) { - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); /* free search data */ for (int a = 0; a < data->items.maxitem; a++) { @@ -716,12 +716,12 @@ static void ui_searchbox_region_free_fn(ARegion *region) MEM_freeN(data->items.icons); MEM_freeN(data->items.states); - if (data->items.name_prefix_offsets != NULL) { + if (data->items.name_prefix_offsets != nullptr) { MEM_freeN(data->items.name_prefix_offsets); } MEM_freeN(data); - region->regiondata = NULL; + region->regiondata = nullptr; } static ARegion *ui_searchbox_create_generic_ex(bContext *C, @@ -746,7 +746,7 @@ static ARegion *ui_searchbox_create_generic_ex(bContext *C, region->type = &type; /* create searchbox data */ - uiSearchboxData *data = MEM_callocN(sizeof(uiSearchboxData), "uiSearchboxData"); + uiSearchboxData *data = (uiSearchboxData *)MEM_callocN(sizeof(uiSearchboxData), __func__); /* set font, get bb */ data->fstyle = style->widget; /* copy struct */ @@ -767,7 +767,7 @@ static ARegion *ui_searchbox_create_generic_ex(bContext *C, data->prv_cols = but->a2; } - if (but->optype != NULL || use_shortcut_sep) { + if (but->optype != nullptr || use_shortcut_sep) { data->use_shortcut_sep = true; } data->sep_string = search_but->item_sep_string; @@ -881,13 +881,13 @@ static ARegion *ui_searchbox_create_generic_ex(bContext *C, /* In case the button's string is dynamic, make sure there are buffers available. */ data->items.maxstrlen = but->hardmax == 0 ? UI_MAX_NAME_STR : but->hardmax; data->items.totitem = 0; - data->items.names = MEM_callocN(data->items.maxitem * sizeof(void *), "search names"); - data->items.pointers = MEM_callocN(data->items.maxitem * sizeof(void *), "search pointers"); - data->items.icons = MEM_callocN(data->items.maxitem * sizeof(int), "search icons"); - data->items.states = MEM_callocN(data->items.maxitem * sizeof(int), "search flags"); - data->items.name_prefix_offsets = NULL; /* Lazy initialized as needed. */ + data->items.names = (char **)MEM_callocN(data->items.maxitem * sizeof(void *), __func__); + data->items.pointers = (void **)MEM_callocN(data->items.maxitem * sizeof(void *), __func__); + data->items.icons = (int *)MEM_callocN(data->items.maxitem * sizeof(int), __func__); + data->items.states = (int *)MEM_callocN(data->items.maxitem * sizeof(int), __func__); + data->items.name_prefix_offsets = nullptr; /* Lazy initialized as needed. */ for (int i = 0; i < data->items.maxitem; i++) { - data->items.names[i] = MEM_callocN(data->items.maxstrlen + 1, "search pointers"); + data->items.names[i] = (char *)MEM_callocN(data->items.maxstrlen + 1, __func__); } return region; @@ -924,7 +924,7 @@ static void str_tolower_titlecaps_ascii(char *str, const size_t len) static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARegion *region) { - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); /* pixel space */ wmOrtho2_region_pixelspace(region); @@ -952,10 +952,10 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe { const int state = ((a == data->active) ? UI_ACTIVE : 0) | data->items.states[a]; - wmOperatorType *ot = data->items.pointers[a]; + wmOperatorType *ot = static_cast<wmOperatorType *>(data->items.pointers[a]); char text_pre[128]; - char *text_pre_p = strstr(ot->idname, "_OT_"); - if (text_pre_p == NULL) { + const char *text_pre_p = strstr(ot->idname, "_OT_"); + if (text_pre_p == nullptr) { text_pre[0] = '\0'; } else { @@ -975,7 +975,7 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe data->items.icons[a], state, UI_MENU_ITEM_SEPARATOR_NONE, - NULL); + nullptr); ui_draw_menu_item(&data->fstyle, &rect_post, data->items.names[a], @@ -983,7 +983,7 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe state, data->use_shortcut_sep ? UI_MENU_ITEM_SEPARATOR_SHORTCUT : UI_MENU_ITEM_SEPARATOR_NONE, - NULL); + nullptr); } } /* indicate more */ @@ -1044,17 +1044,17 @@ void ui_but_search_refresh(uiButSearch *search_but) return; } - uiSearchItems *items = MEM_callocN(sizeof(uiSearchItems), "search items"); + uiSearchItems *items = (uiSearchItems *)MEM_callocN(sizeof(uiSearchItems), __func__); /* setup search struct */ items->maxitem = 10; items->maxstrlen = 256; - items->names = MEM_callocN(items->maxitem * sizeof(void *), "search names"); + items->names = (char **)MEM_callocN(items->maxitem * sizeof(void *), __func__); for (int i = 0; i < items->maxitem; i++) { - items->names[i] = MEM_callocN(but->hardmax + 1, "search names"); + items->names[i] = (char *)MEM_callocN(but->hardmax + 1, __func__); } - ui_searchbox_update_fn(but->block->evil_C, search_but, but->drawstr, items); + ui_searchbox_update_fn((bContext *)but->block->evil_C, search_but, but->drawstr, items); if (!search_but->results_are_suggestions) { /* Only red-alert when we are sure of it, this can miss cases when >10 matches. */ diff --git a/source/blender/editors/interface/interface_regions_intern.h b/source/blender/editors/interface/interface_regions_intern.h index 0cb1fee9a92..ce938852520 100644 --- a/source/blender/editors/interface/interface_regions_intern.h +++ b/source/blender/editors/interface/interface_regions_intern.h @@ -22,9 +22,17 @@ #pragma once +#ifdef __cplusplus +extern "C" { +#endif + /* interface_region_menu_popup.c */ uint ui_popup_menu_hash(const char *str); /* interface_regions_intern.h */ ARegion *ui_region_temp_add(bScreen *screen); void ui_region_temp_remove(struct bContext *C, bScreen *screen, ARegion *region); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c index 4c640851999..8bb1e477506 100644 --- a/source/blender/editors/interface/interface_style.c +++ b/source/blender/editors/interface/interface_style.c @@ -483,9 +483,9 @@ void uiStyleInit(void) * Yes, this build the glyph cache and create * the texture. */ - BLF_size(font->blf_id, 11 * U.pixelsize, U.dpi); - BLF_size(font->blf_id, 12 * U.pixelsize, U.dpi); - BLF_size(font->blf_id, 14 * U.pixelsize, U.dpi); + BLF_size(font->blf_id, 11.0f * U.pixelsize, U.dpi); + BLF_size(font->blf_id, 12.0f * U.pixelsize, U.dpi); + BLF_size(font->blf_id, 14.0f * U.pixelsize, U.dpi); } } @@ -510,7 +510,7 @@ void uiStyleInit(void) blf_mono_font = BLF_load_mono_default(unique); } - BLF_size(blf_mono_font, 12 * U.pixelsize, 72); + BLF_size(blf_mono_font, 12.0f * U.pixelsize, 72); /* Set default flags based on UI preferences (not render fonts) */ { @@ -555,7 +555,7 @@ void uiStyleInit(void) blf_mono_font_render = BLF_load_mono_default(unique); } - BLF_size(blf_mono_font_render, 12 * U.pixelsize, 72); + BLF_size(blf_mono_font_render, 12.0f * U.pixelsize, 72); } void UI_fontstyle_set(const uiFontStyle *fs) diff --git a/source/blender/editors/interface/interface_template_search_menu.c b/source/blender/editors/interface/interface_template_search_menu.cc index 26250e105eb..fe7660e4221 100644 --- a/source/blender/editors/interface/interface_template_search_menu.c +++ b/source/blender/editors/interface/interface_template_search_menu.cc @@ -21,8 +21,8 @@ * Accessed via the #WM_OT_search_menu operator. */ -#include <stdio.h> -#include <string.h> +#include <cstdio> +#include <cstring> #include "MEM_guardedalloc.h" @@ -85,16 +85,16 @@ struct MenuSearch_Context { }; struct MenuSearch_Parent { - struct MenuSearch_Parent *parent; + MenuSearch_Parent *parent; MenuType *parent_mt; const char *drawstr; /** Set while writing menu items only. */ - struct MenuSearch_Parent *temp_child; + MenuSearch_Parent *temp_child; }; struct MenuSearch_Item { - struct MenuSearch_Item *next, *prev; + MenuSearch_Item *next, *prev; const char *drawstr; const char *drawwstr_full; /** Support a single level sub-menu nesting (for operator buttons that expand). */ @@ -102,12 +102,12 @@ struct MenuSearch_Item { int icon; int state; - struct MenuSearch_Parent *menu_parent; + MenuSearch_Parent *menu_parent; MenuType *mt; - enum { - MENU_SEARCH_TYPE_OP = 1, - MENU_SEARCH_TYPE_RNA = 2, + enum Type { + Operator = 1, + RNA = 2, } type; union { @@ -129,8 +129,8 @@ struct MenuSearch_Item { } rna; }; - /** Set when we need each menu item to be able to set its own context. may be NULL. */ - struct MenuSearch_Context *wm_context; + /** Set when we need each menu item to be able to set its own context. may be nullptr. */ + MenuSearch_Context *wm_context; }; struct MenuSearch_Data { @@ -148,15 +148,15 @@ struct MenuSearch_Data { static int menu_item_sort_by_drawstr_full(const void *menu_item_a_v, const void *menu_item_b_v) { - const struct MenuSearch_Item *menu_item_a = menu_item_a_v; - const struct MenuSearch_Item *menu_item_b = menu_item_b_v; + const MenuSearch_Item *menu_item_a = (MenuSearch_Item *)menu_item_a_v; + const MenuSearch_Item *menu_item_b = (MenuSearch_Item *)menu_item_b_v; return strcmp(menu_item_a->drawwstr_full, menu_item_b->drawwstr_full); } static const char *strdup_memarena(MemArena *memarena, const char *str) { const uint str_size = strlen(str) + 1; - char *str_dst = BLI_memarena_alloc(memarena, str_size); + char *str_dst = (char *)BLI_memarena_alloc(memarena, str_size); memcpy(str_dst, str, str_size); return str_dst; } @@ -164,50 +164,53 @@ static const char *strdup_memarena(MemArena *memarena, const char *str) static const char *strdup_memarena_from_dynstr(MemArena *memarena, DynStr *dyn_str) { const uint str_size = BLI_dynstr_get_len(dyn_str) + 1; - char *str_dst = BLI_memarena_alloc(memarena, str_size); + char *str_dst = (char *)BLI_memarena_alloc(memarena, str_size); BLI_dynstr_get_cstring_ex(dyn_str, str_dst); return str_dst; } -static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *data, +static bool menu_items_from_ui_create_item_from_button(MenuSearch_Data *data, MemArena *memarena, struct MenuType *mt, const char *drawstr_submenu, uiBut *but, - struct MenuSearch_Context *wm_context) + MenuSearch_Context *wm_context) { - struct MenuSearch_Item *item = NULL; + MenuSearch_Item *item = nullptr; /* Use override if the name is empty, this can happen with popovers. */ - const char *drawstr_override = NULL; + const char *drawstr_override = nullptr; const char *drawstr_sep = (but->flag & UI_BUT_HAS_SEP_CHAR) ? strrchr(but->drawstr, UI_SEP_CHAR) : - NULL; + nullptr; const bool drawstr_is_empty = (drawstr_sep == but->drawstr) || (but->drawstr[0] == '\0'); - if (but->optype != NULL) { + if (but->optype != nullptr) { if (drawstr_is_empty) { drawstr_override = WM_operatortype_name(but->optype, but->opptr); } - item = BLI_memarena_calloc(memarena, sizeof(*item)); - item->type = MENU_SEARCH_TYPE_OP; + item = (MenuSearch_Item *)BLI_memarena_calloc(memarena, sizeof(*item)); + item->type = MenuSearch_Item::Type::Operator; item->op.type = but->optype; item->op.opcontext = but->opcontext; item->op.context = but->context; item->op.opptr = but->opptr; - but->opptr = NULL; + but->opptr = nullptr; } - else if (but->rnaprop != NULL) { + else if (but->rnaprop != nullptr) { const int prop_type = RNA_property_type(but->rnaprop); if (drawstr_is_empty) { if (prop_type == PROP_ENUM) { const int value_enum = (int)but->hardmax; EnumPropertyItem enum_item; - if (RNA_property_enum_item_from_value_gettexted( - but->block->evil_C, &but->rnapoin, but->rnaprop, value_enum, &enum_item)) { + if (RNA_property_enum_item_from_value_gettexted((bContext *)but->block->evil_C, + &but->rnapoin, + but->rnaprop, + value_enum, + &enum_item)) { drawstr_override = enum_item.name; } else { @@ -229,8 +232,8 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d prop_type); } else { - item = BLI_memarena_calloc(memarena, sizeof(*item)); - item->type = MENU_SEARCH_TYPE_RNA; + item = (MenuSearch_Item *)BLI_memarena_calloc(memarena, sizeof(*item)); + item->type = MenuSearch_Item::Type::RNA; item->rna.ptr = but->rnapoin; item->rna.prop = but->rnaprop; @@ -242,13 +245,12 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d } } - if (item != NULL) { + if (item != nullptr) { /* Handle shared settings. */ - if (drawstr_override != NULL) { + if (drawstr_override != nullptr) { const char *drawstr_suffix = drawstr_sep ? drawstr_sep : ""; - char *drawstr_alloc = BLI_string_joinN("(", drawstr_override, ")", drawstr_suffix); - item->drawstr = strdup_memarena(memarena, drawstr_alloc); - MEM_freeN(drawstr_alloc); + std::string drawstr = std::string("(") + drawstr_override + ")" + drawstr_suffix; + item->drawstr = strdup_memarena(memarena, drawstr.c_str()); } else { item->drawstr = strdup_memarena(memarena, but->drawstr); @@ -258,7 +260,7 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d item->state = (but->flag & (UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT | UI_BUT_HAS_SEP_CHAR)); item->mt = mt; - item->drawstr_submenu = drawstr_submenu ? strdup_memarena(memarena, drawstr_submenu) : NULL; + item->drawstr_submenu = drawstr_submenu ? strdup_memarena(memarena, drawstr_submenu) : nullptr; item->wm_context = wm_context; @@ -272,11 +274,11 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d /** * Populate a fake button from a menu item (use for context menu). */ -static bool menu_items_to_ui_button(struct MenuSearch_Item *item, uiBut *but) +static bool menu_items_to_ui_button(MenuSearch_Item *item, uiBut *but) { bool changed = false; switch (item->type) { - case MENU_SEARCH_TYPE_OP: { + case MenuSearch_Item::Type::Operator: { but->optype = item->op.type; but->opcontext = item->op.opcontext; but->context = item->op.context; @@ -284,7 +286,7 @@ static bool menu_items_to_ui_button(struct MenuSearch_Item *item, uiBut *but) changed = true; break; } - case MENU_SEARCH_TYPE_RNA: { + case MenuSearch_Item::Type::RNA: { const int prop_type = RNA_property_type(item->rna.prop); but->rnapoin = item->rna.ptr; @@ -302,12 +304,12 @@ static bool menu_items_to_ui_button(struct MenuSearch_Item *item, uiBut *but) if (changed) { STRNCPY(but->drawstr, item->drawstr); char *drawstr_sep = (item->state & UI_BUT_HAS_SEP_CHAR) ? strrchr(but->drawstr, UI_SEP_CHAR) : - NULL; + nullptr; if (drawstr_sep) { *drawstr_sep = '\0'; } - but->icon = item->icon; + but->icon = (BIFIconID)item->icon; but->str = but->strdata; } @@ -327,13 +329,13 @@ static void menu_types_add_from_keymap_items(bContext *C, { wmWindowManager *wm = CTX_wm_manager(C); ListBase *handlers[] = { - region ? ®ion->handlers : NULL, - area ? &area->handlers : NULL, + region ? ®ion->handlers : nullptr, + area ? &area->handlers : nullptr, &win->handlers, }; for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) { - if (handlers[handler_index] == NULL) { + if (handlers[handler_index] == nullptr) { continue; } LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers[handler_index]) { @@ -345,7 +347,7 @@ static void menu_types_add_from_keymap_items(bContext *C, continue; } - if (handler_base->poll == NULL || handler_base->poll(region, win->eventstate)) { + if (handler_base->poll == nullptr || handler_base->poll(region, win->eventstate)) { wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base; wmEventHandler_KeymapResult km_result; WM_event_get_keymaps_from_handler(wm, win, handler, &km_result); @@ -382,16 +384,16 @@ static void menu_types_add_from_keymap_items(bContext *C, /** * Display all operators (last). Developer-only convenience feature. */ -static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *data) +static void menu_items_from_all_operators(bContext *C, MenuSearch_Data *data) { /* Add to temporary list so we can sort them separately. */ - ListBase operator_items = {NULL, NULL}; + ListBase operator_items = {nullptr, nullptr}; MemArena *memarena = data->memarena; GHashIterator iter; for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { - wmOperatorType *ot = BLI_ghashIterator_getValue(&iter); + wmOperatorType *ot = (wmOperatorType *)BLI_ghashIterator_getValue(&iter); if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0) { continue; @@ -400,13 +402,13 @@ static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *d if (WM_operator_poll((bContext *)C, ot)) { const char *ot_ui_name = CTX_IFACE_(ot->translation_context, ot->name); - struct MenuSearch_Item *item = NULL; - item = BLI_memarena_calloc(memarena, sizeof(*item)); - item->type = MENU_SEARCH_TYPE_OP; + MenuSearch_Item *item = nullptr; + item = (MenuSearch_Item *)BLI_memarena_calloc(memarena, sizeof(*item)); + item->type = MenuSearch_Item::Type::Operator; item->op.type = ot; item->op.opcontext = WM_OP_INVOKE_DEFAULT; - item->op.context = NULL; + item->op.context = nullptr; char idname_as_py[OP_MAX_TYPENAME]; char uiname[256]; @@ -417,7 +419,7 @@ static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *d item->drawwstr_full = strdup_memarena(memarena, uiname); item->drawstr = ot_ui_name; - item->wm_context = NULL; + item->wm_context = nullptr; BLI_addtail(&operator_items, item); } @@ -434,7 +436,7 @@ static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *d * - Look up predefined editor-menus. * - Look up key-map items which call menus. */ -static struct MenuSearch_Data *menu_items_from_ui_create( +static MenuSearch_Data *menu_items_from_ui_create( bContext *C, wmWindow *win, ScrArea *area_init, ARegion *region_init, bool include_all_areas) { MemArena *memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); @@ -444,12 +446,12 @@ static struct MenuSearch_Data *menu_items_from_ui_create( const uiStyle *style = UI_style_get_dpi(); /* Convert into non-ui structure. */ - struct MenuSearch_Data *data = MEM_callocN(sizeof(*data), __func__); + MenuSearch_Data *data = (MenuSearch_Data *)MEM_callocN(sizeof(*data), __func__); DynStr *dyn_str = BLI_dynstr_new_memarena(); /* Use a stack of menus to handle and discover new menus in passes. */ - LinkNode *menu_stack = NULL; + LinkNode *menu_stack = nullptr; /* Tag menu types not to add, either because they have already been added * or they have been blacklisted. @@ -466,7 +468,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create( }; for (int i = 0; i < ARRAY_SIZE(idname_array); i++) { MenuType *mt = WM_menutype_find(idname_array[i], false); - if (mt != NULL) { + if (mt != nullptr) { BLI_gset_add(menu_tagged, mt); } } @@ -483,7 +485,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create( for (WM_menutype_iter(&iter); (!BLI_ghashIterator_done(&iter)); (BLI_ghashIterator_step(&iter))) { - MenuType *mt = BLI_ghashIterator_getValue(&iter); + MenuType *mt = (MenuType *)BLI_ghashIterator_getValue(&iter); if (BLI_str_endswith(mt->idname, "_context_menu")) { BLI_gset_add(menu_tagged, mt); } @@ -494,34 +496,33 @@ static struct MenuSearch_Data *menu_items_from_ui_create( }; for (int i = 0; i < ARRAY_SIZE(idname_array); i++) { MenuType *mt = WM_menutype_find(idname_array[i], false); - if (mt != NULL) { - BLI_gset_remove(menu_tagged, mt, NULL); + if (mt != nullptr) { + BLI_gset_remove(menu_tagged, mt, nullptr); } } } /* Collect contexts, one for each 'ui_type'. */ - struct MenuSearch_Context *wm_contexts = NULL; + MenuSearch_Context *wm_contexts = nullptr; - const EnumPropertyItem *space_type_ui_items = NULL; + const EnumPropertyItem *space_type_ui_items = nullptr; int space_type_ui_items_len = 0; bool space_type_ui_items_free = false; /* Text used as prefix for top-bar menu items. */ - const char *global_menu_prefix = NULL; + const char *global_menu_prefix = nullptr; if (include_all_areas) { bScreen *screen = WM_window_get_active_screen(win); /* First create arrays for ui_type. */ - PropertyRNA *prop_ui_type = NULL; + PropertyRNA *prop_ui_type = nullptr; { /* This must be a valid pointer, with only it's type checked. */ - ScrArea area_dummy = { - /* Anything besides #SPACE_EMPTY is fine, - * as this value is only included in the enum when set. */ - .spacetype = SPACE_TOPBAR, - }; + ScrArea area_dummy = {nullptr}; + /* Anything besides #SPACE_EMPTY is fine, + * as this value is only included in the enum when set. */ + area_dummy.spacetype = SPACE_TOPBAR; PointerRNA ptr; RNA_pointer_create(&screen->id, &RNA_Area, &area_dummy, &ptr); prop_ui_type = RNA_struct_find_property(&ptr, "ui_type"); @@ -532,7 +533,8 @@ static struct MenuSearch_Data *menu_items_from_ui_create( &space_type_ui_items_len, &space_type_ui_items_free); - wm_contexts = BLI_memarena_calloc(memarena, sizeof(*wm_contexts) * space_type_ui_items_len); + wm_contexts = (MenuSearch_Context *)BLI_memarena_calloc( + memarena, sizeof(*wm_contexts) * space_type_ui_items_len); for (int i = 0; i < space_type_ui_items_len; i++) { wm_contexts[i].space_type_ui_index = -1; } @@ -540,7 +542,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create( LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW); - if (region != NULL) { + if (region != nullptr) { PointerRNA ptr; RNA_pointer_create(&screen->id, &RNA_Area, area, &ptr); const int space_type_ui = RNA_property_enum_get(&ptr, prop_ui_type); @@ -573,16 +575,16 @@ static struct MenuSearch_Data *menu_items_from_ui_create( for (int space_type_ui_index = -1; space_type_ui_index < space_type_ui_items_len; space_type_ui_index += 1) { - ScrArea *area = NULL; - ARegion *region = NULL; - struct MenuSearch_Context *wm_context = NULL; + ScrArea *area = nullptr; + ARegion *region = nullptr; + MenuSearch_Context *wm_context = nullptr; if (include_all_areas) { if (space_type_ui_index == -1) { /* First run without any context, to populate the top-bar without. */ - wm_context = NULL; - area = NULL; - region = NULL; + wm_context = nullptr; + area = nullptr; + region = nullptr; } else { wm_context = &wm_contexts[space_type_ui_index]; @@ -607,7 +609,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create( * from the buttons, however this is quite involved and can be avoided as by convention * each space-type has a single root-menu that headers use. */ { - const char *idname_array[2] = {NULL}; + const char *idname_array[2] = {nullptr}; int idname_array_len = 0; /* Use negative for global (no area) context, populate the top-bar. */ @@ -623,8 +625,8 @@ static struct MenuSearch_Data *menu_items_from_ui_create( case space_type: \ break - if (area != NULL) { - SpaceLink *sl = area->spacedata.first; + if (area != nullptr) { + SpaceLink *sl = (SpaceLink *)area->spacedata.first; switch ((eSpace_Type)area->spacetype) { SPACE_MENU_MAP(SPACE_VIEW3D, "VIEW3D_MT_editor_menus"); SPACE_MENU_MAP(SPACE_GRAPH, "GRAPH_MT_editor_menus"); @@ -656,7 +658,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create( } for (int i = 0; i < idname_array_len; i++) { MenuType *mt = WM_menutype_find(idname_array[i], false); - if (mt != NULL) { + if (mt != nullptr) { /* Check if this exists because of 'include_all_areas'. */ if (BLI_gset_add(menu_tagged, mt)) { BLI_linklist_prepend(&menu_stack, mt); @@ -669,8 +671,8 @@ static struct MenuSearch_Data *menu_items_from_ui_create( bool has_keymap_menu_items = false; - while (menu_stack != NULL) { - MenuType *mt = BLI_linklist_pop(&menu_stack); + while (menu_stack != nullptr) { + MenuType *mt = (MenuType *)BLI_linklist_pop(&menu_stack); if (!WM_menutype_poll(C, mt)) { continue; } @@ -687,7 +689,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create( UI_block_end(C, block); LISTBASE_FOREACH (uiBut *, but, &block->buttons) { - MenuType *mt_from_but = NULL; + MenuType *mt_from_but = nullptr; /* Support menu titles with dynamic from initial labels * (used by edit-mesh context menu). */ if (but->type == UI_BTYPE_LABEL) { @@ -698,13 +700,13 @@ static struct MenuSearch_Data *menu_items_from_ui_create( but_test = but_test->prev; } - if (but_test == NULL) { + if (but_test == nullptr) { BLI_ghash_insert( menu_display_name_map, mt, (void *)strdup_memarena(memarena, but->drawstr)); } } else if (menu_items_from_ui_create_item_from_button( - data, memarena, mt, NULL, but, wm_context)) { + data, memarena, mt, nullptr, but, wm_context)) { /* pass */ } else if ((mt_from_but = UI_but_menutype_get(but))) { @@ -714,8 +716,8 @@ static struct MenuSearch_Data *menu_items_from_ui_create( } if (!BLI_ghash_haskey(menu_parent_map, mt_from_but)) { - struct MenuSearch_Parent *menu_parent = BLI_memarena_calloc(memarena, - sizeof(*menu_parent)); + MenuSearch_Parent *menu_parent = (MenuSearch_Parent *)BLI_memarena_calloc( + memarena, sizeof(*menu_parent)); /* Use brackets for menu key shortcuts, * converting "Text|Some-Shortcut" to "Text (Some-Shortcut)". * This is needed so we don't right align sub-menu contents @@ -723,9 +725,9 @@ static struct MenuSearch_Data *menu_items_from_ui_create( */ const char *drawstr_sep = but->flag & UI_BUT_HAS_SEP_CHAR ? strrchr(but->drawstr, UI_SEP_CHAR) : - NULL; + nullptr; bool drawstr_is_empty = false; - if (drawstr_sep != NULL) { + if (drawstr_sep != nullptr) { BLI_assert(BLI_dynstr_get_len(dyn_str) == 0); /* Detect empty string, fallback to menu name. */ const char *drawstr = but->drawstr; @@ -760,7 +762,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create( } } } - else if (but->menu_create_func != NULL) { + else if (but->menu_create_func != nullptr) { /* A non 'MenuType' menu button. */ /* Only expand one level deep, this is mainly for expanding operator menus. */ @@ -785,19 +787,21 @@ static struct MenuSearch_Data *menu_items_from_ui_create( } if (region) { + BLI_ghash_remove(region->runtime.block_name_map, sub_block->name, nullptr, nullptr); BLI_remlink(®ion->uiblocks, sub_block); } - UI_block_free(NULL, sub_block); + UI_block_free(nullptr, sub_block); } } if (region) { + BLI_ghash_remove(region->runtime.block_name_map, block->name, nullptr, nullptr); BLI_remlink(®ion->uiblocks, block); } - UI_block_free(NULL, block); + UI_block_free(nullptr, block); /* Add key-map items as a second pass, * so all menus are accessed from the header & top-bar before key shortcuts are expanded. */ - if ((menu_stack == NULL) && (has_keymap_menu_items == false)) { + if ((menu_stack == nullptr) && (has_keymap_menu_items == false)) { has_keymap_menu_items = true; menu_types_add_from_keymap_items( C, win, area, region, &menu_stack, menu_to_kmi, menu_tagged); @@ -805,33 +809,34 @@ static struct MenuSearch_Data *menu_items_from_ui_create( } } - LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) { - item->menu_parent = BLI_ghash_lookup(menu_parent_map, item->mt); + LISTBASE_FOREACH (MenuSearch_Item *, item, &data->items) { + item->menu_parent = (MenuSearch_Parent *)BLI_ghash_lookup(menu_parent_map, item->mt); } GHASH_ITER (iter, menu_parent_map) { - struct MenuSearch_Parent *menu_parent = BLI_ghashIterator_getValue(&iter); - menu_parent->parent = BLI_ghash_lookup(menu_parent_map, menu_parent->parent_mt); + MenuSearch_Parent *menu_parent = (MenuSearch_Parent *)BLI_ghashIterator_getValue(&iter); + menu_parent->parent = (MenuSearch_Parent *)BLI_ghash_lookup(menu_parent_map, + menu_parent->parent_mt); } /* NOTE: currently this builds the full path for each menu item, * that could be moved into the parent menu. */ /* Set names as full paths. */ - LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) { + LISTBASE_FOREACH (MenuSearch_Item *, item, &data->items) { BLI_assert(BLI_dynstr_get_len(dyn_str) == 0); if (include_all_areas) { BLI_dynstr_appendf(dyn_str, "%s: ", - (item->wm_context != NULL) ? + (item->wm_context != nullptr) ? space_type_ui_items[item->wm_context->space_type_ui_index].name : global_menu_prefix); } - if (item->menu_parent != NULL) { - struct MenuSearch_Parent *menu_parent = item->menu_parent; - menu_parent->temp_child = NULL; + if (item->menu_parent != nullptr) { + MenuSearch_Parent *menu_parent = item->menu_parent; + menu_parent->temp_child = nullptr; while (menu_parent && menu_parent->parent) { menu_parent->parent->temp_child = menu_parent; menu_parent = menu_parent->parent; @@ -843,14 +848,14 @@ static struct MenuSearch_Data *menu_items_from_ui_create( } } else { - const char *drawstr = BLI_ghash_lookup(menu_display_name_map, item->mt); - if (drawstr == NULL) { + const char *drawstr = (const char *)BLI_ghash_lookup(menu_display_name_map, item->mt); + if (drawstr == nullptr) { drawstr = CTX_IFACE_(item->mt->translation_context, item->mt->label); } BLI_dynstr_append(dyn_str, drawstr); - wmKeyMapItem *kmi = BLI_ghash_lookup(menu_to_kmi, item->mt); - if (kmi != NULL) { + wmKeyMapItem *kmi = (wmKeyMapItem *)BLI_ghash_lookup(menu_to_kmi, item->mt); + if (kmi != nullptr) { char kmi_str[128]; WM_keymap_item_to_string(kmi, false, kmi_str, sizeof(kmi_str)); BLI_dynstr_appendf(dyn_str, " (%s)", kmi_str); @@ -860,7 +865,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create( } /* Optional nested menu. */ - if (item->drawstr_submenu != NULL) { + if (item->drawstr_submenu != nullptr) { BLI_dynstr_append(dyn_str, item->drawstr_submenu); BLI_dynstr_append(dyn_str, " " UI_MENU_ARROW_SEP " "); } @@ -877,12 +882,12 @@ static struct MenuSearch_Data *menu_items_from_ui_create( * NOTE: we might want to keep the in-menu order, for now sort all. */ BLI_listbase_sort(&data->items, menu_item_sort_by_drawstr_full); - BLI_ghash_free(menu_parent_map, NULL, NULL); - BLI_ghash_free(menu_display_name_map, NULL, NULL); + BLI_ghash_free(menu_parent_map, nullptr, nullptr); + BLI_ghash_free(menu_display_name_map, nullptr, nullptr); - BLI_ghash_free(menu_to_kmi, NULL, NULL); + BLI_ghash_free(menu_to_kmi, nullptr, nullptr); - BLI_gset_free(menu_tagged, NULL); + BLI_gset_free(menu_tagged, nullptr); data->memarena = memarena; @@ -915,16 +920,16 @@ static struct MenuSearch_Data *menu_items_from_ui_create( static void menu_search_arg_free_fn(void *data_v) { - struct MenuSearch_Data *data = data_v; - LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) { + MenuSearch_Data *data = (MenuSearch_Data *)data_v; + LISTBASE_FOREACH (MenuSearch_Item *, item, &data->items) { switch (item->type) { - case MENU_SEARCH_TYPE_OP: { - if (item->op.opptr != NULL) { + case MenuSearch_Item::Type::Operator: { + if (item->op.opptr != nullptr) { WM_operator_properties_free(item->op.opptr); MEM_freeN(item->op.opptr); } } - case MENU_SEARCH_TYPE_RNA: { + case MenuSearch_Item::Type::RNA: { break; } } @@ -937,8 +942,8 @@ static void menu_search_arg_free_fn(void *data_v) static void menu_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2) { - struct MenuSearch_Item *item = arg2; - if (item == NULL) { + MenuSearch_Item *item = (MenuSearch_Item *)arg2; + if (item == nullptr) { return; } if (item->state & UI_BUT_DISABLED) { @@ -948,20 +953,20 @@ static void menu_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2) ScrArea *area_prev = CTX_wm_area(C); ARegion *region_prev = CTX_wm_region(C); - if (item->wm_context != NULL) { + if (item->wm_context != nullptr) { CTX_wm_area_set(C, item->wm_context->area); CTX_wm_region_set(C, item->wm_context->region); } switch (item->type) { - case MENU_SEARCH_TYPE_OP: { + case MenuSearch_Item::Type::Operator: { CTX_store_set(C, item->op.context); WM_operator_name_call_ptr_with_depends_on_cursor( C, item->op.type, item->op.opcontext, item->op.opptr, item->drawstr); - CTX_store_set(C, NULL); + CTX_store_set(C, nullptr); break; } - case MENU_SEARCH_TYPE_RNA: { + case MenuSearch_Item::Type::RNA: { PointerRNA *ptr = &item->rna.ptr; PropertyRNA *prop = item->rna.prop; const int index = item->rna.index; @@ -992,7 +997,7 @@ static void menu_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2) } } - if (item->wm_context != NULL) { + if (item->wm_context != nullptr) { CTX_wm_area_set(C, area_prev); CTX_wm_region_set(C, region_prev); } @@ -1004,19 +1009,19 @@ static void menu_search_update_fn(const bContext *UNUSED(C), uiSearchItems *items, const bool UNUSED(is_first)) { - struct MenuSearch_Data *data = arg; + MenuSearch_Data *data = (MenuSearch_Data *)arg; StringSearch *search = BLI_string_search_new(); - LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) { + LISTBASE_FOREACH (MenuSearch_Item *, item, &data->items) { BLI_string_search_add(search, item->drawwstr_full, item); } - struct MenuSearch_Item **filtered_items; + MenuSearch_Item **filtered_items; const int filtered_amount = BLI_string_search_query(search, str, (void ***)&filtered_items); for (int i = 0; i < filtered_amount; i++) { - struct MenuSearch_Item *item = filtered_items[i]; + MenuSearch_Item *item = filtered_items[i]; if (!UI_search_item_add(items, item->drawwstr_full, item, item->icon, item->state, 0)) { break; } @@ -1041,8 +1046,8 @@ static bool ui_search_menu_create_context_menu(struct bContext *C, void *active, const struct wmEvent *event) { - struct MenuSearch_Data *data = arg; - struct MenuSearch_Item *item = active; + MenuSearch_Data *data = (MenuSearch_Data *)arg; + MenuSearch_Item *item = (MenuSearch_Item *)active; bool has_menu = false; memset(&data->context_menu_data, 0x0, sizeof(data->context_menu_data)); @@ -1055,7 +1060,7 @@ static bool ui_search_menu_create_context_menu(struct bContext *C, ScrArea *area_prev = CTX_wm_area(C); ARegion *region_prev = CTX_wm_region(C); - if (item->wm_context != NULL) { + if (item->wm_context != nullptr) { CTX_wm_area_set(C, item->wm_context->area); CTX_wm_region_set(C, item->wm_context->region); } @@ -1064,7 +1069,7 @@ static bool ui_search_menu_create_context_menu(struct bContext *C, has_menu = true; } - if (item->wm_context != NULL) { + if (item->wm_context != nullptr) { CTX_wm_area_set(C, area_prev); CTX_wm_region_set(C, region_prev); } @@ -1085,8 +1090,8 @@ static struct ARegion *ui_search_menu_create_tooltip(struct bContext *C, void *arg, void *active) { - struct MenuSearch_Data *data = arg; - struct MenuSearch_Item *item = active; + MenuSearch_Data *data = (MenuSearch_Data *)arg; + MenuSearch_Item *item = (MenuSearch_Item *)active; memset(&data->context_menu_data, 0x0, sizeof(data->context_menu_data)); uiBut *but = &data->context_menu_data.but; @@ -1112,21 +1117,21 @@ static struct ARegion *ui_search_menu_create_tooltip(struct bContext *C, ScrArea *area_prev = CTX_wm_area(C); ARegion *region_prev = CTX_wm_region(C); - if (item->wm_context != NULL) { + if (item->wm_context != nullptr) { CTX_wm_area_set(C, item->wm_context->area); CTX_wm_region_set(C, item->wm_context->region); } ARegion *region_tip = UI_tooltip_create_from_button(C, region, but, false); - if (item->wm_context != NULL) { + if (item->wm_context != nullptr) { CTX_wm_area_set(C, area_prev); CTX_wm_region_set(C, region_prev); } return region_tip; } - return NULL; + return nullptr; } /** \} */ @@ -1137,14 +1142,13 @@ static struct ARegion *ui_search_menu_create_tooltip(struct bContext *C, void UI_but_func_menu_search(uiBut *but) { - bContext *C = but->block->evil_C; + bContext *C = (bContext *)but->block->evil_C; wmWindow *win = CTX_wm_window(C); ScrArea *area = CTX_wm_area(C); ARegion *region = CTX_wm_region(C); /* When run from top-bar scan all areas in the current window. */ const bool include_all_areas = (area && (area->spacetype == SPACE_TOPBAR)); - struct MenuSearch_Data *data = menu_items_from_ui_create( - C, win, area, region, include_all_areas); + MenuSearch_Data *data = menu_items_from_ui_create(C, win, area, region, include_all_areas); UI_but_func_search_set(but, /* Generic callback. */ ui_searchbox_create_menu, @@ -1153,7 +1157,7 @@ void UI_but_func_menu_search(uiBut *but) false, menu_search_arg_free_fn, menu_search_exec_fn, - NULL); + nullptr); UI_but_func_search_set_context_menu(but, ui_search_menu_create_context_menu); UI_but_func_search_set_tooltip(but, ui_search_menu_create_tooltip); diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 7d1b7b80ccd..784f87d36c1 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -114,7 +114,6 @@ typedef enum { UI_WTYPE_LISTITEM, UI_WTYPE_PROGRESSBAR, UI_WTYPE_NODESOCKET, - UI_WTYPE_DATASETROW, UI_WTYPE_TREEROW, } uiWidgetTypeEnum; @@ -3675,13 +3674,7 @@ static void widget_treerow( widget_treerow_exec(wcol, rect, state, roundboxalign, tree_row->indentation); } -static void widget_datasetrow( - uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign) -{ - uiButDatasetRow *dataset_row = (uiButDatasetRow *)but; - BLI_assert(but->type == UI_BTYPE_DATASETROW); - widget_treerow_exec(wcol, rect, state, roundboxalign, dataset_row->indentation); -} + static void widget_nodesocket( uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign)) @@ -4476,9 +4469,6 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type) wt.custom = widget_progressbar; break; - case UI_WTYPE_DATASETROW: - wt.custom = widget_datasetrow; - break; case UI_WTYPE_TREEROW: wt.custom = widget_treerow; @@ -4811,11 +4801,6 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu fstyle = &style->widgetlabel; break; - case UI_BTYPE_DATASETROW: - wt = widget_type(UI_WTYPE_DATASETROW); - fstyle = &style->widgetlabel; - break; - case UI_BTYPE_TREEROW: wt = widget_type(UI_WTYPE_TREEROW); fstyle = &style->widgetlabel; diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index aece2e58f1e..d960f5e6b1d 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -1340,7 +1340,8 @@ void UI_GetThemeColorBlendShade4fv(int colorid1, int colorid2, float fac, int of CLAMP(g, 0, 255); b = offset + floorf((1.0f - fac) * cp1[2] + fac * cp2[2]); CLAMP(b, 0, 255); - a = offset + floorf((1.0f - fac) * cp1[3] + fac * cp2[3]); + + a = floorf((1.0f - fac) * cp1[3] + fac * cp2[3]); /* No shading offset. */ CLAMP(a, 0, 255); col[0] = ((float)r) / 255.0f; diff --git a/source/blender/editors/interface/tree_view.cc b/source/blender/editors/interface/tree_view.cc index fcc878c440c..5fcf78dd565 100644 --- a/source/blender/editors/interface/tree_view.cc +++ b/source/blender/editors/interface/tree_view.cc @@ -111,7 +111,10 @@ void AbstractTreeView::update_from_old(uiBlock &new_block) uiTreeViewHandle *old_view_handle = ui_block_view_find_matching_in_old_block( &new_block, reinterpret_cast<uiTreeViewHandle *>(this)); - BLI_assert(old_view_handle); + if (old_view_handle == nullptr) { + is_reconstructed_ = true; + return; + } AbstractTreeView &old_view = reinterpret_cast<AbstractTreeView &>(*old_view_handle); @@ -350,9 +353,14 @@ void AbstractTreeViewItem::on_activate() /* Do nothing by default. */ } -void AbstractTreeViewItem::is_active(IsActiveFn is_active_fn) +std::optional<bool> AbstractTreeViewItem::should_be_active() const { - is_active_fn_ = is_active_fn; + return std::nullopt; +} + +bool AbstractTreeViewItem::supports_collapsing() const +{ + return true; } std::unique_ptr<AbstractTreeViewItemDragController> AbstractTreeViewItem::create_drag_controller() @@ -504,7 +512,10 @@ void AbstractTreeViewItem::set_collapsed(bool collapsed) bool AbstractTreeViewItem::is_collapsible() const { - return !children_.is_empty(); + if (children_.is_empty()) { + return false; + } + return this->supports_collapsing(); } bool AbstractTreeViewItem::is_renaming() const @@ -546,7 +557,8 @@ uiButTreeRow *AbstractTreeViewItem::tree_row_button() void AbstractTreeViewItem::change_state_delayed() { - if (is_active_fn_()) { + const std::optional<bool> should_be_active = this->should_be_active(); + if (should_be_active.has_value() && *should_be_active) { activate(); } } @@ -670,11 +682,24 @@ void BasicTreeViewItem::on_activate() } } -void BasicTreeViewItem::on_activate(ActivateFn fn) +void BasicTreeViewItem::set_on_activate_fn(ActivateFn fn) { activate_fn_ = fn; } +void BasicTreeViewItem::set_is_active_fn(IsActiveFn is_active_fn) +{ + is_active_fn_ = is_active_fn; +} + +std::optional<bool> BasicTreeViewItem::should_be_active() const +{ + if (is_active_fn_) { + return is_active_fn_(); + } + return std::nullopt; +} + } // namespace blender::ui using namespace blender::ui; diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index eea6512f0f8..9a6fbbf4016 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -1348,7 +1348,7 @@ void UI_view2d_dot_grid_draw(const View2D *v2d, const float min_step, const int grid_levels) { - BLI_assert(grid_levels > 0 && grid_levels < 10); + BLI_assert(grid_levels >= 0 && grid_levels < 10); const float zoom_x = (float)(BLI_rcti_size_x(&v2d->mask) + 1) / BLI_rctf_size_x(&v2d->cur); const float zoom_normalized = (zoom_x - v2d->minzoom) / (v2d->maxzoom - v2d->minzoom); diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index e4cd48d95bb..912399c25b3 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -821,8 +821,8 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w float view_vec[3], cross[3]; /* convert the 2D normal into 3D */ - mul_mat3_m4_v3(vc.rv3d->viewinv, nor); /* worldspace */ - mul_mat3_m4_v3(vc.obedit->imat, nor); /* local space */ + mul_mat3_m4_v3(vc.rv3d->viewinv, nor); /* World-space. */ + mul_mat3_m4_v3(vc.obedit->imat, nor); /* Local-space. */ /* correct the normal to be aligned on the view plane */ mul_v3_mat3_m4v3(view_vec, vc.obedit->imat, vc.rv3d->viewinv[2]); diff --git a/source/blender/editors/mesh/editmesh_extrude_spin.c b/source/blender/editors/mesh/editmesh_extrude_spin.c index 2146207308c..d7eaf58653f 100644 --- a/source/blender/editors/mesh/editmesh_extrude_spin.c +++ b/source/blender/editors/mesh/editmesh_extrude_spin.c @@ -80,7 +80,7 @@ static int edbm_spin_exec(bContext *C, wmOperator *op) BMesh *bm = em->bm; BMOperator spinop; - /* keep the values in worldspace since we're passing the obmat */ + /* Keep the values in world-space since we're passing the `obmat`. */ if (!EDBM_op_init(em, &spinop, op, diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c index ee227c58fe7..18fe9cf7ad3 100644 --- a/source/blender/editors/mesh/editmesh_intersect.c +++ b/source/blender/editors/mesh/editmesh_intersect.c @@ -114,6 +114,7 @@ static void edbm_intersect_select(BMEditMesh *em, struct Mesh *me, bool do_selec } } } + EDBM_select_flush(em); } EDBM_update(me, diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index b712cfc24ed..76d48432834 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -236,7 +236,7 @@ typedef struct KnifeTool_OpData { GHash *facetrimap; KnifeBVH bvh; - const float (**cagecos)[3]; + float (**cagecos)[3]; BLI_mempool *kverts; BLI_mempool *kedges; @@ -491,7 +491,7 @@ static void knifetool_draw_visible_distances(const KnifeTool_OpData *kcd) float numstr_size[2]; float posit[2]; const float bg_margin = 4.0f * U.dpi_fac; - const int font_size = 14.0f * U.pixelsize; + const float font_size = 14.0f * U.pixelsize; const int distance_precision = 4; /* Calculate distance and convert to string. */ @@ -561,7 +561,7 @@ static void knifetool_draw_angle(const KnifeTool_OpData *kcd, const float arc_size = 64.0f * U.dpi_fac; const float bg_margin = 4.0f * U.dpi_fac; const float cap_size = 4.0f * U.dpi_fac; - const int font_size = 14 * U.pixelsize; + const float font_size = 14.0f * U.pixelsize; const int angle_precision = 3; /* Angle arc in 3d space. */ @@ -3975,7 +3975,7 @@ static void knifetool_init_cagecos(KnifeTool_OpData *kcd, Object *ob, uint base_ BM_mesh_elem_index_ensure(em_eval->bm, BM_VERT); - kcd->cagecos[base_index] = (const float(*)[3])BKE_editmesh_vert_coords_alloc( + kcd->cagecos[base_index] = BKE_editmesh_vert_coords_alloc( kcd->vc.depsgraph, em_eval, scene_eval, obedit_eval, NULL); } diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index c075d2550cb..7391451b694 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -254,7 +254,8 @@ void ED_mesh_uv_loop_reset(struct bContext *C, struct Mesh *me) } /* NOTE: keep in sync with #ED_mesh_color_add. */ -int ED_mesh_uv_texture_add(Mesh *me, const char *name, const bool active_set, const bool do_init) +int ED_mesh_uv_texture_add( + Mesh *me, const char *name, const bool active_set, const bool do_init, ReportList *reports) { BMEditMesh *em; int layernum_dst; @@ -266,6 +267,7 @@ int ED_mesh_uv_texture_add(Mesh *me, const char *name, const bool active_set, co layernum_dst = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPUV); if (layernum_dst >= MAX_MTFACE) { + BKE_reportf(reports, RPT_ERROR, "Cannot add more than %i UV maps", MAX_MTFACE); return -1; } @@ -285,6 +287,7 @@ int ED_mesh_uv_texture_add(Mesh *me, const char *name, const bool active_set, co else { layernum_dst = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV); if (layernum_dst >= MAX_MTFACE) { + BKE_reportf(reports, RPT_ERROR, "Cannot add more than %i UV maps", MAX_MTFACE); return -1; } @@ -325,13 +328,13 @@ void ED_mesh_uv_texture_ensure(struct Mesh *me, const char *name) layernum_dst = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPUV); if (layernum_dst == 0) { - ED_mesh_uv_texture_add(me, name, true, true); + ED_mesh_uv_texture_add(me, name, true, true, NULL); } } else { layernum_dst = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV); if (layernum_dst == 0) { - ED_mesh_uv_texture_add(me, name, true, true); + ED_mesh_uv_texture_add(me, name, true, true, NULL); } } } @@ -379,7 +382,8 @@ bool ED_mesh_uv_texture_remove_named(Mesh *me, const char *name) } /* NOTE: keep in sync with #ED_mesh_uv_texture_add. */ -int ED_mesh_color_add(Mesh *me, const char *name, const bool active_set, const bool do_init) +int ED_mesh_color_add( + Mesh *me, const char *name, const bool active_set, const bool do_init, ReportList *reports) { BMEditMesh *em; int layernum; @@ -389,6 +393,7 @@ int ED_mesh_color_add(Mesh *me, const char *name, const bool active_set, const b layernum = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPCOL); if (layernum >= MAX_MCOL) { + BKE_reportf(reports, RPT_ERROR, "Cannot add more than %i vertex color layers", MAX_MCOL); return -1; } @@ -406,6 +411,7 @@ int ED_mesh_color_add(Mesh *me, const char *name, const bool active_set, const b else { layernum = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL); if (layernum >= MAX_MCOL) { + BKE_reportf(reports, RPT_ERROR, "Cannot add more than %i vertex color layers", MAX_MCOL); return -1; } @@ -511,7 +517,8 @@ static bool sculpt_vertex_color_remove_poll(bContext *C) } /* NOTE: keep in sync with #ED_mesh_uv_texture_add. */ -int ED_mesh_sculpt_color_add(Mesh *me, const char *name, const bool active_set, const bool do_init) +int ED_mesh_sculpt_color_add( + Mesh *me, const char *name, const bool active_set, const bool do_init, ReportList *reports) { BMEditMesh *em; int layernum; @@ -521,6 +528,8 @@ int ED_mesh_sculpt_color_add(Mesh *me, const char *name, const bool active_set, layernum = CustomData_number_of_layers(&em->bm->vdata, CD_PROP_COLOR); if (layernum >= MAX_MCOL) { + BKE_reportf( + reports, RPT_ERROR, "Cannot add more than %i sculpt vertex color layers", MAX_MCOL); return -1; } @@ -538,6 +547,8 @@ int ED_mesh_sculpt_color_add(Mesh *me, const char *name, const bool active_set, else { layernum = CustomData_number_of_layers(&me->vdata, CD_PROP_COLOR); if (layernum >= MAX_MCOL) { + BKE_reportf( + reports, RPT_ERROR, "Cannot add more than %i sculpt vertex color layers", MAX_MCOL); return -1; } @@ -634,12 +645,12 @@ static bool uv_texture_remove_poll(bContext *C) return false; } -static int mesh_uv_texture_add_exec(bContext *C, wmOperator *UNUSED(op)) +static int mesh_uv_texture_add_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); Mesh *me = ob->data; - if (ED_mesh_uv_texture_add(me, NULL, true, true) == -1) { + if (ED_mesh_uv_texture_add(me, NULL, true, true, op->reports) == -1) { return OPERATOR_CANCELLED; } @@ -719,12 +730,12 @@ static bool vertex_color_remove_poll(bContext *C) return false; } -static int mesh_vertex_color_add_exec(bContext *C, wmOperator *UNUSED(op)) +static int mesh_vertex_color_add_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); Mesh *me = ob->data; - if (ED_mesh_color_add(me, NULL, true, true) == -1) { + if (ED_mesh_color_add(me, NULL, true, true, op->reports) == -1) { return OPERATOR_CANCELLED; } @@ -775,12 +786,12 @@ void MESH_OT_vertex_color_remove(wmOperatorType *ot) /*********************** Sculpt Vertex Color Operators ************************/ -static int mesh_sculpt_vertex_color_add_exec(bContext *C, wmOperator *UNUSED(op)) +static int mesh_sculpt_vertex_color_add_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); Mesh *me = ob->data; - if (ED_mesh_sculpt_color_add(me, NULL, true, true) == -1) { + if (ED_mesh_sculpt_color_add(me, NULL, true, true, op->reports) == -1) { return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 8b5894923ad..c77db10d74b 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1657,12 +1657,25 @@ static int collection_instance_add_exec(bContext *C, wmOperator *op) PropertyRNA *prop_name = RNA_struct_find_property(op->ptr, "name"); PropertyRNA *prop_location = RNA_struct_find_property(op->ptr, "location"); + PropertyRNA *prop_session_uuid = RNA_struct_find_property(op->ptr, "session_uuid"); + bool update_location_if_necessary = false; if (RNA_property_is_set(op->ptr, prop_name)) { char name[MAX_ID_NAME - 2]; RNA_property_string_get(op->ptr, prop_name, name); collection = (Collection *)BKE_libblock_find_name(bmain, ID_GR, name); + update_location_if_necessary = true; + } + else if (RNA_property_is_set(op->ptr, prop_session_uuid)) { + const uint32_t session_uuid = (uint32_t)RNA_property_int_get(op->ptr, prop_session_uuid); + collection = (Collection *)BKE_libblock_find_session_uuid(bmain, ID_GR, session_uuid); + update_location_if_necessary = true; + } + else { + collection = BLI_findlink(&bmain->collections, RNA_enum_get(op->ptr, "collection")); + } + if (update_location_if_necessary) { int mval[2]; if (!RNA_property_is_set(op->ptr, prop_location) && object_add_drop_xy_get(C, op, &mval)) { ED_object_location_from_view(C, loc); @@ -1670,9 +1683,6 @@ static int collection_instance_add_exec(bContext *C, wmOperator *op) RNA_property_float_set_array(op->ptr, prop_location, loc); } } - else { - collection = BLI_findlink(&bmain->collections, RNA_enum_get(op->ptr, "collection")); - } if (collection == NULL) { return OPERATOR_CANCELLED; @@ -1707,7 +1717,8 @@ static int object_instance_add_invoke(bContext *C, wmOperator *op, const wmEvent RNA_int_set(op->ptr, "drop_y", event->xy[1]); } - if (!RNA_struct_property_is_set(op->ptr, "name")) { + if (!RNA_struct_property_is_set(op->ptr, "name") && + !RNA_struct_property_is_set(op->ptr, "session_uuid")) { return WM_enum_search_invoke(C, op, event); } return op->type->exec(C, op); @@ -1740,6 +1751,16 @@ void OBJECT_OT_collection_instance_add(wmOperatorType *ot) ot->prop = prop; ED_object_add_generic_props(ot, false); + RNA_def_int(ot->srna, + "session_uuid", + 0, + INT32_MIN, + INT32_MAX, + "Session UUID", + "Session UUID of the collection to add", + INT32_MIN, + INT32_MAX); + object_add_drop_xy_props(ot); } diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 8702b18a46f..47c2998ed3d 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -1449,7 +1449,9 @@ void ED_object_constraint_link(Main *bmain, Object *ob_dst, ListBase *dst, ListB void ED_object_constraint_copy_for_object(Main *bmain, Object *ob_dst, bConstraint *con) { - BKE_constraint_copy_for_object(ob_dst, con); + bConstraint *copy_con = BKE_constraint_copy_for_object(ob_dst, con); + copy_con->flag |= CONSTRAINT_OVERRIDE_LIBRARY_LOCAL; + ED_object_constraint_dependency_tag_update(bmain, ob_dst, con); WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT | NA_ADDED, ob_dst); } @@ -1459,7 +1461,9 @@ void ED_object_constraint_copy_for_pose(Main *bmain, bPoseChannel *pchan, bConstraint *con) { - BKE_constraint_copy_for_pose(ob_dst, pchan, con); + bConstraint *copy_con = BKE_constraint_copy_for_pose(ob_dst, pchan, con); + copy_con->flag |= CONSTRAINT_OVERRIDE_LIBRARY_LOCAL; + ED_object_constraint_dependency_tag_update(bmain, ob_dst, con); WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT | NA_ADDED, ob_dst); } @@ -1654,6 +1658,8 @@ static int constraint_copy_exec(bContext *C, wmOperator *op) /* Couldn't remove due to some invalid data. */ return OPERATOR_CANCELLED; } + copy_con->flag |= CONSTRAINT_OVERRIDE_LIBRARY_LOCAL; + /* Move constraint to correct position. */ const int new_index = BLI_findindex(constraints, con) + 1; const int current_index = BLI_findindex(constraints, copy_con); @@ -1731,7 +1737,9 @@ static int constraint_copy_to_selected_exec(bContext *C, wmOperator *op) continue; } - BKE_constraint_copy_for_pose(ob, chan, con); + bConstraint *copy_con = BKE_constraint_copy_for_pose(ob, chan, con); + copy_con->flag |= CONSTRAINT_OVERRIDE_LIBRARY_LOCAL; + /* Update flags (need to add here, not just copy). */ chan->constflag |= pchan->constflag; @@ -1753,7 +1761,9 @@ static int constraint_copy_to_selected_exec(bContext *C, wmOperator *op) continue; } - BKE_constraint_copy_for_object(ob, con); + bConstraint *copy_con = BKE_constraint_copy_for_object(ob, con); + copy_con->flag |= CONSTRAINT_OVERRIDE_LIBRARY_LOCAL; + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_TRANSFORM); } CTX_DATA_END; diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index efe19785f31..21b978268d9 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -666,12 +666,13 @@ bool ED_object_modifier_convert(ReportList *UNUSED(reports), static Mesh *modifier_apply_create_mesh_for_modifier(Depsgraph *depsgraph, Object *object, ModifierData *md_eval, + bool use_virtual_modifiers, bool build_shapekey_layers) { Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); Object *object_eval = DEG_get_evaluated_object(depsgraph, object); Mesh *mesh_applied = BKE_mesh_create_derived_for_modifier( - depsgraph, scene_eval, object_eval, md_eval, build_shapekey_layers); + depsgraph, scene_eval, object_eval, md_eval, use_virtual_modifiers, build_shapekey_layers); return mesh_applied; } @@ -708,7 +709,8 @@ static bool modifier_apply_shape(Main *bmain, return false; } - Mesh *mesh_applied = modifier_apply_create_mesh_for_modifier(depsgraph, ob, md_eval, false); + Mesh *mesh_applied = modifier_apply_create_mesh_for_modifier( + depsgraph, ob, md_eval, true, false); if (!mesh_applied) { BKE_report(reports, RPT_ERROR, "Modifier is disabled or returned error, skipping apply"); return false; @@ -767,7 +769,8 @@ static bool modifier_apply_obdata( } } else { - Mesh *mesh_applied = modifier_apply_create_mesh_for_modifier(depsgraph, ob, md_eval, true); + Mesh *mesh_applied = modifier_apply_create_mesh_for_modifier( + depsgraph, ob, md_eval, true, true); if (!mesh_applied) { BKE_report(reports, RPT_ERROR, "Modifier returned error, skipping apply"); return false; diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c index 56f32ff603c..be6b44f87bf 100644 --- a/source/blender/editors/physics/dynamicpaint_ops.c +++ b/source/blender/editors/physics/dynamicpaint_ops.c @@ -246,7 +246,7 @@ static int output_toggle_exec(bContext *C, wmOperator *op) /* Vertex Color Layer */ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) { if (!exists) { - ED_mesh_color_add(ob->data, name, true, true); + ED_mesh_color_add(ob->data, name, true, true, op->reports); } else { ED_mesh_color_remove_named(ob->data, name); diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 97f3b96cd18..fc80767be9e 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -3903,8 +3903,8 @@ static void brush_puff(PEData *data, int point_index, float mouse_distance) copy_v3_v3(co, key->co); mul_m4_v3(mat, co); - /* use 'kco' as the object space version of worldspace 'co', - * ob->imat is set before calling */ + /* Use `kco` as the object space version of world-space `co`, + * `ob->imat` is set before calling. */ mul_v3_m4v3(kco, data->ob->imat, co); point_index = BLI_kdtree_3d_find_nearest(edit->emitter_field, kco, NULL); @@ -3993,15 +3993,15 @@ static void brush_puff(PEData *data, int point_index, float mouse_distance) copy_v3_v3(oco, key->co); mul_m4_v3(mat, oco); - /* use 'kco' as the object space version of worldspace 'co', - * ob->imat is set before calling */ + /* Use `kco` as the object space version of world-space `co`, + * `ob->imat` is set before calling. */ mul_v3_m4v3(kco, data->ob->imat, oco); point_index = BLI_kdtree_3d_find_nearest(edit->emitter_field, kco, NULL); if (point_index != -1) { copy_v3_v3(onor, &edit->emitter_cosnos[point_index * 6 + 3]); - mul_mat3_m4_v3(data->ob->obmat, onor); /* normal into worldspace */ - mul_mat3_m4_v3(imat, onor); /* worldspace into particle space */ + mul_mat3_m4_v3(data->ob->obmat, onor); /* Normal into world-space. */ + mul_mat3_m4_v3(imat, onor); /* World-space into particle-space. */ normalize_v3(onor); } else { diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index 4bf250b9d4f..0cc944436b2 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -786,6 +786,11 @@ struct ObjectPreviewData { int sizey; }; +static bool object_preview_is_type_supported(const Object *ob) +{ + return OB_TYPE_IS_GEOMETRY(ob->type); +} + static Object *object_preview_camera_create(Main *preview_main, ViewLayer *view_layer, Object *preview_object) @@ -1658,9 +1663,12 @@ static void icon_preview_startjob_all_sizes(void *customdata, if (ip->id != NULL) { switch (GS(ip->id->name)) { case ID_OB: - /* Much simpler than the ShaderPreview mess used for other ID types. */ - object_preview_render(ip, cur_size); - continue; + if (object_preview_is_type_supported((Object *)ip->id)) { + /* Much simpler than the ShaderPreview mess used for other ID types. */ + object_preview_render(ip, cur_size); + continue; + } + break; case ID_AC: action_preview_render(ip, cur_size); continue; @@ -1749,6 +1757,17 @@ static void icon_preview_free(void *customdata) MEM_freeN(ip); } +/** + * Check if \a id is supported by the automatic preview render. + */ +bool ED_preview_id_is_supported(const ID *id) +{ + if (GS(id->name) == ID_OB) { + return object_preview_is_type_supported((const Object *)id); + } + return BKE_previewimg_id_get_p(id) != NULL; +} + void ED_preview_icon_render( const bContext *C, Scene *scene, ID *id, uint *rect, int sizex, int sizey) { diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 8523496bdbd..38eadf95bde 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -594,7 +594,7 @@ void ED_region_do_draw(bContext *C, ARegion *region) memset(®ion->drawrct, 0, sizeof(region->drawrct)); - UI_blocklist_free_inactive(C, ®ion->uiblocks); + UI_blocklist_free_inactive(C, region); if (area) { const bScreen *screen = WM_window_get_active_screen(win); @@ -1985,7 +1985,7 @@ void ED_area_init(wmWindowManager *wm, wmWindow *win, ScrArea *area) } else { /* prevent uiblocks to run */ - UI_blocklist_free(NULL, ®ion->uiblocks); + UI_blocklist_free(NULL, region); } /* Some AZones use View2D data which is only updated in region init, so call that first! */ @@ -3323,7 +3323,7 @@ bool ED_region_property_search(const bContext *C, } /* Free the panels and blocks, as they are only used for search. */ - UI_blocklist_free(C, ®ion->uiblocks); + UI_blocklist_free(C, region); UI_panels_free_instanced(C, region); BKE_area_region_panels_free(®ion->panels); diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index fa0cfd16817..3c8fb2e7446 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -1495,8 +1495,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const * switching screens with tooltip open because region and tooltip * are no longer in the same screen */ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { - UI_blocklist_free(C, ®ion->uiblocks); - + UI_blocklist_free(C, region); if (region->regiontimer) { WM_event_remove_timer(wm, NULL, region->regiontimer); region->regiontimer = NULL; diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index 3b668a1bd4c..b826ff8701d 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -44,6 +44,7 @@ set(SRC paint_hide.c paint_image.c paint_image_2d.c + paint_image_2d_curve_mask.cc paint_image_proj.c paint_mask.c paint_ops.c diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c index 63f61b6c5c1..7191431cf4c 100644 --- a/source/blender/editors/sculpt_paint/paint_image_2d.c +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -78,12 +78,13 @@ typedef struct BrushPainterCache { ImBuf *ibuf; ImBuf *texibuf; - ushort *curve_mask; ushort *tex_mask; ushort *tex_mask_old; uint tex_mask_old_w; uint tex_mask_old_h; + CurveMaskCache curve_mask_cache; + int image_size[2]; } BrushPainterCache; @@ -169,9 +170,6 @@ static void brush_painter_2d_require_imbuf( if (cache->ibuf) { IMB_freeImBuf(cache->ibuf); } - if (cache->curve_mask) { - MEM_freeN(cache->curve_mask); - } if (cache->tex_mask) { MEM_freeN(cache->tex_mask); } @@ -179,7 +177,6 @@ static void brush_painter_2d_require_imbuf( MEM_freeN(cache->tex_mask_old); } cache->ibuf = NULL; - cache->curve_mask = NULL; cache->tex_mask = NULL; cache->lastdiameter = -1; /* force ibuf create in refresh */ cache->invert = invert; @@ -200,9 +197,7 @@ static void brush_painter_cache_2d_free(BrushPainterCache *cache) if (cache->texibuf) { IMB_freeImBuf(cache->texibuf); } - if (cache->curve_mask) { - MEM_freeN(cache->curve_mask); - } + paint_curve_mask_cache_free_data(&cache->curve_mask_cache); if (cache->tex_mask) { MEM_freeN(cache->tex_mask); } @@ -380,79 +375,6 @@ static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter, cache->tex_mask_old_h = diameter; } -/* create a mask with the falloff strength */ -static ushort *brush_painter_curve_mask_new(BrushPainter *painter, - int diameter, - float radius, - const float pos[2]) -{ - Brush *brush = painter->brush; - - int offset = (int)floorf(diameter / 2.0f); - - ushort *mask, *m; - - mask = MEM_mallocN(sizeof(ushort) * diameter * diameter, "brush_painter_mask"); - m = mask; - - int aa_samples = 1.0f / (radius * 0.20f); - if (brush->sampling_flag & BRUSH_PAINT_ANTIALIASING) { - aa_samples = clamp_i(aa_samples, 3, 16); - } - else { - aa_samples = 1; - } - - /* Temporal until we have the brush properties */ - const float hardness = 1.0f; - const float rotation = 0.0f; - - float aa_offset = 1.0f / (2.0f * (float)aa_samples); - float aa_step = 1.0f / (float)aa_samples; - - float bpos[2]; - bpos[0] = pos[0] - floorf(pos[0]) + offset - aa_offset; - bpos[1] = pos[1] - floorf(pos[1]) + offset - aa_offset; - - const float co = cosf(DEG2RADF(rotation)); - const float si = sinf(DEG2RADF(rotation)); - - float norm_factor = 65535.0f / (float)(aa_samples * aa_samples); - - for (int y = 0; y < diameter; y++) { - for (int x = 0; x < diameter; x++, m++) { - float total_samples = 0; - for (int i = 0; i < aa_samples; i++) { - for (int j = 0; j < aa_samples; j++) { - float pixel_xy[2] = {x + (aa_step * i), y + (aa_step * j)}; - float xy_rot[2]; - sub_v2_v2(pixel_xy, bpos); - - xy_rot[0] = co * pixel_xy[0] - si * pixel_xy[1]; - xy_rot[1] = si * pixel_xy[0] + co * pixel_xy[1]; - - float len = len_v2(xy_rot); - float p = len / radius; - if (hardness < 1.0f) { - p = (p - hardness) / (1.0f - hardness); - p = 1.0f - p; - CLAMP(p, 0.0f, 1.0f); - } - else { - p = 1.0; - } - float hardness_factor = 3.0f * p * p - 2.0f * p * p * p; - float curve = BKE_brush_curve_strength_clamped(brush, len, radius); - total_samples += curve * hardness_factor; - } - } - *m = (ushort)(total_samples * norm_factor); - } - } - - return mask; -} - /* create imbuf with brush color */ static ImBuf *brush_painter_imbuf_new( BrushPainter *painter, ImagePaintTile *tile, const int size, float pressure, float distance) @@ -858,10 +780,8 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s, } } - /* curve mask can only change if the size changes */ - MEM_SAFE_FREE(cache->curve_mask); - - cache->curve_mask = brush_painter_curve_mask_new(painter, diameter, size, pos); + /* Re-initialize the curve mask. Mask is always recreated due to the change of position. */ + paint_curve_mask_cache_update(&cache->curve_mask_cache, brush, diameter, size, pos); /* detect if we need to recreate image brush buffer */ if (diameter != cache->lastdiameter || (tex_rotation != cache->last_tex_rotation) || do_random || @@ -1325,7 +1245,7 @@ static void paint_2d_do_making_brush(ImagePaintState *s, &tmpbuf, frombuf, mask, - tile->cache.curve_mask, + tile->cache.curve_mask_cache.curve_mask, tile->cache.tex_mask, mask_max, region->destx, @@ -1474,7 +1394,7 @@ static int paint_2d_op(void *state, canvas, frombuf, NULL, - tile->cache.curve_mask, + tile->cache.curve_mask_cache.curve_mask, tile->cache.tex_mask, mask_max, region[a].destx, diff --git a/source/blender/editors/sculpt_paint/paint_image_2d_curve_mask.cc b/source/blender/editors/sculpt_paint/paint_image_2d_curve_mask.cc new file mode 100644 index 00000000000..8d57a3d9152 --- /dev/null +++ b/source/blender/editors/sculpt_paint/paint_image_2d_curve_mask.cc @@ -0,0 +1,188 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup ed + */ + +#include "BLI_math.h" + +#include "MEM_guardedalloc.h" + +#include "DNA_brush_types.h" + +#include "BKE_brush.h" + +#include "paint_intern.h" + +namespace blender::ed::sculpt_paint { + +constexpr int AntiAliasingSamplesPerTexelAxisMin = 3; +constexpr int AntiAliasingSamplesPerTexelAxisMax = 16; +/** + * \brief Number of samples to use between 0..1. + */ +constexpr int CurveSamplesBaseLen = 1024; +/** + * \brief Number of samples to store in the cache. + * + * M_SQRT2 is used as brushes are circles and the curve_mask is square. + * + 1 to fix floating rounding issues. + */ +constexpr int CurveSamplesLen = M_SQRT2 * CurveSamplesBaseLen + 1; + +static int aa_samples_per_texel_axis(const Brush *brush, const float radius) +{ + int aa_samples = 1.0f / (radius * 0.20f); + if (brush->sampling_flag & BRUSH_PAINT_ANTIALIASING) { + aa_samples = clamp_i( + aa_samples, AntiAliasingSamplesPerTexelAxisMin, AntiAliasingSamplesPerTexelAxisMax); + } + else { + aa_samples = 1; + } + return aa_samples; +} + +/* create a mask with the falloff strength */ +static void update_curve_mask(CurveMaskCache *curve_mask_cache, + const Brush *brush, + const int diameter, + const float radius, + const float cursor_position[2]) +{ + BLI_assert(curve_mask_cache->curve_mask != nullptr); + int offset = (int)floorf(diameter / 2.0f); + + unsigned short *m = curve_mask_cache->curve_mask; + + const int aa_samples = aa_samples_per_texel_axis(brush, radius); + const float aa_offset = 1.0f / (2.0f * (float)aa_samples); + const float aa_step = 1.0f / (float)aa_samples; + + float bpos[2]; + bpos[0] = cursor_position[0] - floorf(cursor_position[0]) + offset; + bpos[1] = cursor_position[1] - floorf(cursor_position[1]) + offset; + + float weight_factor = 65535.0f / (float)(aa_samples * aa_samples); + + for (int y = 0; y < diameter; y++) { + for (int x = 0; x < diameter; x++, m++) { + float pixel_xy[2]; + pixel_xy[0] = static_cast<float>(x) + aa_offset; + float total_weight = 0; + + for (int i = 0; i < aa_samples; i++) { + pixel_xy[1] = static_cast<float>(y) + aa_offset; + for (int j = 0; j < aa_samples; j++) { + const float len = len_v2v2(pixel_xy, bpos); + const int sample_index = min_ii((len / radius) * CurveSamplesBaseLen, + CurveSamplesLen - 1); + const float sample_weight = curve_mask_cache->sampled_curve[sample_index]; + + total_weight += sample_weight; + + pixel_xy[1] += aa_step; + } + pixel_xy[0] += aa_step; + } + *m = (unsigned short)(total_weight * weight_factor); + } + } +} + +static bool is_sampled_curve_valid(const CurveMaskCache *curve_mask_cache, const Brush *brush) +{ + if (curve_mask_cache->sampled_curve == nullptr) { + return false; + } + return curve_mask_cache->last_curve_timestamp == brush->curve->changed_timestamp; +} + +static void sampled_curve_free(CurveMaskCache *curve_mask_cache) +{ + MEM_SAFE_FREE(curve_mask_cache->sampled_curve); + curve_mask_cache->last_curve_timestamp = 0; +} + +static void update_sampled_curve(CurveMaskCache *curve_mask_cache, const Brush *brush) +{ + if (curve_mask_cache->sampled_curve == nullptr) { + curve_mask_cache->sampled_curve = static_cast<float *>( + MEM_mallocN(CurveSamplesLen * sizeof(float), __func__)); + } + + for (int i = 0; i < CurveSamplesLen; i++) { + const float len = i / float(CurveSamplesBaseLen); + const float sample_weight = BKE_brush_curve_strength_clamped(brush, len, 1.0f); + curve_mask_cache->sampled_curve[i] = sample_weight; + } + curve_mask_cache->last_curve_timestamp = brush->curve->changed_timestamp; +} + +static size_t diameter_to_curve_mask_size(const int diameter) +{ + return diameter * diameter * sizeof(ushort); +} + +static bool is_curve_mask_size_valid(const CurveMaskCache *curve_mask_cache, const int diameter) +{ + return curve_mask_cache->curve_mask_size == diameter_to_curve_mask_size(diameter); +} + +static void curve_mask_free(CurveMaskCache *curve_mask_cache) +{ + curve_mask_cache->curve_mask_size = 0; + MEM_SAFE_FREE(curve_mask_cache->curve_mask); +} + +static void curve_mask_allocate(CurveMaskCache *curve_mask_cache, const int diameter) +{ + const size_t curve_mask_size = diameter_to_curve_mask_size(diameter); + curve_mask_cache->curve_mask = static_cast<unsigned short *>( + MEM_mallocN(curve_mask_size, __func__)); + curve_mask_cache->curve_mask_size = curve_mask_size; +} + +} // namespace blender::ed::sculpt_paint + +using namespace blender::ed::sculpt_paint; + +void paint_curve_mask_cache_free_data(CurveMaskCache *curve_mask_cache) +{ + sampled_curve_free(curve_mask_cache); + curve_mask_free(curve_mask_cache); +} + +void paint_curve_mask_cache_update(CurveMaskCache *curve_mask_cache, + const Brush *brush, + const int diameter, + const float radius, + const float cursor_position[2]) +{ + if (!is_sampled_curve_valid(curve_mask_cache, brush)) { + update_sampled_curve(curve_mask_cache, brush); + } + + if (!is_curve_mask_size_valid(curve_mask_cache, diameter)) { + curve_mask_free(curve_mask_cache); + curve_mask_allocate(curve_mask_cache, diameter); + } + update_curve_mask(curve_mask_cache, brush, diameter, radius, cursor_position); +} diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 89263bec7b1..db3e69b0953 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -3125,7 +3125,8 @@ static void project_paint_face_init(const ProjPaintState *ps, uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w); } - /* a pity we need to get the worldspace pixel location here */ + /* A pity we need to get the world-space pixel location here + * because it is a relatively expensive operation. */ if (do_clip || do_3d_mapping) { interp_v3_v3v3v3(wco, ps->mvert_eval[lt_vtri[0]].co, @@ -3208,7 +3209,10 @@ static void project_paint_face_init(const ProjPaintState *ps, else { /* we have a seam - deal with it! */ - /* inset face coords. NOTE!!! ScreenSace for ortho, Worldspace in perspective view */ + /* Inset face coords. + * - screen-space in orthographic view. + * - world-space in perspective view. + */ float insetCos[3][3]; /* Vertex screen-space coords. */ @@ -3373,8 +3377,8 @@ static void project_paint_face_init(const ProjPaintState *ps, if ((ps->do_occlude == false) || !project_bucket_point_occluded( ps, bucketFaceNodes, tri_index, pixel_on_edge)) { - /* a pity we need to get the worldspace - * pixel location here */ + /* A pity we need to get the world-space pixel location here + * because it is a relatively expensive operation. */ if (do_clip || do_3d_mapping) { interp_v3_v3v3v3(wco, vCo[0], vCo[1], vCo[2], w); diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index 7341d984c91..62320defbb3 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -23,6 +23,13 @@ #pragma once +#include "BKE_paint.h" +#include "DNA_scene_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + struct ARegion; struct Brush; struct ColorManagedDisplay; @@ -43,8 +50,6 @@ struct wmEvent; struct wmKeyConfig; struct wmOperator; struct wmOperatorType; -enum ePaintMode; -enum ePaintSymmetryFlags; typedef struct CoNo { float co[3]; @@ -245,6 +250,45 @@ void PAINT_OT_add_texture_paint_slot(struct wmOperatorType *ot); void PAINT_OT_image_paint(struct wmOperatorType *ot); void PAINT_OT_add_simple_uvs(struct wmOperatorType *ot); +/* paint_image_2d_curve_mask.cc */ +/** + * \brief Caching structure for curve mask. + * + * When 2d painting images the curve mask is used as an input. + */ +typedef struct CurveMaskCache { + /** + * \brief Last #CurveMapping.changed_timestamp being read. + * + * When different the input cache needs to be recalculated. + */ + int last_curve_timestamp; + + /** + * \brief sampled version of the brush curvemapping. + */ + float *sampled_curve; + + /** + * \brief Size in bytes of the curve_mask field. + * + * Used to determine if the curve_mask needs to be re-allocated. + */ + size_t curve_mask_size; + + /** + * \brief Curve mask that can be passed as curve_mask parameter when. + */ + ushort *curve_mask; +} CurveMaskCache; + +void paint_curve_mask_cache_free_data(CurveMaskCache *curve_mask_cache); +void paint_curve_mask_cache_update(CurveMaskCache *curve_mask_cache, + const struct Brush *brush, + const int diameter, + const float radius, + const float cursor_position[2]); + /* sculpt_uv.c */ void SCULPT_OT_uv_sculpt_stroke(struct wmOperatorType *ot); @@ -366,3 +410,8 @@ void paint_delete_blur_kernel(BlurKernel *); /* paint curve defines */ #define PAINT_CURVE_NUM_SEGMENTS 40 + +#ifdef __cplusplus +} +#endif + diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 696c3332a2b..16df1efd969 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -366,10 +366,12 @@ float *SCULPT_boundary_automasking_init(Object *ob, /* Geodesic distances. */ -/* Returns an array indexed by vertex index containing the geodesic distance to the closest vertex -in the initial vertex set. The caller is responsible for freeing the array. -Geodesic distances will only work when used with PBVH_FACES, for other types of PBVH it will -fallback to euclidean distances to one of the initial vertices in the set. */ +/** + * Returns an array indexed by vertex index containing the geodesic distance to the closest vertex + * in the initial vertex set. The caller is responsible for freeing the array. + * Geodesic distances will only work when used with PBVH_FACES, for other types of PBVH it will + * fallback to euclidean distances to one of the initial vertices in the set. + */ float *SCULPT_geodesic_distances_create(struct Object *ob, struct GSet *initial_vertices, const float limit_radius); diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c index a4fd2d81778..9ff46d96207 100644 --- a/source/blender/editors/space_action/action_data.c +++ b/source/blender/editors/space_action/action_data.c @@ -702,6 +702,9 @@ void ACTION_OT_unlink(wmOperatorType *ot) "Clear Fake User and remove " "copy stashed in this data-block's NLA stack"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ************************************************************************** */ diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index b04291b7ab4..bc701bd7aa5 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -445,7 +445,7 @@ static void property_search_all_tabs(const bContext *C, i, property_search_for_context(C, region_copy, &sbuts_copy)); - UI_blocklist_free(C, ®ion_copy->uiblocks); + UI_blocklist_free(C, region_copy); } BKE_area_region_free(area_copy.type, region_copy); diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c index 834ef847069..97fcf4ef8ba 100644 --- a/source/blender/editors/space_clip/clip_editor.c +++ b/source/blender/editors/space_clip/clip_editor.c @@ -272,7 +272,7 @@ ImBuf *ED_space_clip_get_stable_buffer(SpaceClip *sc, float loc[2], float *scale } bool ED_space_clip_get_position(struct SpaceClip *sc, - struct ARegion *ar, + struct ARegion *region, int mval[2], float fpos[2]) { @@ -282,7 +282,7 @@ bool ED_space_clip_get_position(struct SpaceClip *sc, } /* map the mouse coords to the backdrop image space */ - ED_clip_mouse_pos(sc, ar, mval, fpos); + ED_clip_mouse_pos(sc, region, mval, fpos); IMB_freeImBuf(ibuf); return true; diff --git a/source/blender/editors/space_file/asset_catalog_tree_view.cc b/source/blender/editors/space_file/asset_catalog_tree_view.cc index b3b81c5e07f..dee5168e30b 100644 --- a/source/blender/editors/space_file/asset_catalog_tree_view.cc +++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc @@ -122,6 +122,7 @@ class AssetCatalogDropController : public ui::AbstractTreeViewItemDropController bool on_drop(const wmDrag &drag) override; ::AssetLibrary &get_asset_library() const; + AssetCatalog *get_drag_catalog(const wmDrag &drag) const; static bool has_droppable_asset(const wmDrag &drag, const char **r_disabled_hint); static bool drop_assets_into_catalog(const AssetCatalogTreeView &tree_view, @@ -190,7 +191,8 @@ ui::BasicTreeViewItem &AssetCatalogTreeView::build_catalog_items_recursive( { ui::BasicTreeViewItem &view_item = view_parent_item.add_tree_item<AssetCatalogTreeViewItem>( &catalog); - view_item.is_active([this, &catalog]() { return is_active_catalog(catalog.get_catalog_id()); }); + view_item.set_is_active_fn( + [this, &catalog]() { return is_active_catalog(catalog.get_catalog_id()); }); catalog.foreach_child([&view_item, this](AssetCatalogTreeItem &child) { build_catalog_items_recursive(view_item, child); @@ -204,11 +206,11 @@ void AssetCatalogTreeView::add_all_item() AssetCatalogTreeViewAllItem &item = add_tree_item<AssetCatalogTreeViewAllItem>(IFACE_("All"), ICON_HOME); - item.on_activate([params](ui::BasicTreeViewItem & /*item*/) { + item.set_on_activate_fn([params](ui::BasicTreeViewItem & /*item*/) { params->asset_catalog_visibility = FILE_SHOW_ASSETS_ALL_CATALOGS; WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr); }); - item.is_active( + item.set_is_active_fn( [params]() { return params->asset_catalog_visibility == FILE_SHOW_ASSETS_ALL_CATALOGS; }); } @@ -219,11 +221,11 @@ void AssetCatalogTreeView::add_unassigned_item() AssetCatalogTreeViewUnassignedItem &item = add_tree_item<AssetCatalogTreeViewUnassignedItem>( IFACE_("Unassigned"), ICON_FILE_HIDDEN); - item.on_activate([params](ui::BasicTreeViewItem & /*item*/) { + item.set_on_activate_fn([params](ui::BasicTreeViewItem & /*item*/) { params->asset_catalog_visibility = FILE_SHOW_ASSETS_WITHOUT_CATALOG; WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr); }); - item.is_active( + item.set_is_active_fn( [params]() { return params->asset_catalog_visibility == FILE_SHOW_ASSETS_WITHOUT_CATALOG; }); } @@ -343,7 +345,14 @@ AssetCatalogDropController::AssetCatalogDropController(AssetCatalogTreeView &tre bool AssetCatalogDropController::can_drop(const wmDrag &drag, const char **r_disabled_hint) const { if (drag.type == WM_DRAG_ASSET_CATALOG) { - /* Always supported. */ + const AssetCatalog *drag_catalog = get_drag_catalog(drag); + /* Note: Technically it's not an issue to allow this (the catalog will just receive a new + * path and the catalog system will generate missing parents from the path). But it does + * appear broken to users, so disabling entirely. */ + if (catalog_item_.catalog_path().is_contained_in(drag_catalog->path)) { + *r_disabled_hint = "Catalog cannot be dropped into itself"; + return false; + } return true; } if (drag.type == WM_DRAG_ASSET_LIST) { @@ -363,11 +372,7 @@ std::string AssetCatalogDropController::drop_tooltip(const wmDrag &drag) const std::string AssetCatalogDropController::drop_tooltip_asset_catalog(const wmDrag &drag) const { BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG); - - const ::AssetLibrary *asset_library = tree_view<AssetCatalogTreeView>().asset_library_; - bke::AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service(asset_library); - wmDragAssetCatalog *catalog_drag = WM_drag_get_asset_catalog_data(&drag); - AssetCatalog *src_catalog = catalog_service->find_catalog(catalog_drag->drag_catalog_id); + const AssetCatalog *src_catalog = get_drag_catalog(drag); return std::string(TIP_("Move Catalog")) + " '" + src_catalog->path.name() + "' " + TIP_("into") + " '" + catalog_item_.get_name() + "'"; @@ -439,6 +444,18 @@ bool AssetCatalogDropController::drop_assets_into_catalog(const AssetCatalogTree return true; } +AssetCatalog *AssetCatalogDropController::get_drag_catalog(const wmDrag &drag) const +{ + if (drag.type != WM_DRAG_ASSET_CATALOG) { + return nullptr; + } + const bke::AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service( + &get_asset_library()); + const wmDragAssetCatalog *catalog_drag = WM_drag_get_asset_catalog_data(&drag); + + return catalog_service->find_catalog(catalog_drag->drag_catalog_id); +} + bool AssetCatalogDropController::has_droppable_asset(const wmDrag &drag, const char **r_disabled_hint) { diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 66aabe39e44..e393cc41a86 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -178,6 +178,10 @@ static void file_draw_icon(const SpaceFile *sfile, if ((id = filelist_file_get_id(file))) { UI_but_drag_set_id(but, id); + ImBuf *preview_image = filelist_file_getimage(file); + if (preview_image) { + UI_but_drag_attach_image(but, preview_image, UI_DPI_FAC); + } } else if (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS && (file->typeflag & FILE_TYPE_ASSET) != 0) { @@ -504,6 +508,7 @@ static void file_draw_preview(const SpaceFile *sfile, if ((id = filelist_file_get_id(file))) { UI_but_drag_set_id(but, id); + UI_but_drag_attach_image(but, imb, scale); } /* path is no more static, cannot give it directly to but... */ else if (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS && diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c index 0e468718a04..540d4729ed6 100644 --- a/source/blender/editors/space_file/file_panels.c +++ b/source/blender/editors/space_file/file_panels.c @@ -41,6 +41,7 @@ #include "ED_fileselect.h" #include "UI_interface.h" +#include "UI_interface_icons.h" #include "UI_resources.h" #include "WM_api.h" @@ -246,7 +247,20 @@ static void file_panel_asset_catalog_buttons_draw(const bContext *C, Panel *pane RNA_pointer_create(&screen->id, &RNA_FileAssetSelectParams, params, ¶ms_ptr); uiItemR(row, ¶ms_ptr, "asset_library_ref", 0, "", ICON_NONE); - if (params->asset_library_ref.type != ASSET_LIBRARY_LOCAL) { + if (params->asset_library_ref.type == ASSET_LIBRARY_LOCAL) { + bContext *mutable_ctx = CTX_copy(C); + if (WM_operator_name_poll(mutable_ctx, "asset.bundle_install")) { + uiItemS(col); + uiItemMenuEnumO(col, + mutable_ctx, + "asset.bundle_install", + "asset_library_ref", + "Copy Bundle to Asset Library...", + ICON_IMPORT); + } + CTX_free(mutable_ctx); + } + else { uiItemO(row, "", ICON_FILE_REFRESH, "FILE_OT_asset_library_refresh"); } diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index a73fa2b9740..6f929c43e13 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -914,24 +914,14 @@ static void prepare_filter_asset_library(const FileList *filelist, FileListFilte if (!filter->asset_catalog_filter) { return; } + BLI_assert_msg(filelist->asset_library, + "prepare_filter_asset_library() should only be called when the file browser is " + "in asset browser mode"); file_ensure_updated_catalog_filter_data(filter->asset_catalog_filter, filelist->asset_library); } /** - * Copy a string from source to `dest`, but prefix and suffix it with a single space. - * Assumes `dest` has at least space enough for the two spaces. - */ -static void tag_copy_with_spaces(char *dest, const char *source, const size_t dest_size) -{ - BLI_assert(dest_size > 2); - const size_t source_length = BLI_strncpy_rlen(dest + 1, source, dest_size - 2); - dest[0] = ' '; - dest[source_length + 1] = ' '; - dest[source_length + 2] = '\0'; -} - -/** * Return whether at least one tag matches the search filter. * Tags are searched as "entire words", so instead of searching for "tag" in the * filter string, this function searches for " tag ". Assumes the search filter @@ -946,9 +936,7 @@ static void tag_copy_with_spaces(char *dest, const char *source, const size_t de static bool asset_tag_matches_filter(const char *filter_search, const AssetMetaData *asset_data) { LISTBASE_FOREACH (const AssetTag *, asset_tag, &asset_data->tags) { - char tag_name[MAX_NAME + 2]; /* sizeof(AssetTag::name) + 2 */ - tag_copy_with_spaces(tag_name, asset_tag->name, sizeof(tag_name)); - if (BLI_strcasestr(filter_search, tag_name) != NULL) { + if (BLI_strcasestr(asset_tag->name, filter_search) != NULL) { return true; } } @@ -979,13 +967,7 @@ static bool is_filtered_asset(FileListInternEntry *file, FileListFilter *filter) if (BLI_strcasestr(file->name, filter_search + 1) != NULL) { return true; } - - /* Replace the asterisks with spaces, so that we can do matching on " sometag "; that way - * an artist searching for "redder" doesn't result in a match for the tag "red". */ - filter_search[string_length - 1] = ' '; - filter_search[0] = ' '; - - return asset_tag_matches_filter(filter_search, asset_data); + return asset_tag_matches_filter(filter_search + 1, asset_data); } static bool is_filtered_lib_type(FileListInternEntry *file, @@ -1728,7 +1710,7 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry return; } - if (entry->flags & FILE_ENTRY_INVALID_PREVIEW) { + if (entry->flags & (FILE_ENTRY_INVALID_PREVIEW | FILE_ENTRY_PREVIEW_LOADING)) { return; } @@ -1759,6 +1741,7 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry FileListEntryPreviewTaskData *preview_taskdata = MEM_mallocN(sizeof(*preview_taskdata), __func__); preview_taskdata->preview = preview; + entry->flags |= FILE_ENTRY_PREVIEW_LOADING; BLI_task_pool_push(cache->previews_pool, filelist_cache_preview_runf, preview_taskdata, @@ -1876,11 +1859,13 @@ void filelist_settype(FileList *filelist, short type) case FILE_MAIN: filelist->check_dir_fn = filelist_checkdir_main; filelist->read_job_fn = filelist_readjob_main; + filelist->prepare_filter_fn = NULL; filelist->filter_fn = is_filtered_main; break; case FILE_LOADLIB: filelist->check_dir_fn = filelist_checkdir_lib; filelist->read_job_fn = filelist_readjob_lib; + filelist->prepare_filter_fn = NULL; filelist->filter_fn = is_filtered_lib; break; case FILE_ASSET_LIBRARY: @@ -1900,6 +1885,7 @@ void filelist_settype(FileList *filelist, short type) default: filelist->check_dir_fn = filelist_checkdir_dir; filelist->read_job_fn = filelist_readjob_dir; + filelist->prepare_filter_fn = NULL; filelist->filter_fn = is_filtered_file; break; } @@ -2674,24 +2660,27 @@ bool filelist_cache_previews_update(FileList *filelist) // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); - if (preview->icon_id) { - /* Due to asynchronous process, a preview for a given image may be generated several times, - * i.e. entry->image may already be set at this point. */ - if (entry && !entry->preview_icon_id) { + if (entry) { + if (preview->icon_id) { + /* The FILE_ENTRY_PREVIEW_LOADING flag should have prevented any other asynchronous + * process from trying to generate the same preview icon. */ + BLI_assert_msg(!entry->preview_icon_id, "Preview icon should not have been generated yet"); + /* Move ownership over icon. */ entry->preview_icon_id = preview->icon_id; preview->icon_id = 0; changed = true; } else { - BKE_icon_delete(preview->icon_id); + /* We want to avoid re-processing this entry continuously! + * Note that, since entries only live in cache, + * preview will be retried quite often anyway. */ + entry->flags |= FILE_ENTRY_INVALID_PREVIEW; } + entry->flags &= ~FILE_ENTRY_PREVIEW_LOADING; } - else if (entry) { - /* We want to avoid re-processing this entry continuously! - * Note that, since entries only live in cache, - * preview will be retried quite often anyway. */ - entry->flags |= FILE_ENTRY_INVALID_PREVIEW; + else { + BKE_icon_delete(preview->icon_id); } MEM_freeN(preview); @@ -3711,7 +3700,7 @@ static void filelist_readjob_main_assets_add_items(FileListReadJob *job_params, BKE_main_lock(job_params->current_main); FOREACH_MAIN_ID_BEGIN (job_params->current_main, id_iter) { - if (!id_iter->asset_data) { + if (!id_iter->asset_data || ID_IS_LINKED(id_iter)) { continue; } diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 11757975a62..c59398e0016 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -411,6 +411,15 @@ FileAssetSelectParams *ED_fileselect_get_asset_params(const SpaceFile *sfile) return (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS) ? sfile->asset_params : NULL; } +bool ED_fileselect_is_local_asset_library(const SpaceFile *sfile) +{ + const FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile); + if (asset_params == NULL) { + return false; + } + return asset_params->asset_library_ref.type == ASSET_LIBRARY_LOCAL; +} + static void fileselect_refresh_asset_params(FileAssetSelectParams *asset_params) { AssetLibraryReference *library = &asset_params->asset_library_ref; diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index af88bbced9c..3635e9deb29 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -1060,21 +1060,21 @@ static void draw_fcurve(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, bAn const uint shdr_pos = GPU_vertformat_attr_add( immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); - float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); - - immUniform1i("colors_len", 0); /* Simple dashes. */ if (BKE_fcurve_is_protected(fcu)) { - /* protected curves (non editable) are drawn with dotted lines */ + /* Protected curves (non editable) are drawn with dotted lines. */ + immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); + immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); + immUniform1i("colors_len", 0); /* Simple dashes. */ immUniform1f("dash_width", 4.0f); immUniform1f("dash_factor", 0.5f); } else { - immUniform1f("dash_factor", 2.0f); /* solid line */ + immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR); + immUniform2fv("viewportSize", &viewport_size[2]); + immUniform1f("lineWidth", GPU_line_width_get()); } if (((fcu->grp) && (fcu->grp->flag & AGRP_MUTED)) || (fcu->flag & FCURVE_MUTED)) { diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index 22a43ea3794..d76b1842c94 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -185,7 +185,7 @@ void ED_image_draw_info(Scene *scene, GPU_blend(GPU_BLEND_NONE); - BLF_size(blf_mono_font, 11 * U.pixelsize, U.dpi); + BLF_size(blf_mono_font, 11.0f * U.pixelsize, U.dpi); BLF_color3ub(blf_mono_font, 255, 255, 255); SNPRINTF(str, "X:%-4d Y:%-4d |", x, y); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 478e484924a..44794439f5f 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -3191,7 +3191,10 @@ void IMAGE_OT_unpack(wmOperatorType *ot) * \{ */ /* Returns mouse position in image space. */ -bool ED_space_image_get_position(SpaceImage *sima, struct ARegion *ar, int mval[2], float fpos[2]) +bool ED_space_image_get_position(SpaceImage *sima, + struct ARegion *region, + int mval[2], + float fpos[2]) { void *lock; ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, 0); @@ -3201,7 +3204,7 @@ bool ED_space_image_get_position(SpaceImage *sima, struct ARegion *ar, int mval[ return false; } - UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &fpos[0], &fpos[1]); + UI_view2d_region_to_view(®ion->v2d, mval[0], mval[1], &fpos[0], &fpos[1]); ED_space_image_release_buffer(sima, ibuf, lock); return true; diff --git a/source/blender/editors/space_info/CMakeLists.txt b/source/blender/editors/space_info/CMakeLists.txt index b6df07eec4e..144b21fb9b8 100644 --- a/source/blender/editors/space_info/CMakeLists.txt +++ b/source/blender/editors/space_info/CMakeLists.txt @@ -37,7 +37,7 @@ set(SRC info_draw.c info_ops.c info_report.c - info_stats.c + info_stats.cc space_info.c textview.c diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.cc index 13d15bc50a6..19c98fb4d17 100644 --- a/source/blender/editors/space_info/info_stats.c +++ b/source/blender/editors/space_info/info_stats.cc @@ -18,8 +18,8 @@ * \ingroup spinfo */ -#include <stdio.h> -#include <string.h> +#include <cstdio> +#include <cstring> #include "MEM_guardedalloc.h" @@ -70,9 +70,11 @@ #include "GPU_capabilities.h" +ENUM_OPERATORS(eUserpref_StatusBar_Flag, STATUSBAR_SHOW_VERSION) + #define MAX_INFO_NUM_LEN 16 -typedef struct SceneStats { +struct SceneStats { uint64_t totvert, totvertsel, totvertsculpt; uint64_t totedge, totedgesel; uint64_t totface, totfacesel, totfacesculpt; @@ -81,9 +83,9 @@ typedef struct SceneStats { uint64_t totlamp, totlampsel; uint64_t tottri; uint64_t totgplayer, totgpframe, totgpstroke, totgppoint; -} SceneStats; +}; -typedef struct SceneStatsFmt { +struct SceneStatsFmt { /* Totals */ char totvert[MAX_INFO_NUM_LEN], totvertsel[MAX_INFO_NUM_LEN], totvertsculpt[MAX_INFO_NUM_LEN]; char totface[MAX_INFO_NUM_LEN], totfacesel[MAX_INFO_NUM_LEN]; @@ -94,16 +96,16 @@ typedef struct SceneStatsFmt { char tottri[MAX_INFO_NUM_LEN]; char totgplayer[MAX_INFO_NUM_LEN], totgpframe[MAX_INFO_NUM_LEN]; char totgpstroke[MAX_INFO_NUM_LEN], totgppoint[MAX_INFO_NUM_LEN]; -} SceneStatsFmt; +}; static bool stats_mesheval(const Mesh *me_eval, bool is_selected, SceneStats *stats) { - if (me_eval == NULL) { + if (me_eval == nullptr) { return false; } int totvert, totedge, totface, totloop; - if (me_eval->runtime.subdiv_ccg != NULL) { + if (me_eval->runtime.subdiv_ccg != nullptr) { const SubdivCCG *subdiv_ccg = me_eval->runtime.subdiv_ccg; BKE_subdiv_ccg_topology_counters(subdiv_ccg, &totvert, &totedge, &totface, &totloop); } @@ -166,14 +168,14 @@ static void stats_object(Object *ob, case OB_CURVE: case OB_FONT: { const Mesh *me_eval = BKE_object_get_evaluated_mesh(ob); - if ((me_eval != NULL) && !BLI_gset_add(objects_gset, (void *)me_eval)) { + if ((me_eval != nullptr) && !BLI_gset_add(objects_gset, (void *)me_eval)) { break; } if (stats_mesheval(me_eval, is_selected, stats)) { break; } - ATTR_FALLTHROUGH; /* Fallthrough to displist. */ + ATTR_FALLTHROUGH; /* Fall-through to displist. */ } case OB_MBALL: { int totv = 0, totf = 0, tottri = 0; @@ -242,10 +244,9 @@ static void stats_object_edit(Object *obedit, SceneStats *stats) } else if (obedit->type == OB_ARMATURE) { /* Armature Edit */ - bArmature *arm = obedit->data; - EditBone *ebo; + bArmature *arm = static_cast<bArmature *>(obedit->data); - for (ebo = arm->edbo->first; ebo; ebo = ebo->next) { + LISTBASE_FOREACH (EditBone *, ebo, arm->edbo) { stats->totbone++; if ((ebo->flag & BONE_CONNECTED) && ebo->parent) { @@ -274,14 +275,13 @@ static void stats_object_edit(Object *obedit, SceneStats *stats) } else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) { /* OB_FONT has no cu->editnurb */ /* Curve Edit */ - Curve *cu = obedit->data; - Nurb *nu; + Curve *cu = static_cast<Curve *>(obedit->data); BezTriple *bezt; BPoint *bp; int a; ListBase *nurbs = BKE_curve_editNurbs_get(cu); - for (nu = nurbs->first; nu; nu = nu->next) { + LISTBASE_FOREACH (Nurb *, nu, nurbs) { if (nu->type == CU_BEZIER) { bezt = nu->bezt; a = nu->pntsu; @@ -314,10 +314,9 @@ static void stats_object_edit(Object *obedit, SceneStats *stats) } else if (obedit->type == OB_MBALL) { /* MetaBall Edit */ - MetaBall *mball = obedit->data; - MetaElem *ml; + MetaBall *mball = static_cast<MetaBall *>(obedit->data); - for (ml = mball->editelems->first; ml; ml = ml->next) { + LISTBASE_FOREACH (MetaElem *, ml, mball->editelems) { stats->totvert++; if (ml->flag & SELECT) { stats->totvertsel++; @@ -326,7 +325,7 @@ static void stats_object_edit(Object *obedit, SceneStats *stats) } else if (obedit->type == OB_LATTICE) { /* Lattice Edit */ - Lattice *lt = obedit->data; + Lattice *lt = static_cast<Lattice *>(obedit->data); Lattice *editlatt = lt->editlatt->latt; BPoint *bp; int a; @@ -347,10 +346,9 @@ static void stats_object_edit(Object *obedit, SceneStats *stats) static void stats_object_pose(const Object *ob, SceneStats *stats) { if (ob->pose) { - bArmature *arm = ob->data; - bPoseChannel *pchan; + bArmature *arm = static_cast<bArmature *>(ob->data); - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { stats->totbone++; if (pchan->bone && (pchan->bone->flag & BONE_SELECTED)) { if (pchan->bone->layer & arm->layer) { @@ -372,7 +370,7 @@ static void stats_object_sculpt(const Object *ob, SceneStats *stats) SculptSession *ss = ob->sculpt; - if (ss == NULL || ss->pbvh == NULL) { + if (ss == nullptr || ss->pbvh == nullptr) { return; } @@ -460,7 +458,7 @@ static void stats_update(Depsgraph *depsgraph, stats_object(ob_iter, v3d_local, stats, objects_gset); } DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END; - BLI_gset_free(objects_gset, NULL); + BLI_gset_free(objects_gset, nullptr); } } @@ -476,7 +474,7 @@ void ED_info_stats_clear(wmWindowManager *wm, ViewLayer *view_layer) const bScreen *screen = WM_window_get_active_screen(win); LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { if (area->spacetype == SPACE_VIEW3D) { - View3D *v3d = area->spacedata.first; + View3D *v3d = (View3D *)area->spacedata.first; if (v3d->localvd) { MEM_SAFE_FREE(v3d->runtime.local_stats); } @@ -490,14 +488,14 @@ static bool format_stats( { /* Create stats if they don't already exist. */ SceneStats **stats_p = (v3d_local) ? &v3d_local->runtime.local_stats : &view_layer->stats; - if (*stats_p == NULL) { + if (*stats_p == nullptr) { /* Don't access dependency graph if interface is marked as locked. */ - wmWindowManager *wm = bmain->wm.first; + wmWindowManager *wm = (wmWindowManager *)bmain->wm.first; if (wm->is_interface_locked) { return false; } Depsgraph *depsgraph = BKE_scene_ensure_depsgraph(bmain, scene, view_layer); - *stats_p = MEM_mallocN(sizeof(SceneStats), __func__); + *stats_p = (SceneStats *)MEM_mallocN(sizeof(SceneStats), __func__); stats_update(depsgraph, view_layer, v3d_local, *stats_p); } @@ -542,7 +540,7 @@ static void get_stats_string( { Object *ob = OBACT(view_layer); Object *obedit = OBEDIT_FROM_OBACT(ob); - eObjectMode object_mode = ob ? ob->mode : OB_MODE_OBJECT; + eObjectMode object_mode = ob ? (eObjectMode)ob->mode : OB_MODE_OBJECT; LayerCollection *layer_collection = view_layer->active_collection; if (object_mode == OB_MODE_OBJECT) { @@ -646,7 +644,7 @@ static const char *info_statusbar_string(Main *bmain, /* Scene statistics. */ if (statusbar_flag & STATUSBAR_SHOW_STATS) { SceneStatsFmt stats_fmt; - if (format_stats(bmain, scene, view_layer, NULL, &stats_fmt)) { + if (format_stats(bmain, scene, view_layer, nullptr, &stats_fmt)) { get_stats_string(info + ofs, len, &ofs, view_layer, &stats_fmt); } } @@ -731,7 +729,7 @@ static void stats_row(int col1, void ED_info_draw_stats( Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d_local, int x, int *y, int height) { - BLI_assert(v3d_local == NULL || v3d_local->localvd != NULL); + BLI_assert(v3d_local == nullptr || v3d_local->localvd != nullptr); SceneStatsFmt stats_fmt; if (!format_stats(bmain, scene, view_layer, v3d_local, &stats_fmt)) { return; @@ -739,7 +737,7 @@ void ED_info_draw_stats( Object *ob = OBACT(view_layer); Object *obedit = OBEDIT_FROM_OBACT(ob); - eObjectMode object_mode = ob ? ob->mode : OB_MODE_OBJECT; + eObjectMode object_mode = ob ? (eObjectMode)ob->mode : OB_MODE_OBJECT; const int font_id = BLF_set_default(); UI_FontThemeColor(font_id, TH_TEXT_HI); @@ -801,7 +799,7 @@ void ED_info_draw_stats( stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height); stats_row(col1, labels[EDGES], col2, stats_fmt.totedgesel, stats_fmt.totedge, y, height); stats_row(col1, labels[FACES], col2, stats_fmt.totfacesel, stats_fmt.totface, y, height); - stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height); + stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, nullptr, y, height); } else if (obedit->type == OB_ARMATURE) { stats_row(col1, labels[JOINTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height); @@ -816,15 +814,15 @@ void ED_info_draw_stats( stats_row(col1, labels[BONES], col2, stats_fmt.totbonesel, stats_fmt.totbone, y, height); } else if ((ob) && (ob->type == OB_GPENCIL)) { - stats_row(col1, labels[LAYERS], col2, stats_fmt.totgplayer, NULL, y, height); - stats_row(col1, labels[FRAMES], col2, stats_fmt.totgpframe, NULL, y, height); - stats_row(col1, labels[STROKES], col2, stats_fmt.totgpstroke, NULL, y, height); - stats_row(col1, labels[POINTS], col2, stats_fmt.totgppoint, NULL, y, height); + stats_row(col1, labels[LAYERS], col2, stats_fmt.totgplayer, nullptr, y, height); + stats_row(col1, labels[FRAMES], col2, stats_fmt.totgpframe, nullptr, y, height); + stats_row(col1, labels[STROKES], col2, stats_fmt.totgpstroke, nullptr, y, height); + stats_row(col1, labels[POINTS], col2, stats_fmt.totgppoint, nullptr, y, height); } else if (ob && (object_mode & OB_MODE_SCULPT)) { if (stats_is_object_dynamic_topology_sculpt(ob)) { - stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsculpt, NULL, y, height); - stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height); + stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsculpt, nullptr, y, height); + stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, nullptr, y, height); } else { stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsculpt, stats_fmt.totvert, y, height); @@ -835,10 +833,10 @@ void ED_info_draw_stats( stats_row(col1, labels[LIGHTS], col2, stats_fmt.totlampsel, stats_fmt.totlamp, y, height); } else { - stats_row(col1, labels[VERTS], col2, stats_fmt.totvert, NULL, y, height); - stats_row(col1, labels[EDGES], col2, stats_fmt.totedge, NULL, y, height); - stats_row(col1, labels[FACES], col2, stats_fmt.totface, NULL, y, height); - stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height); + stats_row(col1, labels[VERTS], col2, stats_fmt.totvert, nullptr, y, height); + stats_row(col1, labels[EDGES], col2, stats_fmt.totedge, nullptr, y, height); + stats_row(col1, labels[FACES], col2, stats_fmt.totface, nullptr, y, height); + stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, nullptr, y, height); } BLF_disable(font_id, BLF_SHADOW); diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt index 600309c2c86..e88d61fe880 100644 --- a/source/blender/editors/space_node/CMakeLists.txt +++ b/source/blender/editors/space_node/CMakeLists.txt @@ -44,17 +44,17 @@ set(SRC node_draw.cc node_edit.cc node_geometry_attribute_search.cc - node_gizmo.c + node_gizmo.cc node_group.cc - node_ops.c + node_ops.cc node_relationships.cc node_select.cc node_templates.cc node_toolbar.cc node_view.cc - space_node.c + space_node.cc - node_intern.h + node_intern.hh ) set(LIB diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc index fe866a81f67..cf79893a8cb 100644 --- a/source/blender/editors/space_node/drawnode.cc +++ b/source/blender/editors/space_node/drawnode.cc @@ -39,6 +39,7 @@ #include "BKE_image.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_scene.h" #include "BKE_tracking.h" #include "BLF_api.h" @@ -76,7 +77,7 @@ #include "NOD_node_declaration.hh" #include "NOD_shader.h" #include "NOD_texture.h" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ /* Default flags for uiItemR(). Name is kept short since this is used a lot in this file. */ #define DEFAULT_FLAGS UI_ITEM_R_SPLIT_EMPTY_NAME @@ -151,7 +152,7 @@ static void node_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *pt uiTemplateCurveMapping(layout, ptr, "curve", 's', false, false, false, false); uiLayout *row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "frame_start", DEFAULT_FLAGS, IFACE_("Sta"), ICON_NONE); + uiItemR(row, ptr, "frame_start", DEFAULT_FLAGS, IFACE_("Start"), ICON_NONE); uiItemR(row, ptr, "frame_end", DEFAULT_FLAGS, IFACE_("End"), ICON_NONE); } @@ -341,7 +342,7 @@ static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float asp /* XXX font id is crap design */ const int fontid = UI_style_get()->widgetlabel.uifont_id; NodeFrame *data = (NodeFrame *)node->storage; - const int font_size = data->label_size / aspect; + const float font_size = data->label_size / aspect; char label[MAX_NAME]; nodeLabel(ntree, node, label, sizeof(label)); @@ -349,7 +350,7 @@ static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float asp BLF_enable(fontid, BLF_ASPECT); BLF_aspect(fontid, aspect, aspect, 1.0f); /* clamp otherwise it can suck up a LOT of memory */ - BLF_size(fontid, MIN2(24, font_size), U.dpi); + BLF_size(fontid, MIN2(24.0f, font_size), U.dpi); /* title color */ int color_id = node_get_colorid(node); @@ -811,7 +812,7 @@ static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, P uiItemR(layout, ptr, "projection", DEFAULT_FLAGS, IFACE_("Projection"), ICON_NONE); } -static void node_shader_buts_tex_sky(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_shader_buts_tex_sky(uiLayout *layout, bContext *C, PointerRNA *ptr) { uiItemR(layout, ptr, "sky_type", DEFAULT_FLAGS, "", ICON_NONE); @@ -825,6 +826,10 @@ static void node_shader_buts_tex_sky(uiLayout *layout, bContext *UNUSED(C), Poin uiItemR(layout, ptr, "ground_albedo", DEFAULT_FLAGS, nullptr, ICON_NONE); } if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_NISHITA) { + Scene *scene = CTX_data_scene(C); + if (BKE_scene_uses_blender_eevee(scene)) { + uiItemL(layout, TIP_("Nishita not available in Eevee"), ICON_ERROR); + } uiItemR(layout, ptr, "sun_disc", DEFAULT_FLAGS, nullptr, 0); uiLayout *col; @@ -4308,9 +4313,7 @@ void node_draw_link_bezier(const bContext *C, } if (snode->overlay.flag & SN_OVERLAY_SHOW_OVERLAYS && - snode->overlay.flag & SN_OVERLAY_SHOW_WIRE_COLORS && - ((link->fromsock == nullptr || link->fromsock->typeinfo->type >= 0) && - (link->tosock == nullptr || link->tosock->typeinfo->type >= 0))) { + snode->overlay.flag & SN_OVERLAY_SHOW_WIRE_COLORS) { PointerRNA from_node_ptr, to_node_ptr; RNA_pointer_create((ID *)snode->edittree, &RNA_Node, link->fromnode, &from_node_ptr); RNA_pointer_create((ID *)snode->edittree, &RNA_Node, link->tonode, &to_node_ptr); @@ -4396,7 +4399,10 @@ void node_draw_link_bezier(const bContext *C, } /* NOTE: this is used for fake links in groups too. */ -void node_draw_link(const bContext *C, View2D *v2d, SpaceNode *snode, bNodeLink *link) +void node_draw_link(const bContext *C, + const View2D *v2d, + const SpaceNode *snode, + const bNodeLink *link) { int th_col1 = TH_WIRE_INNER, th_col2 = TH_WIRE_INNER, th_col3 = TH_WIRE; diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc index cb66d0dbd2b..2e3579caaa1 100644 --- a/source/blender/editors/space_node/node_add.cc +++ b/source/blender/editors/space_node/node_add.cc @@ -56,7 +56,7 @@ #include "UI_view2d.h" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ /* -------------------------------------------------------------------- */ /** \name Utilities @@ -445,15 +445,14 @@ void NODE_OT_add_group(wmOperatorType *ot) static Object *node_add_object_get_and_poll_object_node_tree(Main *bmain, wmOperator *op) { - char name[MAX_ID_NAME - 2]; - RNA_string_get(op->ptr, "name", name); - - Object *object = (Object *)BKE_libblock_find_name(bmain, ID_OB, name); - if (!object) { - return nullptr; + if (RNA_struct_property_is_set(op->ptr, "session_uuid")) { + const uint32_t session_uuid = (uint32_t)RNA_int_get(op->ptr, "session_uuid"); + return (Object *)BKE_libblock_find_session_uuid(bmain, ID_OB, session_uuid); } - return object; + char name[MAX_ID_NAME - 2]; + RNA_string_get(op->ptr, "name", name); + return (Object *)BKE_libblock_find_name(bmain, ID_OB, name); } static int node_add_object_exec(bContext *C, wmOperator *op) @@ -539,6 +538,15 @@ void NODE_OT_add_object(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; RNA_def_string(ot->srna, "name", "Object", MAX_ID_NAME - 2, "Name", "Data-block name to assign"); + RNA_def_int(ot->srna, + "session_uuid", + 0, + INT32_MIN, + INT32_MAX, + "Session UUID", + "Session UUID of the data-block to assign", + INT32_MIN, + INT32_MAX); } /** \} */ @@ -549,15 +557,14 @@ void NODE_OT_add_object(wmOperatorType *ot) static Tex *node_add_texture_get_and_poll_texture_node_tree(Main *bmain, wmOperator *op) { - char name[MAX_ID_NAME - 2]; - RNA_string_get(op->ptr, "name", name); - - Tex *texture = (Tex *)BKE_libblock_find_name(bmain, ID_TE, name); - if (!texture) { - return nullptr; + if (RNA_struct_property_is_set(op->ptr, "session_uuid")) { + const uint32_t session_uuid = (uint32_t)RNA_int_get(op->ptr, "session_uuid"); + return (Tex *)BKE_libblock_find_session_uuid(bmain, ID_TE, session_uuid); } - return texture; + char name[MAX_ID_NAME - 2]; + RNA_string_get(op->ptr, "name", name); + return (Tex *)BKE_libblock_find_name(bmain, ID_TE, name); } static int node_add_texture_exec(bContext *C, wmOperator *op) @@ -640,6 +647,15 @@ void NODE_OT_add_texture(wmOperatorType *ot) RNA_def_string( ot->srna, "name", "Texture", MAX_ID_NAME - 2, "Name", "Data-block name to assign"); + RNA_def_int(ot->srna, + "session_uuid", + 0, + INT32_MIN, + INT32_MAX, + "Session UUID", + "Session UUID of the data-block to assign", + INT32_MIN, + INT32_MAX); } /** \} */ @@ -651,15 +667,14 @@ void NODE_OT_add_texture(wmOperatorType *ot) static Collection *node_add_collection_get_and_poll_collection_node_tree(Main *bmain, wmOperator *op) { - char name[MAX_ID_NAME - 2]; - RNA_string_get(op->ptr, "name", name); - - Collection *collection = (Collection *)BKE_libblock_find_name(bmain, ID_GR, name); - if (!collection) { - return nullptr; + if (RNA_struct_property_is_set(op->ptr, "session_uuid")) { + const uint32_t session_uuid = (uint32_t)RNA_int_get(op->ptr, "session_uuid"); + return (Collection *)BKE_libblock_find_session_uuid(bmain, ID_GR, session_uuid); } - return collection; + char name[MAX_ID_NAME - 2]; + RNA_string_get(op->ptr, "name", name); + return (Collection *)BKE_libblock_find_name(bmain, ID_GR, name); } static int node_add_collection_exec(bContext *C, wmOperator *op) @@ -746,6 +761,15 @@ void NODE_OT_add_collection(wmOperatorType *ot) RNA_def_string( ot->srna, "name", "Collection", MAX_ID_NAME - 2, "Name", "Data-block name to assign"); + RNA_def_int(ot->srna, + "session_uuid", + 0, + INT32_MIN, + INT32_MAX, + "Session UUID", + "Session UUID of the data-block to assign", + INT32_MIN, + INT32_MAX); } /** \} */ @@ -877,6 +901,18 @@ void NODE_OT_add_file(wmOperatorType *ot) /** \name Add Mask Node Operator * \{ */ +static ID *node_add_mask_get_and_poll_mask(Main *bmain, wmOperator *op) +{ + if (RNA_struct_property_is_set(op->ptr, "session_uuid")) { + const uint32_t session_uuid = (uint32_t)RNA_int_get(op->ptr, "session_uuid"); + return BKE_libblock_find_session_uuid(bmain, ID_MSK, session_uuid); + } + + char name[MAX_ID_NAME - 2]; + RNA_string_get(op->ptr, "name", name); + return BKE_libblock_find_name(bmain, ID_MSK, name); +} + static bool node_add_mask_poll(bContext *C) { SpaceNode *snode = CTX_wm_space_node(C); @@ -889,14 +925,9 @@ static int node_add_mask_exec(bContext *C, wmOperator *op) Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); bNode *node; - ID *mask = nullptr; - /* check input variables */ - char name[MAX_ID_NAME - 2]; - RNA_string_get(op->ptr, "name", name); - mask = BKE_libblock_find_name(bmain, ID_MSK, name); + ID *mask = node_add_mask_get_and_poll_mask(bmain, op); if (!mask) { - BKE_reportf(op->reports, RPT_ERROR, "Mask '%s' not found", name); return OPERATOR_CANCELLED; } @@ -935,6 +966,15 @@ void NODE_OT_add_mask(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; RNA_def_string(ot->srna, "name", "Mask", MAX_ID_NAME - 2, "Name", "Data-block name to assign"); + RNA_def_int(ot->srna, + "session_uuid", + 0, + INT32_MIN, + INT32_MAX, + "Session UUID", + "Session UUID of the data-block to assign", + INT32_MIN, + INT32_MAX); } /** \} */ diff --git a/source/blender/editors/space_node/node_context_path.cc b/source/blender/editors/space_node/node_context_path.cc index a0ff7f3ce25..2f3855fd654 100644 --- a/source/blender/editors/space_node/node_context_path.cc +++ b/source/blender/editors/space_node/node_context_path.cc @@ -43,7 +43,7 @@ #include "UI_interface.hh" -#include "node_intern.h" +#include "node_intern.hh" struct Mesh; struct Curve; diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index 5fdf816339b..867544d0805 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -85,7 +85,7 @@ #include "FN_field_cpp_type.hh" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ #ifdef WITH_COMPOSITOR # include "COM_compositor.h" @@ -1842,7 +1842,13 @@ static void node_draw_basis(const bContext *C, UI_draw_roundbox_4fv(&rect, false, BASIS_RAD, color_outline); } - node_draw_sockets(v2d, C, ntree, node, true, false); + float scale; + UI_view2d_scale_get(v2d, &scale, nullptr); + + /* Skip slow socket drawing if zoom is small. */ + if (scale > 0.2f) { + node_draw_sockets(v2d, C, ntree, node, true, false); + } /* Preview. */ bNodeInstanceHash *previews = (bNodeInstanceHash *)CTX_data_pointer_get(C, "node_previews").data; @@ -2110,15 +2116,15 @@ static void count_multi_input_socket_links(bNodeTree *ntree, SpaceNode *snode) } } /* Count temporary links going into this socket. */ - LISTBASE_FOREACH (bNodeLinkDrag *, nldrag, &snode->runtime->linkdrag) { - LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { - bNodeLink *link = (bNodeLink *)linkdata->data; + if (snode->runtime->linkdrag) { + for (const bNodeLink *link : snode->runtime->linkdrag->links) { if (link->tosock && (link->tosock->flag & SOCK_MULTI_INPUT)) { int &count = counts.lookup_or_add(link->tosock, 0); count++; } } } + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { if (socket->flag & SOCK_MULTI_INPUT) { @@ -2377,9 +2383,9 @@ void node_draw_space(const bContext *C, ARegion *region) /* Temporary links. */ GPU_blend(GPU_BLEND_ALPHA); GPU_line_smooth(true); - LISTBASE_FOREACH (bNodeLinkDrag *, nldrag, &snode->runtime->linkdrag) { - LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { - node_draw_link(C, v2d, snode, (bNodeLink *)linkdata->data); + if (snode->runtime->linkdrag) { + for (const bNodeLink *link : snode->runtime->linkdrag->links) { + node_draw_link(C, v2d, snode, link); } } GPU_line_smooth(false); diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc index 030d1672a08..30c9f7ea56b 100644 --- a/source/blender/editors/space_node/node_edit.cc +++ b/source/blender/editors/space_node/node_edit.cc @@ -76,7 +76,7 @@ #include "NOD_geometry.h" #include "NOD_shader.h" #include "NOD_texture.h" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ #define USE_ESC_COMPO @@ -1192,7 +1192,7 @@ static bool cursor_isect_multi_input_socket(const float cursor[2], const bNodeSo } /* type is SOCK_IN and/or SOCK_OUT */ -int node_find_indicated_socket( +bool node_find_indicated_socket( SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, const float cursor[2], int in_out) { rctf rect; @@ -1224,7 +1224,7 @@ int node_find_indicated_socket( if (node == visible_node(snode, &rect)) { *nodep = node; *sockp = sock; - return 1; + return true; } } } @@ -1232,7 +1232,7 @@ int node_find_indicated_socket( if (node == visible_node(snode, &rect)) { *nodep = node; *sockp = sock; - return 1; + return true; } } } @@ -1245,7 +1245,7 @@ int node_find_indicated_socket( if (node == visible_node(snode, &rect)) { *nodep = node; *sockp = sock; - return 1; + return true; } } } @@ -1253,7 +1253,7 @@ int node_find_indicated_socket( } } - return 0; + return false; } /* ****************** Link Dimming *********************** */ @@ -1775,8 +1775,7 @@ static int node_mute_exec(bContext *C, wmOperator *UNUSED(op)) ED_preview_kill_jobs(CTX_wm_manager(C), bmain); LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { - /* Only allow muting of nodes having a mute func! */ - if ((node->flag & SELECT) && node->typeinfo->update_internal_links) { + if ((node->flag & SELECT) && !node->typeinfo->no_muting) { node->flag ^= NODE_MUTED; snode_update(snode, node); do_tag_update |= (do_tag_update || node_connected_to_output(bmain, snode->edittree, node)); diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc index d0ccbb03107..79ba9b8d2d9 100644 --- a/source/blender/editors/space_node/node_geometry_attribute_search.cc +++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc @@ -33,6 +33,7 @@ #include "RNA_access.h" #include "RNA_enum_types.h" +#include "ED_screen.h" #include "ED_undo.h" #include "BLT_translation.h" @@ -43,7 +44,7 @@ #include "NOD_geometry_nodes_eval_log.hh" -#include "node_intern.h" +#include "node_intern.hh" using blender::IndexRange; using blender::Map; @@ -64,6 +65,10 @@ BLI_STATIC_ASSERT(std::is_trivially_destructible_v<AttributeSearchData>, ""); static void attribute_search_update_fn( const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first) { + if (ED_screen_animation_playing(CTX_wm_manager(C))) { + return; + } + AttributeSearchData *data = static_cast<AttributeSearchData *>(arg); SpaceNode *snode = CTX_wm_space_node(C); @@ -79,6 +84,9 @@ static void attribute_search_update_fn( static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v) { + if (ED_screen_animation_playing(CTX_wm_manager(C))) { + return; + } if (item_v == nullptr) { return; } diff --git a/source/blender/editors/space_node/node_gizmo.c b/source/blender/editors/space_node/node_gizmo.cc index e1deca54890..717f4d2f4f9 100644 --- a/source/blender/editors/space_node/node_gizmo.c +++ b/source/blender/editors/space_node/node_gizmo.cc @@ -18,7 +18,7 @@ * \ingroup spnode */ -#include <math.h> +#include <cmath> #include "BLI_math_matrix.h" #include "BLI_math_vector.h" @@ -41,7 +41,7 @@ #include "WM_api.h" #include "WM_types.h" -#include "node_intern.h" +#include "node_intern.hh" /* -------------------------------------------------------------------- */ /** \name Local Utilities @@ -80,9 +80,9 @@ static void gizmo_node_backdrop_prop_matrix_get(const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, void *value_p) { - float(*matrix)[4] = value_p; + float(*matrix)[4] = (float(*)[4])value_p; BLI_assert(gz_prop->type->array_length == 16); - const SpaceNode *snode = gz_prop->custom_func.user_data; + const SpaceNode *snode = (const SpaceNode *)gz_prop->custom_func.user_data; matrix[0][0] = snode->zoom; matrix[1][1] = snode->zoom; matrix[3][0] = snode->xof; @@ -93,9 +93,9 @@ static void gizmo_node_backdrop_prop_matrix_set(const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, const void *value_p) { - const float(*matrix)[4] = value_p; + const float(*matrix)[4] = (const float(*)[4])value_p; BLI_assert(gz_prop->type->array_length == 16); - SpaceNode *snode = gz_prop->custom_func.user_data; + SpaceNode *snode = (SpaceNode *)gz_prop->custom_func.user_data; snode->zoom = matrix[0][0]; snode->xof = matrix[3][0]; snode->yof = matrix[3][1]; @@ -122,9 +122,9 @@ static bool WIDGETGROUP_node_transform_poll(const bContext *C, wmGizmoGroupType static void WIDGETGROUP_node_transform_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) { - wmGizmoWrapper *wwrapper = MEM_mallocN(sizeof(wmGizmoWrapper), __func__); + wmGizmoWrapper *wwrapper = (wmGizmoWrapper *)MEM_mallocN(sizeof(wmGizmoWrapper), __func__); - wwrapper->gizmo = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, NULL); + wwrapper->gizmo = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, nullptr); RNA_enum_set(wwrapper->gizmo->ptr, "transform", @@ -139,11 +139,11 @@ static void WIDGETGROUP_node_transform_refresh(const bContext *C, wmGizmoGroup * wmGizmo *cage = ((wmGizmoWrapper *)gzgroup->customdata)->gizmo; const ARegion *region = CTX_wm_region(C); /* center is always at the origin */ - const float origin[3] = {region->winx / 2, region->winy / 2}; + const float origin[3] = {float(region->winx / 2), float(region->winy / 2), 0.0f}; void *lock; Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock); if (ibuf) { const float dims[2] = { @@ -164,14 +164,12 @@ static void WIDGETGROUP_node_transform_refresh(const bContext *C, wmGizmoGroup * WM_gizmo_target_property_def_rna(cage, "scale", &nodeptr, "backdrop_zoom", -1); #endif - WM_gizmo_target_property_def_func(cage, - "matrix", - &(const struct wmGizmoPropertyFnParams){ - .value_get_fn = gizmo_node_backdrop_prop_matrix_get, - .value_set_fn = gizmo_node_backdrop_prop_matrix_set, - .range_get_fn = NULL, - .user_data = snode, - }); + wmGizmoPropertyFnParams params{}; + params.value_get_fn = gizmo_node_backdrop_prop_matrix_get; + params.value_set_fn = gizmo_node_backdrop_prop_matrix_set; + params.range_get_fn = nullptr; + params.user_data = snode; + WM_gizmo_target_property_def_func(cage, "matrix", ¶ms); } else { WM_gizmo_set_flag(cage, WM_GIZMO_HIDDEN, true); @@ -262,12 +260,12 @@ static void gizmo_node_crop_prop_matrix_get(const wmGizmo *gz, wmGizmoProperty *gz_prop, void *value_p) { - float(*matrix)[4] = value_p; + float(*matrix)[4] = (float(*)[4])value_p; BLI_assert(gz_prop->type->array_length == 16); - struct NodeCropWidgetGroup *crop_group = gz->parent_gzgroup->customdata; + NodeCropWidgetGroup *crop_group = (NodeCropWidgetGroup *)gz->parent_gzgroup->customdata; const float *dims = crop_group->state.dims; - const bNode *node = gz_prop->custom_func.user_data; - const NodeTwoXYs *nxy = node->storage; + const bNode *node = (const bNode *)gz_prop->custom_func.user_data; + const NodeTwoXYs *nxy = (const NodeTwoXYs *)node->storage; bool is_relative = (bool)node->custom2; rctf rct; two_xy_to_rect(nxy, &rct, dims, is_relative); @@ -281,12 +279,12 @@ static void gizmo_node_crop_prop_matrix_set(const wmGizmo *gz, wmGizmoProperty *gz_prop, const void *value_p) { - const float(*matrix)[4] = value_p; + const float(*matrix)[4] = (const float(*)[4])value_p; BLI_assert(gz_prop->type->array_length == 16); - struct NodeCropWidgetGroup *crop_group = gz->parent_gzgroup->customdata; + NodeCropWidgetGroup *crop_group = (NodeCropWidgetGroup *)gz->parent_gzgroup->customdata; const float *dims = crop_group->state.dims; - bNode *node = gz_prop->custom_func.user_data; - NodeTwoXYs *nxy = node->storage; + bNode *node = (bNode *)gz_prop->custom_func.user_data; + NodeTwoXYs *nxy = (NodeTwoXYs *)node->storage; bool is_relative = (bool)node->custom2; rctf rct; two_xy_to_rect(nxy, &rct, dims, is_relative); @@ -294,15 +292,8 @@ static void gizmo_node_crop_prop_matrix_set(const wmGizmo *gz, const bool ny = rct.ymin > rct.ymax; BLI_rctf_resize(&rct, fabsf(matrix[0][0]), fabsf(matrix[1][1])); BLI_rctf_recenter(&rct, (matrix[3][0] / dims[0]) + 0.5f, (matrix[3][1] / dims[1]) + 0.5f); - BLI_rctf_isect( - &(rctf){ - .xmin = 0, - .ymin = 0, - .xmax = 1, - .ymax = 1, - }, - &rct, - &rct); + const rctf rct_isect{0, 0, 1, 1}; + BLI_rctf_isect(&rct_isect, &rct, &rct); if (nx) { SWAP(float, rct.xmin, rct.xmax); } @@ -337,10 +328,10 @@ static bool WIDGETGROUP_node_crop_poll(const bContext *C, wmGizmoGroupType *UNUS static void WIDGETGROUP_node_crop_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) { - struct NodeCropWidgetGroup *crop_group = MEM_mallocN(sizeof(struct NodeCropWidgetGroup), - __func__); + struct NodeCropWidgetGroup *crop_group = (NodeCropWidgetGroup *)MEM_mallocN( + sizeof(struct NodeCropWidgetGroup), __func__); - crop_group->border = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, NULL); + crop_group->border = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, nullptr); RNA_enum_set(crop_group->border->ptr, "transform", @@ -352,7 +343,7 @@ static void WIDGETGROUP_node_crop_setup(const bContext *UNUSED(C), wmGizmoGroup static void WIDGETGROUP_node_crop_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup) { ARegion *region = CTX_wm_region(C); - wmGizmo *gz = gzgroup->gizmos.first; + wmGizmo *gz = (wmGizmo *)gzgroup->gizmos.first; SpaceNode *snode = CTX_wm_space_node(C); @@ -362,12 +353,12 @@ static void WIDGETGROUP_node_crop_draw_prepare(const bContext *C, wmGizmoGroup * static void WIDGETGROUP_node_crop_refresh(const bContext *C, wmGizmoGroup *gzgroup) { Main *bmain = CTX_data_main(C); - struct NodeCropWidgetGroup *crop_group = gzgroup->customdata; + NodeCropWidgetGroup *crop_group = (NodeCropWidgetGroup *)gzgroup->customdata; wmGizmo *gz = crop_group->border; void *lock; Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock); if (ibuf) { crop_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f; @@ -385,14 +376,12 @@ static void WIDGETGROUP_node_crop_refresh(const bContext *C, wmGizmoGroup *gzgro crop_group->update_data.prop = RNA_struct_find_property(&crop_group->update_data.ptr, "relative"); - WM_gizmo_target_property_def_func(gz, - "matrix", - &(const struct wmGizmoPropertyFnParams){ - .value_get_fn = gizmo_node_crop_prop_matrix_get, - .value_set_fn = gizmo_node_crop_prop_matrix_set, - .range_get_fn = NULL, - .user_data = node, - }); + wmGizmoPropertyFnParams params{}; + params.value_get_fn = gizmo_node_crop_prop_matrix_get; + params.value_set_fn = gizmo_node_crop_prop_matrix_set; + params.range_get_fn = nullptr; + params.user_data = snode; + WM_gizmo_target_property_def_func(gz, "matrix", ¶ms); } else { WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true); @@ -450,10 +439,10 @@ static bool WIDGETGROUP_node_sbeam_poll(const bContext *C, wmGizmoGroupType *UNU static void WIDGETGROUP_node_sbeam_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) { - struct NodeSunBeamsWidgetGroup *sbeam_group = MEM_mallocN(sizeof(struct NodeSunBeamsWidgetGroup), - __func__); + NodeSunBeamsWidgetGroup *sbeam_group = (NodeSunBeamsWidgetGroup *)MEM_mallocN( + sizeof(NodeSunBeamsWidgetGroup), __func__); - sbeam_group->gizmo = WM_gizmo_new("GIZMO_GT_move_3d", gzgroup, NULL); + sbeam_group->gizmo = WM_gizmo_new("GIZMO_GT_move_3d", gzgroup, nullptr); wmGizmo *gz = sbeam_group->gizmo; RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_MOVE_STYLE_CROSS_2D); @@ -465,9 +454,9 @@ static void WIDGETGROUP_node_sbeam_setup(const bContext *UNUSED(C), wmGizmoGroup static void WIDGETGROUP_node_sbeam_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup) { - struct NodeSunBeamsWidgetGroup *sbeam_group = gzgroup->customdata; + NodeSunBeamsWidgetGroup *sbeam_group = (NodeSunBeamsWidgetGroup *)gzgroup->customdata; ARegion *region = CTX_wm_region(C); - wmGizmo *gz = gzgroup->gizmos.first; + wmGizmo *gz = (wmGizmo *)gzgroup->gizmos.first; SpaceNode *snode = CTX_wm_space_node(C); @@ -478,12 +467,12 @@ static void WIDGETGROUP_node_sbeam_draw_prepare(const bContext *C, wmGizmoGroup static void WIDGETGROUP_node_sbeam_refresh(const bContext *C, wmGizmoGroup *gzgroup) { Main *bmain = CTX_data_main(C); - struct NodeSunBeamsWidgetGroup *sbeam_group = gzgroup->customdata; + NodeSunBeamsWidgetGroup *sbeam_group = (NodeSunBeamsWidgetGroup *)gzgroup->customdata; wmGizmo *gz = sbeam_group->gizmo; void *lock; Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock); if (ibuf) { sbeam_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f; @@ -555,12 +544,12 @@ static bool WIDGETGROUP_node_corner_pin_poll(const bContext *C, wmGizmoGroupType static void WIDGETGROUP_node_corner_pin_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) { - struct NodeCornerPinWidgetGroup *cpin_group = MEM_mallocN( - sizeof(struct NodeCornerPinWidgetGroup), __func__); + NodeCornerPinWidgetGroup *cpin_group = (NodeCornerPinWidgetGroup *)MEM_mallocN( + sizeof(NodeCornerPinWidgetGroup), __func__); const wmGizmoType *gzt_move_3d = WM_gizmotype_find("GIZMO_GT_move_3d", false); for (int i = 0; i < 4; i++) { - cpin_group->gizmos[i] = WM_gizmo_new_ptr(gzt_move_3d, gzgroup, NULL); + cpin_group->gizmos[i] = WM_gizmo_new_ptr(gzt_move_3d, gzgroup, nullptr); wmGizmo *gz = cpin_group->gizmos[i]; RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_MOVE_STYLE_CROSS_2D); @@ -573,7 +562,7 @@ static void WIDGETGROUP_node_corner_pin_setup(const bContext *UNUSED(C), wmGizmo static void WIDGETGROUP_node_corner_pin_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup) { - struct NodeCornerPinWidgetGroup *cpin_group = gzgroup->customdata; + NodeCornerPinWidgetGroup *cpin_group = (NodeCornerPinWidgetGroup *)gzgroup->customdata; ARegion *region = CTX_wm_region(C); SpaceNode *snode = CTX_wm_space_node(C); @@ -591,11 +580,11 @@ static void WIDGETGROUP_node_corner_pin_draw_prepare(const bContext *C, wmGizmoG static void WIDGETGROUP_node_corner_pin_refresh(const bContext *C, wmGizmoGroup *gzgroup) { Main *bmain = CTX_data_main(C); - struct NodeCornerPinWidgetGroup *cpin_group = gzgroup->customdata; + NodeCornerPinWidgetGroup *cpin_group = (NodeCornerPinWidgetGroup *)gzgroup->customdata; void *lock; Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock); if (ibuf) { cpin_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f; @@ -606,7 +595,7 @@ static void WIDGETGROUP_node_corner_pin_refresh(const bContext *C, wmGizmoGroup /* need to set property here for undo. TODO: would prefer to do this in _init. */ int i = 0; - for (bNodeSocket *sock = node->inputs.first; sock && i < 4; sock = sock->next) { + for (bNodeSocket *sock = (bNodeSocket *)node->inputs.first; sock && i < 4; sock = sock->next) { if (sock->type == SOCK_VECTOR) { wmGizmo *gz = cpin_group->gizmos[i++]; diff --git a/source/blender/editors/space_node/node_group.cc b/source/blender/editors/space_node/node_group.cc index d7541d8f512..d9fbbc81a8f 100644 --- a/source/blender/editors/space_node/node_group.cc +++ b/source/blender/editors/space_node/node_group.cc @@ -58,7 +58,7 @@ #include "NOD_common.h" #include "NOD_socket.h" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ /* -------------------------------------------------------------------- */ /** \name Local Utilities diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h deleted file mode 100644 index 383fe5afdf9..00000000000 --- a/source/blender/editors/space_node/node_intern.h +++ /dev/null @@ -1,355 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2008 Blender Foundation. - * All rights reserved. - */ - -/** \file - * \ingroup spnode - */ - -#pragma once - -#include "BKE_node.h" -#include "UI_interface.h" -#include "UI_view2d.h" -#include <stddef.h> /* for size_t */ - -/* internal exports only */ - -struct ARegion; -struct ARegionType; -struct Main; -struct NodeInsertOfsData; -struct View2D; -struct bContext; -struct bNode; -struct bNodeLink; -struct bNodeSocket; -struct wmGizmoGroupType; -struct wmKeyConfig; -struct wmWindow; - -#ifdef __cplusplus -extern "C" { -#endif - -/* temp data to pass on to modal */ -typedef struct bNodeLinkDrag { - struct bNodeLinkDrag *next, *prev; - - /* List of links dragged by the operator. - * NOTE: This is a list of LinkData structs on top of the actual bNodeLinks. - * This way the links can be added to the node tree while being stored in this list. - */ - ListBase links; - bool from_multi_input_socket; - int in_out; - - /** Temporarily stores the last picked link from multi-input socket operator. */ - struct bNodeLink *last_picked_multi_input_socket_link; - - /** Temporarily stores the last hovered socket for multi-input socket operator. - * Store it to recalculate sorting after it is no longer hovered. */ - struct bNode *last_node_hovered_while_dragging_a_link; - - /* Data for edge panning */ - View2DEdgePanData pan_data; -} bNodeLinkDrag; - -typedef struct SpaceNode_Runtime { - float aspect; - - /** Mouse position for drawing socket-less links and adding nodes. */ - float cursor[2]; - - /** For auto compositing. */ - bool recalc; - - /** Temporary data for modal linking operator. */ - struct ListBase linkdrag; - - /* XXX hack for translate_attach op-macros to pass data from transform op to insert_offset op */ - /** Temporary data for node insert offset (in UI called Auto-offset). */ - struct NodeInsertOfsData *iofsd; -} SpaceNode_Runtime; - -/* space_node.c */ - -/* transform between View2Ds in the tree path */ -void space_node_group_offset(struct SpaceNode *snode, float *x, float *y); - -/* node_draw.cc */ -float node_socket_calculate_height(const bNodeSocket *socket); -void node_link_calculate_multi_input_position(const float socket_x, - const float socket_y, - const int index, - const int total_inputs, - float r[2]); - -int node_get_colorid(struct bNode *node); -int node_get_resize_cursor(int directions); -void node_draw_shadow(const struct SpaceNode *snode, - const struct bNode *node, - float radius, - float alpha); -void node_draw_default(const struct bContext *C, - struct ARegion *region, - struct SpaceNode *snode, - struct bNodeTree *ntree, - struct bNode *node, - bNodeInstanceKey key); -void node_draw_sockets(const struct View2D *v2d, - const struct bContext *C, - struct bNodeTree *ntree, - struct bNode *node, - bool draw_outputs, - bool select_all); -void node_update_default(const struct bContext *C, struct bNodeTree *ntree, struct bNode *node); -int node_select_area_default(struct bNode *node, int x, int y); -int node_tweak_area_default(struct bNode *node, int x, int y); -void node_socket_color_get(const struct bContext *C, - struct bNodeTree *ntree, - struct PointerRNA *node_ptr, - struct bNodeSocket *sock, - float r_color[4]); -void node_update_nodetree(const struct bContext *C, struct bNodeTree *ntree); -void node_draw_nodetree(const struct bContext *C, - struct ARegion *region, - struct SpaceNode *snode, - struct bNodeTree *ntree, - bNodeInstanceKey parent_key); -void node_draw_space(const bContext *C, ARegion *region); - -void node_set_cursor(struct wmWindow *win, struct SpaceNode *snode, float cursor[2]); -/* DPI scaled coords */ -void node_to_view(const struct bNode *node, float x, float y, float *rx, float *ry); -void node_to_updated_rect(const struct bNode *node, rctf *r_rect); -void node_from_view(const struct bNode *node, float x, float y, float *rx, float *ry); - -/* node_toolbar.c */ -void node_toolbar_register(struct ARegionType *art); - -/* node_ops.c */ -void node_operatortypes(void); -void node_keymap(struct wmKeyConfig *keyconf); - -/* node_select.c */ -void node_deselect_all(struct SpaceNode *snode); -void node_socket_select(struct bNode *node, struct bNodeSocket *sock); -void node_socket_deselect(struct bNode *node, struct bNodeSocket *sock, const bool deselect_node); -void node_deselect_all_input_sockets(struct SpaceNode *snode, const bool deselect_nodes); -void node_deselect_all_output_sockets(struct SpaceNode *snode, const bool deselect_nodes); -void node_select_single(struct bContext *C, struct bNode *node); - -void NODE_OT_select(struct wmOperatorType *ot); -void NODE_OT_select_all(struct wmOperatorType *ot); -void NODE_OT_select_linked_to(struct wmOperatorType *ot); -void NODE_OT_select_linked_from(struct wmOperatorType *ot); -void NODE_OT_select_box(struct wmOperatorType *ot); -void NODE_OT_select_circle(struct wmOperatorType *ot); -void NODE_OT_select_lasso(struct wmOperatorType *ot); -void NODE_OT_select_grouped(struct wmOperatorType *ot); -void NODE_OT_select_same_type_step(struct wmOperatorType *ot); -void NODE_OT_find_node(struct wmOperatorType *ot); - -/* node_view.c */ -int space_node_view_flag(struct bContext *C, - struct SpaceNode *snode, - ARegion *region, - const int node_flag, - const int smooth_viewtx); - -void NODE_OT_view_all(struct wmOperatorType *ot); -void NODE_OT_view_selected(struct wmOperatorType *ot); -void NODE_OT_geometry_node_view_legacy(struct wmOperatorType *ot); - -void NODE_OT_backimage_move(struct wmOperatorType *ot); -void NODE_OT_backimage_zoom(struct wmOperatorType *ot); -void NODE_OT_backimage_fit(struct wmOperatorType *ot); -void NODE_OT_backimage_sample(struct wmOperatorType *ot); - -/* drawnode.c */ -void nodelink_batch_start(struct SpaceNode *snode); -void nodelink_batch_end(struct SpaceNode *snode); - -void node_draw_link(const struct bContext *C, - struct View2D *v2d, - struct SpaceNode *snode, - struct bNodeLink *link); -void node_draw_link_bezier(const struct bContext *C, - const struct View2D *v2d, - const struct SpaceNode *snode, - const struct bNodeLink *link, - int th_col1, - int th_col2, - int th_col3); -bool node_link_bezier_points(const struct View2D *v2d, - const struct SpaceNode *snode, - const struct bNodeLink *link, - float coord_array[][2], - const int resol); -bool node_link_bezier_handles(const struct View2D *v2d, - const struct SpaceNode *snode, - const struct bNodeLink *link, - float vec[4][2]); -void draw_nodespace_back_pix(const struct bContext *C, - struct ARegion *region, - struct SpaceNode *snode, - bNodeInstanceKey parent_key); - -/* node_add.c */ -bNode *node_add_node( - const struct bContext *C, const char *idname, int type, float locx, float locy); -void NODE_OT_add_reroute(struct wmOperatorType *ot); -void NODE_OT_add_group(struct wmOperatorType *ot); -void NODE_OT_add_object(struct wmOperatorType *ot); -void NODE_OT_add_collection(struct wmOperatorType *ot); -void NODE_OT_add_texture(struct wmOperatorType *ot); -void NODE_OT_add_file(struct wmOperatorType *ot); -void NODE_OT_add_mask(struct wmOperatorType *ot); -void NODE_OT_new_node_tree(struct wmOperatorType *ot); - -/* node_group.c */ -const char *node_group_idname(struct bContext *C); -void NODE_OT_group_make(struct wmOperatorType *ot); -void NODE_OT_group_insert(struct wmOperatorType *ot); -void NODE_OT_group_ungroup(struct wmOperatorType *ot); -void NODE_OT_group_separate(struct wmOperatorType *ot); -void NODE_OT_group_edit(struct wmOperatorType *ot); - -/* node_relationships.c */ -void sort_multi_input_socket_links(struct SpaceNode *snode, - struct bNode *node, - struct bNodeLink *drag_link, - float cursor[2]); -bool node_connected_to_output(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node); - -void NODE_OT_link(struct wmOperatorType *ot); -void NODE_OT_link_make(struct wmOperatorType *ot); -void NODE_OT_links_cut(struct wmOperatorType *ot); -void NODE_OT_links_detach(struct wmOperatorType *ot); -void NODE_OT_links_mute(struct wmOperatorType *ot); - -void NODE_OT_parent_set(struct wmOperatorType *ot); -void NODE_OT_join(struct wmOperatorType *ot); -void NODE_OT_attach(struct wmOperatorType *ot); -void NODE_OT_detach(struct wmOperatorType *ot); - -void NODE_OT_link_viewer(struct wmOperatorType *ot); - -void NODE_OT_insert_offset(struct wmOperatorType *ot); - -/* node_edit.c */ -void snode_notify(struct bContext *C, struct SpaceNode *snode); -void snode_dag_update(struct bContext *C, struct SpaceNode *snode); -void snode_set_context(const struct bContext *C); - -void snode_update(struct SpaceNode *snode, struct bNode *node); -bool composite_node_active(struct bContext *C); -bool composite_node_editable(struct bContext *C); - -bool node_has_hidden_sockets(struct bNode *node); -void node_set_hidden_sockets(struct SpaceNode *snode, bNode *node, int set); -int node_render_changed_exec(bContext *, struct wmOperator *); -int node_find_indicated_socket(struct SpaceNode *snode, - struct bNode **nodep, - struct bNodeSocket **sockp, - const float cursor[2], - int in_out); -float node_link_dim_factor(const struct View2D *v2d, const struct bNodeLink *link); -bool node_link_is_hidden_or_dimmed(const struct View2D *v2d, const struct bNodeLink *link); - -void NODE_OT_duplicate(struct wmOperatorType *ot); -void NODE_OT_delete(struct wmOperatorType *ot); -void NODE_OT_delete_reconnect(struct wmOperatorType *ot); -void NODE_OT_resize(struct wmOperatorType *ot); - -void NODE_OT_mute_toggle(struct wmOperatorType *ot); -void NODE_OT_hide_toggle(struct wmOperatorType *ot); -void NODE_OT_hide_socket_toggle(struct wmOperatorType *ot); -void NODE_OT_preview_toggle(struct wmOperatorType *ot); -void NODE_OT_options_toggle(struct wmOperatorType *ot); -void NODE_OT_node_copy_color(struct wmOperatorType *ot); - -void NODE_OT_read_viewlayers(struct wmOperatorType *ot); -void NODE_OT_render_changed(struct wmOperatorType *ot); - -void NODE_OT_output_file_add_socket(struct wmOperatorType *ot); -void NODE_OT_output_file_remove_active_socket(struct wmOperatorType *ot); -void NODE_OT_output_file_move_active_socket(struct wmOperatorType *ot); - -void NODE_OT_switch_view_update(struct wmOperatorType *ot); - -/* NOTE: clipboard_cut is a simple macro of copy + delete. */ -void NODE_OT_clipboard_copy(struct wmOperatorType *ot); -void NODE_OT_clipboard_paste(struct wmOperatorType *ot); - -void NODE_OT_tree_socket_add(struct wmOperatorType *ot); -void NODE_OT_tree_socket_remove(struct wmOperatorType *ot); -void NODE_OT_tree_socket_change_type(struct wmOperatorType *ot); -void NODE_OT_tree_socket_move(struct wmOperatorType *ot); - -void NODE_OT_shader_script_update(struct wmOperatorType *ot); - -void NODE_OT_viewer_border(struct wmOperatorType *ot); -void NODE_OT_clear_viewer_border(struct wmOperatorType *ot); - -/* node_widgets.c */ -void NODE_GGT_backdrop_transform(struct wmGizmoGroupType *gzgt); -void NODE_GGT_backdrop_crop(struct wmGizmoGroupType *gzgt); -void NODE_GGT_backdrop_sun_beams(struct wmGizmoGroupType *gzgt); -void NODE_GGT_backdrop_corner_pin(struct wmGizmoGroupType *gzgt); - -void NODE_OT_cryptomatte_layer_add(struct wmOperatorType *ot); -void NODE_OT_cryptomatte_layer_remove(struct wmOperatorType *ot); - -/* node_geometry_attribute_search.cc */ -void node_geometry_add_attribute_search_button(const struct bContext *C, - const struct bNodeTree *node_tree, - const struct bNode *node, - struct PointerRNA *socket_ptr, - struct uiLayout *layout); - -extern const char *node_context_dir[]; - -/* XXXXXX */ - -/* Nodes draw without dpi - the view zoom is flexible. */ -#define HIDDEN_RAD (0.75f * U.widget_unit) -#define BASIS_RAD (0.2f * U.widget_unit) -#define NODE_DYS (U.widget_unit / 2) -#define NODE_DY U.widget_unit -#define NODE_SOCKDY (0.1f * U.widget_unit) -#define NODE_WIDTH(node) (node->width * UI_DPI_FAC) -#define NODE_HEIGHT(node) (node->height * UI_DPI_FAC) -#define NODE_MARGIN_X (1.2f * U.widget_unit) -#define NODE_SOCKSIZE (0.25f * U.widget_unit) -#define NODE_MULTI_INPUT_LINK_GAP (0.25f * U.widget_unit) -#define NODE_RESIZE_MARGIN (0.20f * U.widget_unit) -#define NODE_LINK_RESOL 12 - -#ifdef __cplusplus -} -#endif - -#ifdef __cplusplus -# include "BLI_vector.hh" -# include "UI_interface.hh" -namespace blender::ed::space_node { -Vector<ui::ContextPathItem> context_path_for_space_node(const bContext &C); -} -#endif diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh new file mode 100644 index 00000000000..2e973def867 --- /dev/null +++ b/source/blender/editors/space_node/node_intern.hh @@ -0,0 +1,332 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2008 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup spnode + */ + +#pragma once + +#include "BKE_node.h" +#include "UI_interface.h" +#include "UI_view2d.h" + +#include "BLI_vector.hh" +#include "UI_interface.hh" + +#include <stddef.h> /* for size_t */ + +/* internal exports only */ + +struct ARegion; +struct ARegionType; +struct Main; +struct NodeInsertOfsData; +struct View2D; +struct bContext; +struct bNode; +struct bNodeLink; +struct bNodeSocket; +struct wmGizmoGroupType; +struct wmKeyConfig; +struct wmWindow; + +/* temp data to pass on to modal */ +struct bNodeLinkDrag { + /** Links dragged by the operator. */ + blender::Vector<bNodeLink *> links; + bool from_multi_input_socket; + int in_out; + + /** Temporarily stores the last picked link from multi-input socket operator. */ + struct bNodeLink *last_picked_multi_input_socket_link; + + /** Temporarily stores the last hovered socket for multi-input socket operator. + * Store it to recalculate sorting after it is no longer hovered. */ + struct bNode *last_node_hovered_while_dragging_a_link; + + /* Data for edge panning */ + View2DEdgePanData pan_data; +}; + +struct SpaceNode_Runtime { + float aspect; + + /** Mouse position for drawing socket-less links and adding nodes. */ + float cursor[2]; + + /** For auto compositing. */ + bool recalc; + + /** Temporary data for modal linking operator. */ + std::unique_ptr<bNodeLinkDrag> linkdrag; + + /* XXX hack for translate_attach op-macros to pass data from transform op to insert_offset op */ + /** Temporary data for node insert offset (in UI called Auto-offset). */ + struct NodeInsertOfsData *iofsd; +}; + +/* space_node.c */ + +/* transform between View2Ds in the tree path */ +void space_node_group_offset(SpaceNode *snode, float *x, float *y); + +/* node_draw.cc */ +float node_socket_calculate_height(const bNodeSocket *socket); +void node_link_calculate_multi_input_position(const float socket_x, + const float socket_y, + const int index, + const int total_inputs, + float r[2]); + +int node_get_colorid(bNode *node); +int node_get_resize_cursor(int directions); +void node_draw_shadow(const SpaceNode *snode, const bNode *node, float radius, float alpha); +void node_draw_default(const bContext *C, + ARegion *region, + SpaceNode *snode, + bNodeTree *ntree, + bNode *node, + bNodeInstanceKey key); +void node_draw_sockets(const View2D *v2d, + const bContext *C, + bNodeTree *ntree, + bNode *node, + bool draw_outputs, + bool select_all); +void node_update_default(const bContext *C, bNodeTree *ntree, bNode *node); +int node_select_area_default(bNode *node, int x, int y); +int node_tweak_area_default(bNode *node, int x, int y); +void node_socket_color_get(const bContext *C, + bNodeTree *ntree, + PointerRNA *node_ptr, + bNodeSocket *sock, + float r_color[4]); +void node_update_nodetree(const bContext *C, bNodeTree *ntree); +void node_draw_nodetree(const bContext *C, + ARegion *region, + SpaceNode *snode, + bNodeTree *ntree, + bNodeInstanceKey parent_key); +void node_draw_space(const bContext *C, ARegion *region); + +void node_set_cursor(wmWindow *win, SpaceNode *snode, float cursor[2]); +/* DPI scaled coords */ +void node_to_view(const bNode *node, float x, float y, float *rx, float *ry); +void node_to_updated_rect(const bNode *node, rctf *r_rect); +void node_from_view(const bNode *node, float x, float y, float *rx, float *ry); + +/* node_toolbar.c */ +void node_toolbar_register(ARegionType *art); + +/* node_ops.c */ +void node_operatortypes(void); +void node_keymap(wmKeyConfig *keyconf); + +/* node_select.c */ +void node_deselect_all(SpaceNode *snode); +void node_socket_select(bNode *node, bNodeSocket *sock); +void node_socket_deselect(bNode *node, bNodeSocket *sock, const bool deselect_node); +void node_deselect_all_input_sockets(SpaceNode *snode, const bool deselect_nodes); +void node_deselect_all_output_sockets(SpaceNode *snode, const bool deselect_nodes); +void node_select_single(bContext *C, bNode *node); + +void NODE_OT_select(wmOperatorType *ot); +void NODE_OT_select_all(wmOperatorType *ot); +void NODE_OT_select_linked_to(wmOperatorType *ot); +void NODE_OT_select_linked_from(wmOperatorType *ot); +void NODE_OT_select_box(wmOperatorType *ot); +void NODE_OT_select_circle(wmOperatorType *ot); +void NODE_OT_select_lasso(wmOperatorType *ot); +void NODE_OT_select_grouped(wmOperatorType *ot); +void NODE_OT_select_same_type_step(wmOperatorType *ot); +void NODE_OT_find_node(wmOperatorType *ot); + +/* node_view.c */ +int space_node_view_flag( + bContext *C, SpaceNode *snode, ARegion *region, const int node_flag, const int smooth_viewtx); + +void NODE_OT_view_all(wmOperatorType *ot); +void NODE_OT_view_selected(wmOperatorType *ot); +void NODE_OT_geometry_node_view_legacy(wmOperatorType *ot); + +void NODE_OT_backimage_move(wmOperatorType *ot); +void NODE_OT_backimage_zoom(wmOperatorType *ot); +void NODE_OT_backimage_fit(wmOperatorType *ot); +void NODE_OT_backimage_sample(wmOperatorType *ot); + +/* drawnode.c */ +void nodelink_batch_start(SpaceNode *snode); +void nodelink_batch_end(SpaceNode *snode); + +void node_draw_link(const bContext *C, + const View2D *v2d, + const SpaceNode *snode, + const bNodeLink *link); +void node_draw_link_bezier(const bContext *C, + const View2D *v2d, + const SpaceNode *snode, + const bNodeLink *link, + int th_col1, + int th_col2, + int th_col3); +bool node_link_bezier_points(const View2D *v2d, + const SpaceNode *snode, + const bNodeLink *link, + float coord_array[][2], + const int resol); +bool node_link_bezier_handles(const View2D *v2d, + const SpaceNode *snode, + const bNodeLink *link, + float vec[4][2]); +void draw_nodespace_back_pix(const bContext *C, + ARegion *region, + SpaceNode *snode, + bNodeInstanceKey parent_key); + +/* node_add.c */ +bNode *node_add_node(const bContext *C, const char *idname, int type, float locx, float locy); +void NODE_OT_add_reroute(wmOperatorType *ot); +void NODE_OT_add_group(wmOperatorType *ot); +void NODE_OT_add_object(wmOperatorType *ot); +void NODE_OT_add_collection(wmOperatorType *ot); +void NODE_OT_add_texture(wmOperatorType *ot); +void NODE_OT_add_file(wmOperatorType *ot); +void NODE_OT_add_mask(wmOperatorType *ot); +void NODE_OT_new_node_tree(wmOperatorType *ot); + +/* node_group.c */ +const char *node_group_idname(bContext *C); +void NODE_OT_group_make(wmOperatorType *ot); +void NODE_OT_group_insert(wmOperatorType *ot); +void NODE_OT_group_ungroup(wmOperatorType *ot); +void NODE_OT_group_separate(wmOperatorType *ot); +void NODE_OT_group_edit(wmOperatorType *ot); + +/* node_relationships.c */ +void sort_multi_input_socket_links(SpaceNode *snode, + bNode *node, + bNodeLink *drag_link, + float cursor[2]); +bool node_connected_to_output(Main *bmain, bNodeTree *ntree, bNode *node); + +void NODE_OT_link(wmOperatorType *ot); +void NODE_OT_link_make(wmOperatorType *ot); +void NODE_OT_links_cut(wmOperatorType *ot); +void NODE_OT_links_detach(wmOperatorType *ot); +void NODE_OT_links_mute(wmOperatorType *ot); + +void NODE_OT_parent_set(wmOperatorType *ot); +void NODE_OT_join(wmOperatorType *ot); +void NODE_OT_attach(wmOperatorType *ot); +void NODE_OT_detach(wmOperatorType *ot); + +void NODE_OT_link_viewer(wmOperatorType *ot); + +void NODE_OT_insert_offset(wmOperatorType *ot); + +/* node_edit.c */ +void snode_notify(bContext *C, SpaceNode *snode); +void snode_dag_update(bContext *C, SpaceNode *snode); +void snode_set_context(const bContext *C); + +void snode_update(SpaceNode *snode, bNode *node); +bool composite_node_active(bContext *C); +bool composite_node_editable(bContext *C); + +bool node_has_hidden_sockets(bNode *node); +void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set); +int node_render_changed_exec(bContext *, wmOperator *); +bool node_find_indicated_socket( + SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, const float cursor[2], int in_out); +float node_link_dim_factor(const View2D *v2d, const bNodeLink *link); +bool node_link_is_hidden_or_dimmed(const View2D *v2d, const bNodeLink *link); + +void NODE_OT_duplicate(wmOperatorType *ot); +void NODE_OT_delete(wmOperatorType *ot); +void NODE_OT_delete_reconnect(wmOperatorType *ot); +void NODE_OT_resize(wmOperatorType *ot); + +void NODE_OT_mute_toggle(wmOperatorType *ot); +void NODE_OT_hide_toggle(wmOperatorType *ot); +void NODE_OT_hide_socket_toggle(wmOperatorType *ot); +void NODE_OT_preview_toggle(wmOperatorType *ot); +void NODE_OT_options_toggle(wmOperatorType *ot); +void NODE_OT_node_copy_color(wmOperatorType *ot); + +void NODE_OT_read_viewlayers(wmOperatorType *ot); +void NODE_OT_render_changed(wmOperatorType *ot); + +void NODE_OT_output_file_add_socket(wmOperatorType *ot); +void NODE_OT_output_file_remove_active_socket(wmOperatorType *ot); +void NODE_OT_output_file_move_active_socket(wmOperatorType *ot); + +void NODE_OT_switch_view_update(wmOperatorType *ot); + +/* NOTE: clipboard_cut is a simple macro of copy + delete. */ +void NODE_OT_clipboard_copy(wmOperatorType *ot); +void NODE_OT_clipboard_paste(wmOperatorType *ot); + +void NODE_OT_tree_socket_add(wmOperatorType *ot); +void NODE_OT_tree_socket_remove(wmOperatorType *ot); +void NODE_OT_tree_socket_change_type(wmOperatorType *ot); +void NODE_OT_tree_socket_move(wmOperatorType *ot); + +void NODE_OT_shader_script_update(wmOperatorType *ot); + +void NODE_OT_viewer_border(wmOperatorType *ot); +void NODE_OT_clear_viewer_border(wmOperatorType *ot); + +/* node_widgets.c */ +void NODE_GGT_backdrop_transform(wmGizmoGroupType *gzgt); +void NODE_GGT_backdrop_crop(wmGizmoGroupType *gzgt); +void NODE_GGT_backdrop_sun_beams(wmGizmoGroupType *gzgt); +void NODE_GGT_backdrop_corner_pin(wmGizmoGroupType *gzgt); + +void NODE_OT_cryptomatte_layer_add(wmOperatorType *ot); +void NODE_OT_cryptomatte_layer_remove(wmOperatorType *ot); + +/* node_geometry_attribute_search.cc */ +void node_geometry_add_attribute_search_button(const bContext *C, + const bNodeTree *node_tree, + const bNode *node, + PointerRNA *socket_ptr, + uiLayout *layout); + +extern const char *node_context_dir[]; + +/* XXXXXX */ + +/* Nodes draw without dpi - the view zoom is flexible. */ +#define HIDDEN_RAD (0.75f * U.widget_unit) +#define BASIS_RAD (0.2f * U.widget_unit) +#define NODE_DYS (U.widget_unit / 2) +#define NODE_DY U.widget_unit +#define NODE_SOCKDY (0.1f * U.widget_unit) +#define NODE_WIDTH(node) (node->width * UI_DPI_FAC) +#define NODE_HEIGHT(node) (node->height * UI_DPI_FAC) +#define NODE_MARGIN_X (1.2f * U.widget_unit) +#define NODE_SOCKSIZE (0.25f * U.widget_unit) +#define NODE_MULTI_INPUT_LINK_GAP (0.25f * U.widget_unit) +#define NODE_RESIZE_MARGIN (0.20f * U.widget_unit) +#define NODE_LINK_RESOL 12 + +namespace blender::ed::space_node { +Vector<ui::ContextPathItem> context_path_for_space_node(const bContext &C); +} diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.cc index 0c54da65e9c..4c08f4d7b47 100644 --- a/source/blender/editors/space_node/node_ops.c +++ b/source/blender/editors/space_node/node_ops.cc @@ -33,9 +33,9 @@ #include "WM_api.h" #include "WM_types.h" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ -void node_operatortypes(void) +void node_operatortypes() { WM_operatortype_append(NODE_OT_select); WM_operatortype_append(NODE_OT_select_all); diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index 55b547d3195..aee749edbc4 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -60,9 +60,10 @@ #include "NOD_node_declaration.hh" #include "NOD_node_tree_ref.hh" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ using namespace blender::nodes::node_tree_ref_types; +using blender::Vector; /* -------------------------------------------------------------------- */ /** \name Relations Helpers @@ -207,11 +208,9 @@ static void clear_picking_highlight(ListBase *links) } } -static LinkData *create_drag_link(Main *bmain, SpaceNode *snode, bNode *node, bNodeSocket *sock) +static bNodeLink *create_drag_link(Main *bmain, SpaceNode *snode, bNode *node, bNodeSocket *sock) { - LinkData *linkdata = (LinkData *)MEM_callocN(sizeof(LinkData), "drag link op link data"); bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link"); - linkdata->data = oplink; if (sock->in_out == SOCK_OUT) { oplink->fromnode = node; oplink->fromsock = sock; @@ -226,7 +225,7 @@ static LinkData *create_drag_link(Main *bmain, SpaceNode *snode, bNode *node, bN oplink->flag |= NODE_LINK_TEST; } oplink->flag |= NODE_LINK_DRAGGED; - return linkdata; + return oplink; } static void pick_link(const bContext *C, @@ -240,10 +239,9 @@ static void pick_link(const bContext *C, RNA_boolean_set(op->ptr, "has_link_picked", true); Main *bmain = CTX_data_main(C); - LinkData *linkdata = create_drag_link( - bmain, snode, link_to_pick->fromnode, link_to_pick->fromsock); + bNodeLink *link = create_drag_link(bmain, snode, link_to_pick->fromnode, link_to_pick->fromsock); - BLI_addtail(&nldrag->links, linkdata); + nldrag->links.append(link); nodeRemLink(snode->edittree, link_to_pick); BLI_assert(nldrag->last_node_hovered_while_dragging_a_link != nullptr); @@ -324,19 +322,6 @@ static void pick_input_link_by_link_intersect(const bContext *C, } } -static int sort_nodes_locx(const void *a, const void *b) -{ - const bNodeListItem *nli1 = (const bNodeListItem *)a; - const bNodeListItem *nli2 = (const bNodeListItem *)b; - const bNode *node1 = nli1->node; - const bNode *node2 = nli2->node; - - if (node1->locx > node2->locx) { - return 1; - } - return 0; -} - static bool socket_is_available(bNodeTree *UNUSED(ntree), bNodeSocket *sock, const bool allow_used) { if (nodeSocketIsHidden(sock)) { @@ -527,30 +512,25 @@ static void snode_autoconnect(Main *bmain, const bool replace) { bNodeTree *ntree = snode->edittree; - ListBase *nodelist = (ListBase *)MEM_callocN(sizeof(ListBase), "items_list"); + Vector<bNode *> sorted_nodes; LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->flag & NODE_SELECT) { - bNodeListItem *nli = (bNodeListItem *)MEM_mallocN(sizeof(bNodeListItem), - "temporary node list item"); - nli->node = node; - BLI_addtail(nodelist, nli); + sorted_nodes.append(node); } } - /* sort nodes left to right */ - BLI_listbase_sort(nodelist, sort_nodes_locx); + /* Sort nodes left to right. */ + std::sort(sorted_nodes.begin(), sorted_nodes.end(), [](const bNode *a, const bNode *b) { + return a->locx < b->locx; + }); int numlinks = 0; - LISTBASE_FOREACH (bNodeListItem *, nli, nodelist) { + for (const int i : sorted_nodes.as_mutable_span().drop_back(1).index_range()) { bool has_selected_inputs = false; - if (nli->next == nullptr) { - break; - } - - bNode *node_fr = nli->node; - bNode *node_to = nli->next->node; + bNode *node_fr = sorted_nodes[i]; + bNode *node_to = sorted_nodes[i + 1]; /* corner case: input/output node aligned the wrong way around (T47729) */ if (BLI_listbase_is_empty(&node_to->inputs) || BLI_listbase_is_empty(&node_fr->outputs)) { SWAP(bNode *, node_fr, node_to); @@ -606,9 +586,6 @@ static void snode_autoconnect(Main *bmain, if (numlinks > 0) { ntreeUpdateTree(bmain, ntree); } - - BLI_freelistN(nodelist); - MEM_freeN(nodelist); } /** \} */ @@ -1013,9 +990,7 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links) /* avoid updates while applying links */ ntree->is_updating = true; - LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { - bNodeLink *link = (bNodeLink *)linkdata->data; - + for (bNodeLink *link : nldrag->links) { /* See note below, but basically TEST flag means that the link * was connected to output (or to a node which affects the * output). @@ -1068,10 +1043,7 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links) UI_view2d_edge_pan_cancel(C, &nldrag->pan_data); } - BLI_remlink(&snode->runtime->linkdrag, nldrag); - /* links->data pointers are either held by the tree or freed already */ - BLI_freelistN(&nldrag->links); - MEM_freeN(nldrag); + snode->runtime->linkdrag.reset(); } static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2]) @@ -1083,9 +1055,7 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2]) bNode *tnode; bNodeSocket *tsock = nullptr; if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_IN)) { - LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { - bNodeLink *link = (bNodeLink *)linkdata->data; - + for (bNodeLink *link : nldrag->links) { /* skip if socket is on the same node as the fromsock */ if (tnode && link->fromnode == tnode) { continue; @@ -1115,8 +1085,7 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2]) } } else { - LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { - bNodeLink *link = (bNodeLink *)linkdata->data; + for (bNodeLink *link : nldrag->links) { if (nldrag->last_node_hovered_while_dragging_a_link) { sort_multi_input_socket_links( snode, nldrag->last_node_hovered_while_dragging_a_link, nullptr, cursor); @@ -1130,9 +1099,7 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2]) bNode *tnode; bNodeSocket *tsock = nullptr; if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_OUT)) { - LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { - bNodeLink *link = (bNodeLink *)linkdata->data; - + for (bNodeLink *link : nldrag->links) { /* skip if this is already the target socket */ if (link->fromsock == tsock) { continue; @@ -1148,9 +1115,7 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2]) } } else { - LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { - bNodeLink *link = (bNodeLink *)linkdata->data; - + for (bNodeLink *link : nldrag->links) { link->fromnode = nullptr; link->fromsock = nullptr; } @@ -1202,16 +1167,16 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_RUNNING_MODAL; } -/* return 1 when socket clicked */ -static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor[2], bool detach) +static std::unique_ptr<bNodeLinkDrag> node_link_init(Main *bmain, + SpaceNode *snode, + float cursor[2], + bool detach) { - bNodeLinkDrag *nldrag = nullptr; - /* output indicated? */ bNode *node; bNodeSocket *sock; if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) { - nldrag = (bNodeLinkDrag *)MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata"); + std::unique_ptr<bNodeLinkDrag> nldrag = std::make_unique<bNodeLinkDrag>(); const int num_links = nodeCountSocketLinks(snode->edittree, sock); int link_limit = nodeSocketLinkLimit(sock); @@ -1221,9 +1186,7 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor /* detach current links and store them in the operator data */ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode->edittree->links) { if (link->fromsock == sock) { - LinkData *linkdata = (LinkData *)MEM_callocN(sizeof(LinkData), "drag link op link data"); bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link"); - linkdata->data = oplink; *oplink = *link; oplink->next = oplink->prev = nullptr; oplink->flag |= NODE_LINK_VALID; @@ -1240,7 +1203,7 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor oplink->flag |= NODE_LINK_TEST; } - BLI_addtail(&nldrag->links, linkdata); + nldrag->links.append(oplink); nodeRemLink(snode->edittree, link); } } @@ -1249,14 +1212,14 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor /* dragged links are fixed on output side */ nldrag->in_out = SOCK_OUT; /* create a new link */ - LinkData *linkdata = create_drag_link(bmain, snode, node, sock); - - BLI_addtail(&nldrag->links, linkdata); + nldrag->links.append(create_drag_link(bmain, snode, node, sock)); } + return nldrag; } + /* or an input? */ - else if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) { - nldrag = (bNodeLinkDrag *)MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata"); + if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) { + std::unique_ptr<bNodeLinkDrag> nldrag = std::make_unique<bNodeLinkDrag>(); nldrag->last_node_hovered_while_dragging_a_link = node; const int num_links = nodeCountSocketLinks(snode->edittree, sock); @@ -1275,9 +1238,7 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor } if (link_to_pick != nullptr && !nldrag->from_multi_input_socket) { - LinkData *linkdata = (LinkData *)MEM_callocN(sizeof(LinkData), "drag link op link data"); bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link"); - linkdata->data = oplink; *oplink = *link_to_pick; oplink->next = oplink->prev = nullptr; oplink->flag |= NODE_LINK_VALID; @@ -1287,7 +1248,7 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor oplink->flag |= NODE_LINK_TEST; } - BLI_addtail(&nldrag->links, linkdata); + nldrag->links.append(oplink); nodeRemLink(snode->edittree, link_to_pick); /* send changed event to original link->tonode */ @@ -1300,13 +1261,12 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor /* dragged links are fixed on input side */ nldrag->in_out = SOCK_IN; /* create a new link */ - LinkData *linkdata = create_drag_link(bmain, snode, node, sock); - - BLI_addtail(&nldrag->links, linkdata); + nldrag->links.append(create_drag_link(bmain, snode, node, sock)); } + return nldrag; } - return nldrag; + return {}; } static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event) @@ -1324,13 +1284,13 @@ static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event) ED_preview_kill_jobs(CTX_wm_manager(C), bmain); - bNodeLinkDrag *nldrag = node_link_init(bmain, snode, cursor, detach); + std::unique_ptr<bNodeLinkDrag> nldrag = node_link_init(bmain, snode, cursor, detach); if (nldrag) { UI_view2d_edge_pan_operator_init(C, &nldrag->pan_data, op); - op->customdata = nldrag; - BLI_addtail(&snode->runtime->linkdrag, nldrag); + snode->runtime->linkdrag = std::move(nldrag); + op->customdata = snode->runtime->linkdrag.get(); /* add modal handler */ WM_event_add_modal_handler(C, op); @@ -1345,12 +1305,10 @@ static void node_link_cancel(bContext *C, wmOperator *op) SpaceNode *snode = CTX_wm_space_node(C); bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op->customdata; - BLI_remlink(&snode->runtime->linkdrag, nldrag); - UI_view2d_edge_pan_cancel(C, &nldrag->pan_data); - BLI_freelistN(&nldrag->links); - MEM_freeN(nldrag); + snode->runtime->linkdrag.reset(); + clear_picking_highlight(&snode->edittree->links); } @@ -2369,8 +2327,8 @@ static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd, /* NODE_TEST will be used later, so disable for all nodes */ ntreeNodeFlagSet(ntree, NODE_TEST, false); - /* insert->totr isn't updated yet, - * so totr_insert is used to get the correct worldspace coords */ + /* `insert->totr` isn't updated yet, + * so `totr_insert` is used to get the correct world-space coords. */ rctf totr_insert; node_to_updated_rect(insert, &totr_insert); diff --git a/source/blender/editors/space_node/node_select.cc b/source/blender/editors/space_node/node_select.cc index 29b8372d043..3c7b404547b 100644 --- a/source/blender/editors/space_node/node_select.cc +++ b/source/blender/editors/space_node/node_select.cc @@ -61,7 +61,7 @@ #include "MEM_guardedalloc.h" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ /** * Function to detect if there is a visible view3d that uses workbench in texture mode. diff --git a/source/blender/editors/space_node/node_templates.cc b/source/blender/editors/space_node/node_templates.cc index f68d8589624..b2a7c1753fb 100644 --- a/source/blender/editors/space_node/node_templates.cc +++ b/source/blender/editors/space_node/node_templates.cc @@ -48,7 +48,7 @@ #include "UI_interface.h" #include "ED_node.h" /* own include */ -#include "node_intern.h" +#include "node_intern.hh" #include "ED_undo.h" diff --git a/source/blender/editors/space_node/node_toolbar.cc b/source/blender/editors/space_node/node_toolbar.cc index 2e7d6ab6cd5..c32dcbef91b 100644 --- a/source/blender/editors/space_node/node_toolbar.cc +++ b/source/blender/editors/space_node/node_toolbar.cc @@ -30,7 +30,7 @@ #include "WM_api.h" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ /* ******************* node toolbar registration ************** */ diff --git a/source/blender/editors/space_node/node_view.cc b/source/blender/editors/space_node/node_view.cc index 762b4b36a39..36b84bec7eb 100644 --- a/source/blender/editors/space_node/node_view.cc +++ b/source/blender/editors/space_node/node_view.cc @@ -54,7 +54,7 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ using blender::StringRef; diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.cc index 0b5d7cdda82..ac64503cfc9 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.cc @@ -52,21 +52,19 @@ #include "WM_api.h" #include "WM_types.h" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ /* ******************** tree path ********************* */ void ED_node_tree_start(SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from) { - bNodeTreePath *path, *path_next; - for (path = snode->treepath.first; path; path = path_next) { - path_next = path->next; + LISTBASE_FOREACH_MUTABLE (bNodeTreePath *, path, &snode->treepath) { MEM_freeN(path); } BLI_listbase_clear(&snode->treepath); if (ntree) { - path = MEM_callocN(sizeof(bNodeTreePath), "node tree path"); + bNodeTreePath *path = (bNodeTreePath *)MEM_callocN(sizeof(bNodeTreePath), "node tree path"); path->nodetree = ntree; path->parent_key = NODE_INSTANCE_KEY_BASE; @@ -94,13 +92,13 @@ void ED_node_tree_start(SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from) ED_node_set_active_viewer_key(snode); - WM_main_add_notifier(NC_SCENE | ND_NODES, NULL); + WM_main_add_notifier(NC_SCENE | ND_NODES, nullptr); } void ED_node_tree_push(SpaceNode *snode, bNodeTree *ntree, bNode *gnode) { - bNodeTreePath *path = MEM_callocN(sizeof(bNodeTreePath), "node tree path"); - bNodeTreePath *prev_path = snode->treepath.last; + bNodeTreePath *path = (bNodeTreePath *)MEM_callocN(sizeof(bNodeTreePath), "node tree path"); + bNodeTreePath *prev_path = (bNodeTreePath *)snode->treepath.last; path->nodetree = ntree; if (gnode) { if (prev_path) { @@ -129,12 +127,12 @@ void ED_node_tree_push(SpaceNode *snode, bNodeTree *ntree, bNode *gnode) ED_node_set_active_viewer_key(snode); - WM_main_add_notifier(NC_SCENE | ND_NODES, NULL); + WM_main_add_notifier(NC_SCENE | ND_NODES, nullptr); } void ED_node_tree_pop(SpaceNode *snode) { - bNodeTreePath *path = snode->treepath.last; + bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last; /* don't remove root */ if (path == snode->treepath.first) { @@ -145,13 +143,13 @@ void ED_node_tree_pop(SpaceNode *snode) MEM_freeN(path); /* update current tree */ - path = snode->treepath.last; + path = (bNodeTreePath *)snode->treepath.last; snode->edittree = path->nodetree; ED_node_set_active_viewer_key(snode); /* listener updates the View2D center from edittree */ - WM_main_add_notifier(NC_SCENE | ND_NODES, NULL); + WM_main_add_notifier(NC_SCENE | ND_NODES, nullptr); } int ED_node_tree_depth(SpaceNode *snode) @@ -163,12 +161,12 @@ bNodeTree *ED_node_tree_get(SpaceNode *snode, int level) { bNodeTreePath *path; int i; - for (path = snode->treepath.last, i = 0; path; path = path->prev, i++) { + for (path = (bNodeTreePath *)snode->treepath.last, i = 0; path; path = path->prev, i++) { if (i == level) { return path->nodetree; } } - return NULL; + return nullptr; } int ED_node_tree_path_length(SpaceNode *snode) @@ -203,7 +201,7 @@ void ED_node_tree_path_get(SpaceNode *snode, char *value) void ED_node_set_active_viewer_key(SpaceNode *snode) { - bNodeTreePath *path = snode->treepath.last; + bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last; if (snode->nodetree && path) { snode->nodetree->active_viewer_key = path->parent_key; } @@ -211,7 +209,7 @@ void ED_node_set_active_viewer_key(SpaceNode *snode) void space_node_group_offset(SpaceNode *snode, float *x, float *y) { - bNodeTreePath *path = snode->treepath.last; + bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last; if (path && path->prev) { float dcenter[2]; @@ -228,10 +226,7 @@ void space_node_group_offset(SpaceNode *snode, float *x, float *y) static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(scene)) { - ARegion *region; - SpaceNode *snode; - - snode = MEM_callocN(sizeof(SpaceNode), "initnode"); + SpaceNode *snode = (SpaceNode *)MEM_callocN(sizeof(SpaceNode), "initnode"); snode->spacetype = SPACE_NODE; snode->flag = SNODE_SHOW_GPENCIL | SNODE_USE_ALPHA; @@ -249,21 +244,21 @@ static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(s NODE_TREE_TYPES_END; /* header */ - region = MEM_callocN(sizeof(ARegion), "header for node"); + ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "header for node"); BLI_addtail(&snode->regionbase, region); region->regiontype = RGN_TYPE_HEADER; region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP; /* buttons/list view */ - region = MEM_callocN(sizeof(ARegion), "buttons for node"); + region = (ARegion *)MEM_callocN(sizeof(ARegion), "buttons for node"); BLI_addtail(&snode->regionbase, region); region->regiontype = RGN_TYPE_UI; region->alignment = RGN_ALIGN_RIGHT; /* toolbar */ - region = MEM_callocN(sizeof(ARegion), "node tools"); + region = (ARegion *)MEM_callocN(sizeof(ARegion), "node tools"); BLI_addtail(&snode->regionbase, region); region->regiontype = RGN_TYPE_TOOLS; @@ -272,7 +267,7 @@ static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(s region->flag = RGN_FLAG_HIDDEN; /* main region */ - region = MEM_callocN(sizeof(ARegion), "main region for node"); + region = (ARegion *)MEM_callocN(sizeof(ARegion), "main region for node"); BLI_addtail(&snode->regionbase, region); region->regiontype = RGN_TYPE_WINDOW; @@ -290,7 +285,7 @@ static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(s region->v2d.max[0] = 32000.0f; region->v2d.max[1] = 32000.0f; - region->v2d.minzoom = 0.09f; + region->v2d.minzoom = 0.05f; region->v2d.maxzoom = 2.31f; region->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM); @@ -308,7 +303,10 @@ static void node_free(SpaceLink *sl) MEM_freeN(path); } - MEM_SAFE_FREE(snode->runtime); + if (snode->runtime) { + snode->runtime->linkdrag.reset(); + MEM_freeN(snode->runtime); + } } /* spacetype; init callback */ @@ -316,8 +314,8 @@ static void node_init(struct wmWindowManager *UNUSED(wm), ScrArea *area) { SpaceNode *snode = (SpaceNode *)area->spacedata.first; - if (snode->runtime == NULL) { - snode->runtime = MEM_callocN(sizeof(SpaceNode_Runtime), __func__); + if (snode->runtime == nullptr) { + snode->runtime = (SpaceNode_Runtime *)MEM_callocN(sizeof(SpaceNode_Runtime), __func__); } } @@ -327,7 +325,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) wmNotifier *wmn = params->notifier; /* NOTE: #ED_area_tag_refresh will re-execute compositor. */ - SpaceNode *snode = area->spacedata.first; + SpaceNode *snode = (SpaceNode *)area->spacedata.first; /* shaderfrom is only used for new shading nodes, otherwise all shaders are from objects */ short shader_type = snode->shaderfrom; @@ -337,7 +335,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) switch (wmn->data) { case ND_NODES: { ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW); - bNodeTreePath *path = snode->treepath.last; + bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last; /* shift view to node tree center */ if (region && path) { UI_view2d_center_set(®ion->v2d, path->view_center[0], path->view_center[1]); @@ -379,7 +377,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) ED_area_tag_refresh(area); } else if (wmn->action == NA_ADDED && snode->edittree) { - nodeSetActiveID(snode->edittree, ID_MA, wmn->reference); + nodeSetActiveID(snode->edittree, ID_MA, (ID *)wmn->reference); } } break; @@ -404,7 +402,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) else if (ED_node_is_geometry(snode)) { /* Rather strict check: only redraw when the reference matches the current editor's ID. */ if (wmn->data == ND_MODIFIER) { - if (wmn->reference == snode->id || snode->id == NULL) { + if (wmn->reference == snode->id || snode->id == nullptr) { ED_area_tag_refresh(area); } } @@ -447,7 +445,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) /* note that nodeUpdateID is already called by BKE_image_signal() on all * scenes so really this is just to know if the images is used in the compo else * painting on images could become very slow when the compositor is open. */ - if (nodeUpdateID(snode->nodetree, wmn->reference)) { + if (nodeUpdateID(snode->nodetree, (ID *)wmn->reference)) { ED_area_tag_refresh(area); } } @@ -457,7 +455,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) case NC_MOVIECLIP: if (wmn->action == NA_EDITED) { if (ED_node_is_compositor(snode)) { - if (nodeUpdateID(snode->nodetree, wmn->reference)) { + if (nodeUpdateID(snode->nodetree, (ID *)wmn->reference)) { ED_area_tag_refresh(area); } } @@ -485,7 +483,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) static void node_area_refresh(const struct bContext *C, ScrArea *area) { /* default now: refresh node is starting preview */ - SpaceNode *snode = area->spacedata.first; + SpaceNode *snode = (SpaceNode *)area->spacedata.first; snode_set_context(C); @@ -494,19 +492,19 @@ static void node_area_refresh(const struct bContext *C, ScrArea *area) if (GS(snode->id->name) == ID_MA) { Material *ma = (Material *)snode->id; if (ma->use_nodes) { - ED_preview_shader_job(C, area, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER); + ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER); } } else if (GS(snode->id->name) == ID_LA) { Light *la = (Light *)snode->id; if (la->use_nodes) { - ED_preview_shader_job(C, area, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER); + ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER); } } else if (GS(snode->id->name) == ID_WO) { World *wo = (World *)snode->id; if (wo->use_nodes) { - ED_preview_shader_job(C, area, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER); + ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER); } } } @@ -516,7 +514,7 @@ static void node_area_refresh(const struct bContext *C, ScrArea *area) /* recalc is set on 3d view changes for auto compo */ if (snode->runtime->recalc) { snode->runtime->recalc = false; - node_render_changed_exec((struct bContext *)C, NULL); + node_render_changed_exec((struct bContext *)C, nullptr); } else { ED_node_composite_job(C, snode->nodetree, scene); @@ -526,7 +524,7 @@ static void node_area_refresh(const struct bContext *C, ScrArea *area) else if (snode->nodetree->type == NTREE_TEXTURE) { Tex *tex = (Tex *)snode->id; if (tex->use_nodes) { - ED_preview_shader_job(C, area, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER); + ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER); } } } @@ -535,14 +533,11 @@ static void node_area_refresh(const struct bContext *C, ScrArea *area) static SpaceLink *node_duplicate(SpaceLink *sl) { SpaceNode *snode = (SpaceNode *)sl; - SpaceNode *snoden = MEM_dupallocN(snode); + SpaceNode *snoden = (SpaceNode *)MEM_dupallocN(snode); BLI_duplicatelist(&snoden->treepath, &snode->treepath); - if (snode->runtime != NULL) { - snoden->runtime = MEM_dupallocN(snode->runtime); - BLI_listbase_clear(&snoden->runtime->linkdrag); - } + snoden->runtime = nullptr; /* NOTE: no need to set node tree user counts, * the editor only keeps at least 1 (id_us_ensure_real), @@ -596,7 +591,7 @@ void ED_node_cursor_location_set(SpaceNode *snode, const float value[2]) static void node_cursor(wmWindow *win, ScrArea *area, ARegion *region) { - SpaceNode *snode = area->spacedata.first; + SpaceNode *snode = (SpaceNode *)area->spacedata.first; /* convert mouse coordinates to v2d space */ UI_view2d_region_to_view(®ion->v2d, @@ -692,7 +687,7 @@ static void node_id_drop_copy(wmDrag *drag, wmDropBox *drop) { ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0); - RNA_string_set(drop->ptr, "name", id->name + 2); + RNA_int_set(drop->ptr, "session_uuid", (int)id->session_uuid); } static void node_id_path_drop_copy(wmDrag *drag, wmDropBox *drop) @@ -710,7 +705,7 @@ static void node_id_path_drop_copy(wmDrag *drag, wmDropBox *drop) } /* this region dropbox definition */ -static void node_dropboxes(void) +static void node_dropboxes() { ListBase *lb = WM_dropboxmap_find("Node Editor", SPACE_NODE, RGN_TYPE_WINDOW); @@ -719,37 +714,37 @@ static void node_dropboxes(void) node_object_drop_poll, node_id_drop_copy, WM_drag_free_imported_drag_ID, - NULL); + nullptr); WM_dropbox_add(lb, "NODE_OT_add_collection", node_collection_drop_poll, node_id_drop_copy, WM_drag_free_imported_drag_ID, - NULL); + nullptr); WM_dropbox_add(lb, "NODE_OT_add_texture", node_texture_drop_poll, node_id_drop_copy, WM_drag_free_imported_drag_ID, - NULL); + nullptr); WM_dropbox_add(lb, "NODE_OT_add_group", node_group_drop_poll, node_group_drop_copy, WM_drag_free_imported_drag_ID, - NULL); + nullptr); WM_dropbox_add(lb, "NODE_OT_add_file", node_ima_drop_poll, node_id_path_drop_copy, WM_drag_free_imported_drag_ID, - NULL); + nullptr); WM_dropbox_add(lb, "NODE_OT_add_mask", node_mask_drop_poll, node_id_drop_copy, WM_drag_free_imported_drag_ID, - NULL); + nullptr); } /* ************* end drop *********** */ @@ -843,7 +838,7 @@ static void node_region_listener(const wmRegionListenerParams *params) } const char *node_context_dir[] = { - "selected_nodes", "active_node", "light", "material", "world", NULL}; + "selected_nodes", "active_node", "light", "material", "world", nullptr}; static int /*eContextResult*/ node_context(const bContext *C, const char *member, bContextDataResult *result) @@ -855,10 +850,8 @@ static int /*eContextResult*/ node_context(const bContext *C, return CTX_RESULT_OK; } if (CTX_data_equals(member, "selected_nodes")) { - bNode *node; - if (snode->edittree) { - for (node = snode->edittree->nodes.last; node; node = node->prev) { + LISTBASE_FOREACH_BACKWARD (bNode *, node, &snode->edittree->nodes) { if (node->flag & NODE_SELECT) { CTX_data_list_add(result, &snode->edittree->id, &RNA_Node, node); } @@ -907,11 +900,11 @@ static int /*eContextResult*/ node_context(const bContext *C, return CTX_RESULT_MEMBER_NOT_FOUND; } -static void node_widgets(void) +static void node_widgets() { - /* create the widgetmap for the area here */ - wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure( - &(const struct wmGizmoMapType_Params){SPACE_NODE, RGN_TYPE_WINDOW}); + /* Create the widget-map for the area here. */ + wmGizmoMapType_Params params{SPACE_NODE, RGN_TYPE_WINDOW}; + wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(¶ms); WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_transform); WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_crop); WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_sun_beams); @@ -928,15 +921,15 @@ static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, I */ BLI_freelistN(&snode->treepath); - /* XXX Untested in case new_id != NULL... */ + /* XXX Untested in case new_id != nullptr... */ snode->id = new_id; - snode->from = NULL; - snode->nodetree = NULL; - snode->edittree = NULL; + snode->from = nullptr; + snode->nodetree = nullptr; + snode->edittree = nullptr; } else if (GS(old_id->name) == ID_OB) { if (snode->from == old_id) { - if (new_id == NULL) { + if (new_id == nullptr) { snode->flag &= ~SNODE_PIN; } snode->from = new_id; @@ -952,7 +945,7 @@ static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, I else if (GS(old_id->name) == ID_NT) { bNodeTreePath *path, *path_next; - for (path = snode->treepath.first; path; path = path->next) { + for (path = (bNodeTreePath *)snode->treepath.first; path; path = path->next) { if ((ID *)path->nodetree == old_id) { path->nodetree = (bNodeTree *)new_id; id_us_ensure_real(new_id); @@ -961,7 +954,7 @@ static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, I /* first nodetree in path is same as snode->nodetree */ snode->nodetree = path->nodetree; } - if (path->nodetree == NULL) { + if (path->nodetree == nullptr) { break; } } @@ -977,24 +970,24 @@ static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, I /* edittree is just the last in the path, * set this directly since the path may have been shortened above */ if (snode->treepath.last) { - path = snode->treepath.last; + path = (bNodeTreePath *)snode->treepath.last; snode->edittree = path->nodetree; } else { - snode->edittree = NULL; + snode->edittree = nullptr; } } } static int node_space_subtype_get(ScrArea *area) { - SpaceNode *snode = area->spacedata.first; + SpaceNode *snode = (SpaceNode *)area->spacedata.first; return rna_node_tree_idname_to_enum(snode->tree_idname); } static void node_space_subtype_set(ScrArea *area, int value) { - SpaceNode *snode = area->spacedata.first; + SpaceNode *snode = (SpaceNode *)area->spacedata.first; ED_node_set_tree_type(snode, rna_node_tree_type_from_enum(value)); } @@ -1011,7 +1004,7 @@ static void node_space_subtype_item_extend(bContext *C, EnumPropertyItem **item, /* only called once, from space/spacetypes.c */ void ED_spacetype_node(void) { - SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype node"); + SpaceType *st = (SpaceType *)MEM_callocN(sizeof(SpaceType), "spacetype node"); ARegionType *art; st->spaceid = SPACE_NODE; @@ -1034,7 +1027,7 @@ void ED_spacetype_node(void) st->space_subtype_set = node_space_subtype_set; /* regions: main window */ - art = MEM_callocN(sizeof(ARegionType), "spacetype node region"); + art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype node region"); art->regionid = RGN_TYPE_WINDOW; art->init = node_main_region_init; art->draw = node_main_region_draw; @@ -1048,7 +1041,7 @@ void ED_spacetype_node(void) BLI_addhead(&st->regiontypes, art); /* regions: header */ - art = MEM_callocN(sizeof(ARegionType), "spacetype node region"); + art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype node region"); art->regionid = RGN_TYPE_HEADER; art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; @@ -1059,7 +1052,7 @@ void ED_spacetype_node(void) BLI_addhead(&st->regiontypes, art); /* regions: listview/buttons */ - art = MEM_callocN(sizeof(ARegionType), "spacetype node region"); + art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype node region"); art->regionid = RGN_TYPE_UI; art->prefsizex = UI_SIDEBAR_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; @@ -1070,7 +1063,7 @@ void ED_spacetype_node(void) BLI_addhead(&st->regiontypes, art); /* regions: toolbar */ - art = MEM_callocN(sizeof(ARegionType), "spacetype view3d tools region"); + art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype view3d tools region"); art->regionid = RGN_TYPE_TOOLS; art->prefsizex = 58; /* XXX */ art->prefsizey = 50; /* XXX */ diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 738db28a2b6..e449e4a609b 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -763,7 +763,7 @@ static int outliner_id_copy_tag(SpaceOutliner *space_outliner, ListBase *tree) if (tselem->flag & TSE_SELECTED && ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION)) { ID *id = tselem->id; if (!(id->tag & LIB_TAG_DOIT)) { - BKE_copybuffer_tag_ID(tselem->id); + BKE_copybuffer_copy_tag_ID(tselem->id); num_ids++; } } @@ -781,7 +781,7 @@ static int outliner_id_copy_exec(bContext *C, wmOperator *op) SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); char str[FILE_MAX]; - BKE_copybuffer_begin(bmain); + BKE_copybuffer_copy_begin(bmain); const int num_ids = outliner_id_copy_tag(space_outliner, &space_outliner->tree); if (num_ids == 0) { @@ -790,7 +790,7 @@ static int outliner_id_copy_exec(bContext *C, wmOperator *op) } BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend"); - BKE_copybuffer_save(bmain, str, op->reports); + BKE_copybuffer_copy_end(bmain, str, op->reports); BKE_reportf(op->reports, RPT_INFO, "Copied %d selected data-block(s)", num_ids); diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index e58e52b5e94..616953e720a 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -678,8 +678,11 @@ static void sequencer_add_movie_multiple_strips(bContext *C, load_data->start_frame += audio_frame_offset; seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data, audio_skip); - int min_startdisp = MIN2(seq_movie->startdisp, seq_sound->startdisp); - int max_enddisp = MAX2(seq_movie->enddisp, seq_sound->enddisp); + int min_startdisp = 0, max_enddisp = 0; + if (seq_sound != NULL) { + min_startdisp = MIN2(seq_movie->startdisp, seq_sound->startdisp); + max_enddisp = MAX2(seq_movie->enddisp, seq_sound->enddisp); + } load_data->start_frame += max_enddisp - min_startdisp - audio_frame_offset; } diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 3374ff11726..2bbc346fb50 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -1389,7 +1389,8 @@ static void draw_seq_strip(const bContext *C, if ((sseq->flag & SEQ_SHOW_OVERLAY) && (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_THUMBNAILS) && (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE))) { - draw_seq_strip_thumbnail(v2d, C, scene, seq, y1, y2, pixelx, pixely); + draw_seq_strip_thumbnail( + v2d, C, scene, seq, y1, y_threshold ? text_margin_y : y2, pixelx, pixely); } if ((sseq->flag & SEQ_SHOW_OVERLAY) && @@ -2721,8 +2722,6 @@ void draw_timeline_seq(const bContext *C, ARegion *region) } UI_view2d_view_ortho(v2d); - /* Get timeline bound-box, needed for the scroll-bars. */ - SEQ_timeline_boundbox(scene, SEQ_active_seqbase_get(ed), &v2d->tot); draw_seq_backdrop(v2d); if ((sseq->flag & SEQ_SHOW_OVERLAY) && (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_GRID)) { U.v2d_min_gridsize *= 3; @@ -2806,5 +2805,8 @@ void draw_timeline_seq_display(const bContext *C, ARegion *region) } ED_time_scrub_draw_current_frame(region, scene, !(sseq->flag & SEQ_DRAWFRAMES)); + + const ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene)); + SEQ_timeline_boundbox(scene, seqbase, &v2d->tot); UI_view2d_scrollers_draw(v2d, NULL); } diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 8c70f4e3f7a..899c2f6b4f4 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -818,8 +818,6 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even case EVT_ESCKEY: case RIGHTMOUSE: { - Editing *ed = SEQ_editing_get(scene); - for (int i = 0; i < data->num_seq; i++) { transseq_restore(data->ts + i, data->seq_array[i]); } @@ -839,8 +837,6 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); - SEQ_relations_free_imbuf(scene, &ed->seqbase, false); - if (area) { ED_area_status_text(area, NULL); } @@ -1116,7 +1112,6 @@ static int sequencer_reload_exec(bContext *C, wmOperator *op) for (seq = ed->seqbasep->first; seq; seq = seq->next) { if (seq->flag & SELECT) { - SEQ_relations_update_changed_seq_and_deps(scene, seq, 0, 1); SEQ_add_reload_new_file(bmain, scene, seq, !adjust_length); if (adjust_length) { @@ -1326,7 +1321,9 @@ static int sequencer_reassign_inputs_exec(bContext *C, wmOperator *op) last_seq->seq3 = seq3; int old_start = last_seq->start; - SEQ_relations_update_changed_seq_and_deps(scene, last_seq, 1, 1); + SEQ_time_update_recursive(scene, last_seq); + + SEQ_relations_invalidate_cache_preprocessed(scene, last_seq); SEQ_offset_animdata(scene, last_seq, (last_seq->start - old_start)); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -1384,7 +1381,7 @@ static int sequencer_swap_inputs_exec(bContext *C, wmOperator *op) last_seq->seq1 = last_seq->seq2; last_seq->seq2 = seq; - SEQ_relations_update_changed_seq_and_deps(scene, last_seq, 1, 1); + SEQ_relations_invalidate_cache_preprocessed(scene, last_seq); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -1791,6 +1788,7 @@ static int sequencer_offset_clear_exec(bContext *C, wmOperator *UNUSED(op)) while (seq) { ListBase *seqbase = SEQ_active_seqbase_get(ed); SEQ_time_update_sequence(scene, seqbase, seq); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); seq = seq->next; } @@ -2156,6 +2154,7 @@ static int sequencer_strip_jump_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + DEG_id_tag_update(&scene->id, ID_RECALC_AUDIO_SEEK); WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene); return OPERATOR_FINISHED; @@ -2202,10 +2201,12 @@ static void swap_sequence(Scene *scene, Sequence *seqa, Sequence *seqb) seq_b_start = (seqb->start - seqb->startdisp) + seqa->startdisp; SEQ_transform_translate_sequence(scene, seqb, seq_b_start - seqb->start); SEQ_time_update_sequence(scene, seqbase, seqb); + SEQ_relations_invalidate_cache_preprocessed(scene, seqb); seq_a_start = (seqa->start - seqa->startdisp) + seqb->enddisp + gap; SEQ_transform_translate_sequence(scene, seqa, seq_a_start - seqa->start); SEQ_time_update_sequence(scene, seqbase, seqa); + SEQ_relations_invalidate_cache_preprocessed(scene, seqa); } static Sequence *find_next_prev_sequence(Scene *scene, Sequence *test, int lr, int sel) @@ -2673,7 +2674,6 @@ static const EnumPropertyItem prop_change_effect_input_types[] = { static int sequencer_change_effect_input_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Editing *ed = SEQ_editing_get(scene); Sequence *seq = SEQ_select_active_get(scene); Sequence **seq_1, **seq_2; @@ -2700,10 +2700,7 @@ static int sequencer_change_effect_input_exec(bContext *C, wmOperator *op) SWAP(Sequence *, *seq_1, *seq_2); - SEQ_relations_update_changed_seq_and_deps(scene, seq, 0, 1); - - /* Invalidate cache. */ - SEQ_relations_free_imbuf(scene, &ed->seqbase, false); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); return OPERATOR_FINISHED; @@ -2757,7 +2754,6 @@ EnumPropertyItem sequencer_prop_effect_types[] = { static int sequencer_change_effect_type_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Editing *ed = SEQ_editing_get(scene); Sequence *seq = SEQ_select_active_get(scene); const int new_type = RNA_enum_get(op->ptr, "type"); @@ -2783,10 +2779,7 @@ static int sequencer_change_effect_type_exec(bContext *C, wmOperator *op) sh = SEQ_effect_handle_get(seq); sh.init(seq); - SEQ_relations_update_changed_seq_and_deps(scene, seq, 0, 1); - /* Invalidate cache. */ - SEQ_relations_free_imbuf(scene, &ed->seqbase, false); - + SEQ_relations_invalidate_cache_preprocessed(scene, seq); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); return OPERATOR_FINISHED; @@ -2880,9 +2873,6 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op) ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene)); SEQ_time_update_sequence(scene, seqbase, seq); - - /* Invalidate cache. */ - SEQ_relations_free_imbuf(scene, seqbase, false); } else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) { bSound *sound = seq->sound; @@ -2906,8 +2896,10 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op) prop = RNA_struct_find_property(&seq_ptr, "filepath"); RNA_property_string_set(&seq_ptr, prop, filepath); RNA_property_update(C, &seq_ptr, prop); + SEQ_relations_sequence_free_anim(seq); } + SEQ_relations_invalidate_cache_raw(scene, seq); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); return OPERATOR_FINISHED; diff --git a/source/blender/editors/space_sequencer/sequencer_thumbnails.c b/source/blender/editors/space_sequencer/sequencer_thumbnails.c index 9efd78c47ff..fe9cd44c5df 100644 --- a/source/blender/editors/space_sequencer/sequencer_thumbnails.c +++ b/source/blender/editors/space_sequencer/sequencer_thumbnails.c @@ -55,6 +55,7 @@ typedef struct ThumbnailDrawJob { rctf *view_area; float pixelx; float pixely; + float thumb_height; } ThumbnailDrawJob; typedef struct ThumbDataItem { @@ -108,7 +109,7 @@ static void seq_get_thumb_image_dimensions(Sequence *seq, float pixelx, float pixely, float *r_thumb_width, - float *r_thumb_height, + float thumb_height, float *r_image_width, float *r_image_height) { @@ -127,20 +128,15 @@ static void seq_get_thumb_image_dimensions(Sequence *seq, } /* Calculate thumb dimensions. */ - float thumb_height = (SEQ_STRIP_OFSTOP - SEQ_STRIP_OFSBOTTOM) - (20 * U.dpi_fac * pixely); aspect_ratio = ((float)image_width) / image_height; float thumb_h_px = thumb_height / pixely; float thumb_width = aspect_ratio * thumb_h_px * pixelx; - if (r_thumb_height == NULL) { - *r_thumb_width = thumb_width; - return; - } - - *r_thumb_height = thumb_height; - *r_image_width = image_width; - *r_image_height = image_height; *r_thumb_width = thumb_width; + if (r_image_width && r_image_height) { + *r_image_width = image_width; + *r_image_height = image_height; + } } static float seq_thumbnail_get_start_frame(Sequence *seq, float frame_step, rctf *view_area) @@ -174,7 +170,7 @@ static void thumbnail_start_job(void *data, if (check_seq_need_thumbnails(seq_orig, tj->view_area)) { seq_get_thumb_image_dimensions( - val->seq_dupli, tj->pixelx, tj->pixely, &frame_step, NULL, NULL, NULL); + val->seq_dupli, tj->pixelx, tj->pixely, &frame_step, tj->thumb_height, NULL, NULL); start_frame = seq_thumbnail_get_start_frame(seq_orig, frame_step, tj->view_area); SEQ_render_thumbnails( &tj->context, val->seq_dupli, seq_orig, start_frame, frame_step, tj->view_area, stop); @@ -191,7 +187,7 @@ static void thumbnail_start_job(void *data, if (check_seq_need_thumbnails(seq_orig, tj->view_area)) { seq_get_thumb_image_dimensions( - val->seq_dupli, tj->pixelx, tj->pixely, &frame_step, NULL, NULL, NULL); + val->seq_dupli, tj->pixelx, tj->pixely, &frame_step, tj->thumb_height, NULL, NULL); start_frame = seq_thumbnail_get_start_frame(seq_orig, frame_step, tj->view_area); SEQ_render_thumbnails_base_set(&tj->context, val->seq_dupli, seq_orig, tj->view_area, stop); SEQ_relations_sequence_free_anim(val->seq_dupli); @@ -243,7 +239,10 @@ static GHash *sequencer_thumbnail_ghash_init(const bContext *C, View2D *v2d, Edi return thumb_data_hash; } -static void sequencer_thumbnail_init_job(const bContext *C, View2D *v2d, Editing *ed) +static void sequencer_thumbnail_init_job(const bContext *C, + View2D *v2d, + Editing *ed, + float thumb_height) { wmJob *wm_job; ThumbnailDrawJob *tj = NULL; @@ -273,6 +272,7 @@ static void sequencer_thumbnail_init_job(const bContext *C, View2D *v2d, Editing tj->sequences_ghash = sequencer_thumbnail_ghash_init(C, v2d, ed); tj->pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask); tj->pixely = BLI_rctf_size_y(&v2d->cur) / BLI_rcti_size_y(&v2d->mask); + tj->thumb_height = thumb_height; WM_jobs_customdata_set(wm_job, tj, thumbnail_freejob); WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_SEQUENCER, NC_SCENE | ND_SEQUENCER); WM_jobs_callbacks(wm_job, thumbnail_start_job, NULL, NULL, thumbnail_endjob); @@ -296,10 +296,8 @@ static bool sequencer_thumbnail_v2d_is_navigating(const bContext *C) return (v2d->flag & V2D_IS_NAVIGATING) != 0; } -static void sequencer_thumbnail_start_job_if_necessary(const bContext *C, - Editing *ed, - View2D *v2d, - bool thumbnail_is_missing) +static void sequencer_thumbnail_start_job_if_necessary( + const bContext *C, Editing *ed, View2D *v2d, bool thumbnail_is_missing, float thumb_height) { SpaceSeq *sseq = CTX_wm_space_seq(C); @@ -326,7 +324,7 @@ static void sequencer_thumbnail_start_job_if_necessary(const bContext *C, WM_jobs_stop(CTX_wm_manager(C), NULL, thumbnail_start_job); } - sequencer_thumbnail_init_job(C, v2d, ed); + sequencer_thumbnail_init_job(C, v2d, ed, thumb_height); sseq->runtime.last_thumbnail_area = v2d->cur; } @@ -450,7 +448,7 @@ void draw_seq_strip_thumbnail(View2D *v2d, float pixely) { bool clipped = false; - float image_height, image_width, thumb_width, thumb_height; + float image_height, image_width, thumb_width; rcti crop; /* If width of the strip too small ignore drawing thumbnails. */ @@ -464,10 +462,11 @@ void draw_seq_strip_thumbnail(View2D *v2d, return; } + const float thumb_height = y2 - y1; seq_get_thumb_image_dimensions( - seq, pixelx, pixely, &thumb_width, &thumb_height, &image_width, &image_height); + seq, pixelx, pixely, &thumb_width, thumb_height, &image_width, &image_height); - float thumb_y_end = y1 + thumb_height - pixely; + float thumb_y_end = y1 + thumb_height; float cut_off = 0; float upper_thumb_bound = (seq->endstill) ? (seq->start + seq->len) : seq->enddisp; @@ -537,7 +536,7 @@ void draw_seq_strip_thumbnail(View2D *v2d, ImBuf *ibuf = SEQ_get_thumbnail(&context, seq, timeline_frame, &crop, clipped); if (!ibuf) { - sequencer_thumbnail_start_job_if_necessary(C, scene->ed, v2d, true); + sequencer_thumbnail_start_job_if_necessary(C, scene->ed, v2d, true, thumb_height); ibuf = sequencer_thumbnail_closest_from_memory( &context, seq, timeline_frame, last_displayed_thumbnails, &crop, clipped); diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index fc20739b5e2..f6f8e45590f 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -28,6 +28,7 @@ #include "DNA_gpencil_types.h" #include "DNA_mask_types.h" #include "DNA_scene_types.h" +#include "DNA_sound_types.h" #include "MEM_guardedalloc.h" @@ -184,7 +185,7 @@ static SpaceLink *sequencer_create(const ScrArea *UNUSED(area), const Scene *sce region->v2d.cur = region->v2d.tot; region->v2d.min[0] = 10.0f; - region->v2d.min[1] = 4.0f; + region->v2d.min[1] = 1.0f; region->v2d.max[0] = MAXFRAMEF; region->v2d.max[1] = MAXSEQ; @@ -400,7 +401,7 @@ static bool image_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) } } - return 0; + return WM_drag_is_ID_type(drag, ID_IM); } static bool movie_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) @@ -416,7 +417,8 @@ static bool movie_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) } } } - return 0; + + return WM_drag_is_ID_type(drag, ID_MC); } static bool sound_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) @@ -432,35 +434,61 @@ static bool sound_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) } } } - return 0; + + return WM_drag_is_ID_type(drag, ID_SO); } static void sequencer_drop_copy(wmDrag *drag, wmDropBox *drop) { - /* Copy drag path to properties. */ - if (RNA_struct_find_property(drop->ptr, "filepath")) { - RNA_string_set(drop->ptr, "filepath", drag->path); + ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0); + /* ID dropped. */ + if (id != NULL) { + const ID_Type id_type = GS(id->name); + if (id_type == ID_IM) { + Image *ima = (Image *)id; + PointerRNA itemptr; + char dir[FILE_MAX], file[FILE_MAX]; + BLI_split_dirfile(ima->filepath, dir, file, sizeof(dir), sizeof(file)); + RNA_string_set(drop->ptr, "directory", dir); + RNA_collection_clear(drop->ptr, "files"); + RNA_collection_add(drop->ptr, "files", &itemptr); + RNA_string_set(&itemptr, "name", file); + } + else if (id_type == ID_MC) { + MovieClip *clip = (MovieClip *)id; + RNA_string_set(drop->ptr, "filepath", clip->filepath); + RNA_struct_property_unset(drop->ptr, "name"); + } + else if (id_type == ID_SO) { + bSound *sound = (bSound *)id; + RNA_string_set(drop->ptr, "filepath", sound->filepath); + RNA_struct_property_unset(drop->ptr, "name"); + } } + /* Path dropped. */ + else if (drag->path[0]) { + if (RNA_struct_find_property(drop->ptr, "filepath")) { + RNA_string_set(drop->ptr, "filepath", drag->path); + } + if (RNA_struct_find_property(drop->ptr, "directory")) { + PointerRNA itemptr; + char dir[FILE_MAX], file[FILE_MAX]; - if (RNA_struct_find_property(drop->ptr, "directory")) { - PointerRNA itemptr; - char dir[FILE_MAX], file[FILE_MAX]; - - BLI_split_dirfile(drag->path, dir, file, sizeof(dir), sizeof(file)); + BLI_split_dirfile(drag->path, dir, file, sizeof(dir), sizeof(file)); - RNA_string_set(drop->ptr, "directory", dir); + RNA_string_set(drop->ptr, "directory", dir); - RNA_collection_clear(drop->ptr, "files"); - RNA_collection_add(drop->ptr, "files", &itemptr); - RNA_string_set(&itemptr, "name", file); + RNA_collection_clear(drop->ptr, "files"); + RNA_collection_add(drop->ptr, "files", &itemptr); + RNA_string_set(&itemptr, "name", file); + } } } /* This region dropbox definition. */ -static void sequencer_dropboxes(void) -{ - ListBase *lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW); +static void sequencer_dropboxes_add_to_lb(ListBase *lb) +{ WM_dropbox_add( lb, "SEQUENCER_OT_image_strip_add", image_drop_poll, sequencer_drop_copy, NULL, NULL); WM_dropbox_add( @@ -469,6 +497,14 @@ static void sequencer_dropboxes(void) lb, "SEQUENCER_OT_sound_strip_add", sound_drop_poll, sequencer_drop_copy, NULL, NULL); } +static void sequencer_dropboxes(void) +{ + ListBase *lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW); + sequencer_dropboxes_add_to_lb(lb); + lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_PREVIEW); + sequencer_dropboxes_add_to_lb(lb); +} + /* ************* end drop *********** */ /* DO NOT make this static, this hides the symbol and breaks API generation script. */ @@ -757,6 +793,9 @@ static void sequencer_preview_region_init(wmWindowManager *wm, ARegion *region) /* Own keymap. */ keymap = WM_keymap_ensure(wm->defaultconf, "SequencerPreview", SPACE_SEQ, 0); WM_event_add_keymap_handler_v2d_mask(®ion->handlers, keymap); + + ListBase *lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_PREVIEW); + WM_event_add_dropbox_handler(®ion->handlers, lb); } static void sequencer_preview_region_layout(const bContext *C, ARegion *region) diff --git a/source/blender/editors/space_spreadsheet/CMakeLists.txt b/source/blender/editors/space_spreadsheet/CMakeLists.txt index 192b80881ee..27446fe1a94 100644 --- a/source/blender/editors/space_spreadsheet/CMakeLists.txt +++ b/source/blender/editors/space_spreadsheet/CMakeLists.txt @@ -41,10 +41,10 @@ set(SRC spreadsheet_data_source.cc spreadsheet_data_source_geometry.cc spreadsheet_dataset_draw.cc - spreadsheet_dataset_layout.cc spreadsheet_draw.cc spreadsheet_layout.cc spreadsheet_ops.cc + spreadsheet_panels.cc spreadsheet_row_filter.cc spreadsheet_row_filter_ui.cc @@ -56,7 +56,6 @@ set(SRC spreadsheet_data_source.hh spreadsheet_data_source_geometry.hh spreadsheet_dataset_draw.hh - spreadsheet_dataset_layout.hh spreadsheet_draw.hh spreadsheet_intern.hh spreadsheet_layout.hh diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc index 50b67c55bd6..b37706e02e8 100644 --- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc +++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc @@ -41,6 +41,8 @@ #include "WM_api.h" #include "WM_types.h" +#include "BLT_translation.h" + #include "BLF_api.h" #include "spreadsheet_intern.hh" @@ -591,35 +593,10 @@ static void spreadsheet_dataset_region_listener(const wmRegionListenerParams *pa spreadsheet_header_region_listener(params); } -static void spreadsheet_dataset_region_init(wmWindowManager *wm, ARegion *region) -{ - region->v2d.scroll |= V2D_SCROLL_RIGHT; - region->v2d.scroll &= ~(V2D_SCROLL_LEFT | V2D_SCROLL_TOP | V2D_SCROLL_BOTTOM); - region->v2d.scroll |= V2D_SCROLL_HORIZONTAL_HIDE; - region->v2d.scroll |= V2D_SCROLL_VERTICAL_HIDE; - - UI_view2d_region_reinit(®ion->v2d, V2D_COMMONVIEW_LIST, region->winx, region->winy); - - wmKeyMap *keymap = WM_keymap_ensure( - wm->defaultconf, "Spreadsheet Generic", SPACE_SPREADSHEET, 0); - WM_event_add_keymap_handler(®ion->handlers, keymap); -} - static void spreadsheet_dataset_region_draw(const bContext *C, ARegion *region) { spreadsheet_update_context_path(C); - - View2D *v2d = ®ion->v2d; - UI_view2d_view_ortho(v2d); - UI_ThemeClearColor(TH_BACK); - - draw_dataset_in_region(C, region); - - /* reset view matrix */ - UI_view2d_view_restore(C); - - /* scrollers */ - UI_view2d_scrollers_draw(v2d, nullptr); + ED_region_panels(C, region); } static void spreadsheet_sidebar_init(wmWindowManager *wm, ARegion *region) @@ -710,11 +687,12 @@ void ED_spacetype_spreadsheet(void) /* regions: channels */ art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spreadsheet dataset region"); art->regionid = RGN_TYPE_CHANNELS; - art->prefsizex = 200 + V2D_SCROLL_WIDTH; + art->prefsizex = 150 + V2D_SCROLL_WIDTH; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D; - art->init = spreadsheet_dataset_region_init; + art->init = ED_region_panels_init; art->draw = spreadsheet_dataset_region_draw; art->listener = spreadsheet_dataset_region_listener; + blender::ed::spreadsheet::spreadsheet_data_set_region_panels_register(*art); BLI_addhead(&st->regiontypes, art); BKE_spacetype_register(st); diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc index cf048d1bbd8..8cdb462718d 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc @@ -78,7 +78,7 @@ static std::optional<eSpreadsheetColumnValueType> cpp_type_to_column_value_type( void ExtraColumns::foreach_default_column_ids( FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const { - for (const auto &item : columns_.items()) { + for (const auto item : columns_.items()) { SpreadsheetColumnID column_id; column_id.name = (char *)item.key.c_str(); fn(column_id, true); @@ -168,12 +168,12 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( if (!attribute) { return {}; } - const fn::GVArray *varray = scope_.add(std::move(attribute.varray)); + fn::GVArray varray = std::move(attribute.varray); if (attribute.domain != domain_) { return {}; } - int domain_size = varray->size(); - const CustomDataType type = bke::cpp_type_to_custom_data_type(varray->type()); + int domain_size = varray.size(); + const CustomDataType type = bke::cpp_type_to_custom_data_type(varray.type()); switch (type) { case CD_PROP_FLOAT: return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT, @@ -181,7 +181,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( domain_size, [varray](int index, CellValue &r_cell_value) { float value; - varray->get(index, &value); + varray.get(index, &value); r_cell_value.value_float = value; }); case CD_PROP_INT32: @@ -191,7 +191,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( domain_size, [varray](int index, CellValue &r_cell_value) { int value; - varray->get(index, &value); + varray.get(index, &value); r_cell_value.value_int = value; }, STREQ(column_id.name, "id") ? 5.5f : 0.0f); @@ -201,7 +201,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( domain_size, [varray](int index, CellValue &r_cell_value) { bool value; - varray->get(index, &value); + varray.get(index, &value); r_cell_value.value_bool = value; }); case CD_PROP_FLOAT2: { @@ -210,7 +210,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( domain_size, [varray](int index, CellValue &r_cell_value) { float2 value; - varray->get(index, &value); + varray.get(index, &value); r_cell_value.value_float2 = value; }); } @@ -220,7 +220,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( domain_size, [varray](int index, CellValue &r_cell_value) { float3 value; - varray->get(index, &value); + varray.get(index, &value); r_cell_value.value_float3 = value; }); } @@ -230,7 +230,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( domain_size, [varray](int index, CellValue &r_cell_value) { ColorGeometry4f value; - varray->get(index, &value); + varray.get(index, &value); r_cell_value.value_color = value; }); } @@ -582,8 +582,7 @@ int VolumeDataSource::tot_rows() const } GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspreadsheet, - Object *object_eval, - const GeometryComponentType used_component_type) + Object *object_eval) { GeometrySet geometry_set; if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL) { @@ -615,7 +614,7 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread } } else { - if (used_component_type == GEO_COMPONENT_TYPE_MESH && object_eval->mode == OB_MODE_EDIT) { + if (object_eval->mode == OB_MODE_EDIT && object_eval->type == OB_MESH) { Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval, false); if (mesh == nullptr) { return geometry_set; @@ -738,7 +737,7 @@ static void add_fields_as_extra_columns(SpaceSpreadsheet *sspreadsheet, const AttributeDomain domain = (AttributeDomain)sspreadsheet->attribute_domain; const int domain_size = component.attribute_domain_size(domain); - for (const auto &item : fields_to_show.items()) { + for (const auto item : fields_to_show.items()) { StringRef name = item.key; const GField &field = item.value; @@ -762,8 +761,7 @@ std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); const AttributeDomain domain = (AttributeDomain)sspreadsheet->attribute_domain; const GeometryComponentType component_type = get_display_component_type(C, object_eval); - GeometrySet geometry_set = spreadsheet_get_display_geometry_set( - sspreadsheet, object_eval, component_type); + GeometrySet geometry_set = spreadsheet_get_display_geometry_set(sspreadsheet, object_eval); if (!geometry_set.has(component_type)) { return {}; diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc index 6a04440afc7..2a81b56d129 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc @@ -14,288 +14,226 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include <array> - #include "DNA_space_types.h" #include "DNA_windowmanager_types.h" #include "BKE_context.h" #include "BKE_volume.h" -#include "BLF_api.h" - -#include "BLI_rect.h" - #include "RNA_access.h" #include "UI_interface.h" -#include "UI_view2d.h" +#include "UI_interface.hh" +#include "UI_tree_view.hh" #include "WM_types.h" +#include "BLT_translation.h" + #include "spreadsheet_dataset_draw.hh" #include "spreadsheet_draw.hh" #include "spreadsheet_intern.hh" -static int is_component_row_selected(struct uiBut *but, const void *arg) -{ - SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)arg; +namespace blender::ed::spreadsheet { - GeometryComponentType component = (GeometryComponentType)UI_but_datasetrow_component_get(but); - AttributeDomain domain = (AttributeDomain)UI_but_datasetrow_domain_get(but); +class GeometryDataSetTreeView; - const bool is_component_selected = (GeometryComponentType) - sspreadsheet->geometry_component_type == component; - const bool is_domain_selected = (AttributeDomain)sspreadsheet->attribute_domain == domain; - bool is_selected = is_component_selected && is_domain_selected; +class GeometryDataSetTreeViewItem : public ui::AbstractTreeViewItem { + GeometryComponentType component_type_; + std::optional<AttributeDomain> domain_; + BIFIconID icon_; - if (ELEM(component, GEO_COMPONENT_TYPE_VOLUME, GEO_COMPONENT_TYPE_INSTANCES)) { - is_selected = is_component_selected; - } + public: + GeometryDataSetTreeViewItem(GeometryComponentType component_type, + StringRef label, + BIFIconID icon); + GeometryDataSetTreeViewItem(GeometryComponentType component_type, + AttributeDomain domain, + StringRef label, + BIFIconID icon); - return is_selected; -} + void on_activate() override; -namespace blender::ed::spreadsheet { + void build_row(uiLayout &row) override; -/* -------------------------------------------------------------------- */ -/* Draw Context */ + protected: + std::optional<bool> should_be_active() const override; + bool supports_collapsing() const override; -class DatasetDrawContext { - std::array<int, 2> mval_; + private: + GeometryDataSetTreeView &get_tree() const; + std::optional<int> count() const; +}; - public: - const SpaceSpreadsheet *sspreadsheet; - Object *object_eval; - /* Current geometry set, changes per component. */ - GeometrySet current_geometry_set; +class GeometryDataSetTreeView : public ui::AbstractTreeView { + GeometrySet geometry_set_; + const bContext &C_; + SpaceSpreadsheet &sspreadsheet_; + bScreen &screen_; - DatasetDrawContext(const bContext *C); + friend class GeometryDataSetTreeViewItem; - GeometrySet geometry_set_from_component(GeometryComponentType component); - const std::array<int, 2> &cursor_mval() const; + public: + GeometryDataSetTreeView(GeometrySet geometry_set, const bContext &C) + : geometry_set_(std::move(geometry_set)), + C_(C), + sspreadsheet_(*CTX_wm_space_spreadsheet(&C)), + screen_(*CTX_wm_screen(&C)) + { + } + + void build_tree() override + { + GeometryDataSetTreeViewItem &mesh = this->add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_MESH, IFACE_("Mesh"), ICON_MESH_DATA); + mesh.add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_POINT, IFACE_("Vertex"), ICON_VERTEXSEL); + mesh.add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_EDGE, IFACE_("Edge"), ICON_EDGESEL); + mesh.add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_FACE, IFACE_("Face"), ICON_FACESEL); + mesh.add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_CORNER, IFACE_("Face Corner"), ICON_NODE_CORNER); + + GeometryDataSetTreeViewItem &curve = this->add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_CURVE, IFACE_("Curve"), ICON_CURVE_DATA); + curve.add_tree_item<GeometryDataSetTreeViewItem>(GEO_COMPONENT_TYPE_CURVE, + ATTR_DOMAIN_POINT, + IFACE_("Control Point"), + ICON_CURVE_BEZCIRCLE); + curve.add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_CURVE, ATTR_DOMAIN_CURVE, IFACE_("Spline"), ICON_CURVE_PATH); + + GeometryDataSetTreeViewItem &pointcloud = this->add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_POINT_CLOUD, IFACE_("Point Cloud"), ICON_POINTCLOUD_DATA); + pointcloud.add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_POINT_CLOUD, ATTR_DOMAIN_POINT, IFACE_("Point"), ICON_PARTICLE_POINT); + + this->add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_VOLUME, IFACE_("Volume Grids"), ICON_VOLUME_DATA); + + this->add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_INSTANCES, ATTR_DOMAIN_INSTANCE, IFACE_("Instances"), ICON_EMPTY_AXIS); + } }; -DatasetDrawContext::DatasetDrawContext(const bContext *C) - : sspreadsheet(CTX_wm_space_spreadsheet(C)), - object_eval(spreadsheet_get_object_eval(sspreadsheet, CTX_data_depsgraph_pointer(C))) +GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem(GeometryComponentType component_type, + StringRef label, + BIFIconID icon) + : component_type_(component_type), domain_(std::nullopt), icon_(icon) { - const wmWindow *win = CTX_wm_window(C); - const ARegion *region = CTX_wm_region(C); - mval_ = {win->eventstate->xy[0] - region->winrct.xmin, - win->eventstate->xy[1] - region->winrct.ymin}; + label_ = label; + this->set_collapsed(false); } - -GeometrySet DatasetDrawContext::geometry_set_from_component(GeometryComponentType component) +GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem(GeometryComponentType component_type, + AttributeDomain domain, + StringRef label, + BIFIconID icon) + : component_type_(component_type), domain_(domain), icon_(icon) { - return spreadsheet_get_display_geometry_set(sspreadsheet, object_eval, component); + label_ = label; } -const std::array<int, 2> &DatasetDrawContext::cursor_mval() const +void GeometryDataSetTreeViewItem::on_activate() { - return mval_; + GeometryDataSetTreeView &tree_view = this->get_tree(); + bContext &C = const_cast<bContext &>(tree_view.C_); + SpaceSpreadsheet &sspreadsheet = tree_view.sspreadsheet_; + tree_view.sspreadsheet_.geometry_component_type = component_type_; + if (domain_) { + tree_view.sspreadsheet_.attribute_domain = *domain_; + } + PointerRNA ptr; + RNA_pointer_create(&tree_view.screen_.id, &RNA_SpaceSpreadsheet, &sspreadsheet, &ptr); + RNA_property_update(&C, &ptr, RNA_struct_find_property(&ptr, "attribute_domain")); + RNA_property_update(&C, &ptr, RNA_struct_find_property(&ptr, "geometry_component_type")); } -/* -------------------------------------------------------------------- */ -/* Drawer */ - -DatasetRegionDrawer::DatasetRegionDrawer(const ARegion *region, - uiBlock &block, - DatasetDrawContext &draw_context) - : row_height(UI_UNIT_Y), - xmin(region->v2d.cur.xmin), - xmax(region->v2d.cur.xmax), - block(block), - v2d(region->v2d), - draw_context(draw_context) +void GeometryDataSetTreeViewItem::build_row(uiLayout &row) { + uiItemL(&row, label_.c_str(), icon_); + + if (const std::optional<int> count = this->count()) { + /* Using the tree row button instead of a separate right aligned button gives padding + * to the right side of the number, which it didn't have with the button. */ + char element_count[7]; + BLI_str_format_attribute_domain_size(element_count, *count); + UI_but_hint_drawstr_set((uiBut *)this->tree_row_button(), element_count); + } } -void DatasetRegionDrawer::draw_hierarchy(const DatasetLayoutHierarchy &layout) +std::optional<bool> GeometryDataSetTreeViewItem::should_be_active() const { - for (const DatasetComponentLayoutInfo &component : layout.components) { - draw_context.current_geometry_set = draw_context.geometry_set_from_component(component.type); - - draw_component_row(component); - - /* Iterate attribute domains, skip unset ones (storage has to be in a enum-based, fixed size - * array so uses optionals to support skipping enum values that shouldn't be displayed for a - * component). */ - for (const auto &optional_domain : component.attr_domains) { - if (!optional_domain) { - continue; - } + GeometryDataSetTreeView &tree_view = this->get_tree(); + SpaceSpreadsheet &sspreadsheet = tree_view.sspreadsheet_; - const DatasetAttrDomainLayoutInfo &domain_info = *optional_domain; - draw_attribute_domain_row(component, domain_info); - } + if (component_type_ == GEO_COMPONENT_TYPE_VOLUME) { + return sspreadsheet.geometry_component_type == component_type_; } -} -static int element_count_from_instances(const GeometrySet &geometry_set) -{ - if (geometry_set.has_instances()) { - const InstancesComponent *instances_component = - geometry_set.get_component_for_read<InstancesComponent>(); - return instances_component->instances_amount(); + if (!domain_) { + return false; } - return 0; + + return sspreadsheet.geometry_component_type == component_type_ && + sspreadsheet.attribute_domain == *domain_; } -static int element_count_from_volume(const GeometrySet &geometry_set) +bool GeometryDataSetTreeViewItem::supports_collapsing() const { - if (const Volume *volume = geometry_set.get_volume_for_read()) { - return BKE_volume_num_grids(volume); - } - return 0; + return false; } -static int element_count_from_component_domain(const GeometrySet &geometry_set, - GeometryComponentType component, - AttributeDomain domain) +GeometryDataSetTreeView &GeometryDataSetTreeViewItem::get_tree() const { - if (geometry_set.has_mesh() && component == GEO_COMPONENT_TYPE_MESH) { - const MeshComponent *mesh_component = geometry_set.get_component_for_read<MeshComponent>(); - return mesh_component->attribute_domain_size(domain); - } - - if (geometry_set.has_pointcloud() && component == GEO_COMPONENT_TYPE_POINT_CLOUD) { - const PointCloudComponent *point_cloud_component = - geometry_set.get_component_for_read<PointCloudComponent>(); - return point_cloud_component->attribute_domain_size(domain); - } - - if (geometry_set.has_volume() && component == GEO_COMPONENT_TYPE_VOLUME) { - const VolumeComponent *volume_component = - geometry_set.get_component_for_read<VolumeComponent>(); - return volume_component->attribute_domain_size(domain); - } - - if (geometry_set.has_curve() && component == GEO_COMPONENT_TYPE_CURVE) { - const CurveComponent *curve_component = geometry_set.get_component_for_read<CurveComponent>(); - return curve_component->attribute_domain_size(domain); - } - - return 0; + return static_cast<GeometryDataSetTreeView &>(this->get_tree_view()); } -void DatasetRegionDrawer::draw_dataset_row(const int indentation, - const GeometryComponentType component, - const std::optional<AttributeDomain> domain, - BIFIconID icon, - const char *label, - const bool is_active) +std::optional<int> GeometryDataSetTreeViewItem::count() const { + GeometryDataSetTreeView &tree_view = this->get_tree(); + GeometrySet &geometry = tree_view.geometry_set_; - const float row_height = UI_UNIT_Y; - const float padding_x = UI_UNIT_X * 0.25f; - - const rctf rect = {float(xmin) + padding_x, - float(xmax) - V2D_SCROLL_HANDLE_WIDTH, - ymin_offset - row_height, - ymin_offset}; - - char element_count[7]; - if (component == GEO_COMPONENT_TYPE_INSTANCES) { - BLI_str_format_attribute_domain_size( - element_count, element_count_from_instances(draw_context.current_geometry_set)); - } - if (component == GEO_COMPONENT_TYPE_VOLUME) { - BLI_str_format_attribute_domain_size( - element_count, element_count_from_volume(draw_context.current_geometry_set)); - } - else { - BLI_str_format_attribute_domain_size( - element_count, - domain ? element_count_from_component_domain( - draw_context.current_geometry_set, component, *domain) : - 0); - } - - std::string label_and_element_count = label; - label_and_element_count += UI_SEP_CHAR; - label_and_element_count += element_count; - - uiBut *bt = uiDefIconTextButO(&block, - UI_BTYPE_DATASETROW, - "SPREADSHEET_OT_change_spreadsheet_data_source", - WM_OP_INVOKE_DEFAULT, - icon, - label, - rect.xmin, - rect.ymin, - BLI_rctf_size_x(&rect), - BLI_rctf_size_y(&rect), - nullptr); - - UI_but_datasetrow_indentation_set(bt, indentation); - - if (is_active) { - UI_but_hint_drawstr_set(bt, element_count); - UI_but_datasetrow_component_set(bt, component); - if (domain) { - UI_but_datasetrow_domain_set(bt, *domain); - } - UI_but_func_pushed_state_set(bt, &is_component_row_selected, draw_context.sspreadsheet); - - PointerRNA *but_ptr = UI_but_operator_ptr_get((uiBut *)bt); - RNA_int_set(but_ptr, "component_type", component); - if (domain) { - RNA_int_set(but_ptr, "attribute_domain_type", *domain); + /* Special case for volumes since there is no grid domain. */ + if (component_type_ == GEO_COMPONENT_TYPE_VOLUME) { + if (const Volume *volume = geometry.get_volume_for_read()) { + return BKE_volume_num_grids(volume); } + return 0; } - ymin_offset -= row_height; -} - -void DatasetRegionDrawer::draw_component_row(const DatasetComponentLayoutInfo &component_info) -{ - if (ELEM(component_info.type, GEO_COMPONENT_TYPE_VOLUME, GEO_COMPONENT_TYPE_INSTANCES)) { - draw_dataset_row( - 0, component_info.type, std::nullopt, component_info.icon, component_info.label, true); + if (!domain_) { + return std::nullopt; } - else { - draw_dataset_row( - 0, component_info.type, std::nullopt, component_info.icon, component_info.label, false); + + if (const GeometryComponent *component = geometry.get_component_for_read(component_type_)) { + return component->attribute_domain_size(*domain_); } -} -void DatasetRegionDrawer::draw_attribute_domain_row( - const DatasetComponentLayoutInfo &component_info, - const DatasetAttrDomainLayoutInfo &domain_info) -{ - draw_dataset_row( - 1, component_info.type, domain_info.type, domain_info.icon, domain_info.label, true); + return 0; } -/* -------------------------------------------------------------------- */ -/* Drawer */ - -void draw_dataset_in_region(const bContext *C, ARegion *region) +void spreadsheet_data_set_panel_draw(const bContext *C, Panel *panel) { - DatasetDrawContext draw_context{C}; - if (!draw_context.object_eval) { - /* No object means nothing to display. Keep the region empty. */ + const SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); + Object *object = spreadsheet_get_object_eval(sspreadsheet, CTX_data_depsgraph_pointer(C)); + if (!object) { return; } + uiLayout *layout = panel->layout; - uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS); - - DatasetRegionDrawer drawer{region, *block, draw_context}; + uiBlock *block = uiLayoutGetBlock(layout); - /* Start with an offset to align buttons to spreadsheet rows. Use spreadsheet drawing info for - * that. */ - drawer.ymin_offset = -SpreadsheetDrawer().top_row_height + drawer.row_height; + UI_block_layout_set_current(block, layout); - const DatasetLayoutHierarchy hierarchy = dataset_layout_hierarchy(); - drawer.draw_hierarchy(hierarchy); -#ifndef NDEBUG - dataset_layout_hierarchy_sanity_check(hierarchy); -#endif + ui::AbstractTreeView *tree_view = UI_block_add_view( + *block, + "Data Set Tree View", + std::make_unique<GeometryDataSetTreeView>( + spreadsheet_get_display_geometry_set(sspreadsheet, object), *C)); - UI_block_end(C, block); - UI_view2d_totRect_set(®ion->v2d, region->winx, abs(drawer.ymin_offset)); - UI_block_draw(C, block); + ui::TreeViewBuilder builder(*block); + builder.build_tree_view(*tree_view); } } // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.hh b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.hh index 19906d73e7f..4a604533f11 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.hh @@ -16,49 +16,11 @@ #pragma once -#include <array> - -#include "BKE_geometry_set.hh" -#include "UI_interface.h" -#include "spreadsheet_dataset_layout.hh" - -struct ARegion; -struct View2D; +struct Panel; struct bContext; -struct uiBlock; namespace blender::ed::spreadsheet { -class DatasetDrawContext; - -class DatasetRegionDrawer { - public: - const int row_height; - float ymin_offset = 0; - - int xmin; - int xmax; - uiBlock █ - const View2D &v2d; - DatasetDrawContext &draw_context; - - DatasetRegionDrawer(const ARegion *region, uiBlock &block, DatasetDrawContext &draw_context); - - void draw_hierarchy(const DatasetLayoutHierarchy &layout); - - void draw_attribute_domain_row(const DatasetComponentLayoutInfo &component, - const DatasetAttrDomainLayoutInfo &domain_info); - void draw_component_row(const DatasetComponentLayoutInfo &component_info); - - private: - void draw_dataset_row(const int indentation, - const GeometryComponentType component, - const std::optional<AttributeDomain> domain, - const BIFIconID icon, - const char *label, - const bool is_active); -}; - -void draw_dataset_in_region(const bContext *C, ARegion *region); +void spreadsheet_data_set_panel_draw(const bContext *C, Panel *panel); } // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc deleted file mode 100644 index f15af2e4d32..00000000000 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc +++ /dev/null @@ -1,118 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include <optional> - -#include "BLI_span.hh" - -#include "BLT_translation.h" - -#include "spreadsheet_dataset_layout.hh" - -namespace blender::ed::spreadsheet { - -#define ATTR_INFO(type, label, icon) \ - std::optional<DatasetAttrDomainLayoutInfo> \ - { \ - std::in_place, type, label, icon \ - } -#define ATTR_INFO_NONE(type) \ - { \ - std::nullopt \ - } - -/** - * Definition for the component->attribute-domain hierarchy. - * Constructed at compile time. - * - * \warning Order of attribute-domains matters! It __must__ match the #AttributeDomain - * definition and fill gaps with unset optionals (i.e. `std::nullopt`). Would be nice to use - * array designators for this (which C++ doesn't support). - */ -constexpr DatasetComponentLayoutInfo DATASET_layout_hierarchy[] = { - { - GEO_COMPONENT_TYPE_MESH, - N_("Mesh"), - ICON_MESH_DATA, - { - ATTR_INFO(ATTR_DOMAIN_POINT, N_("Vertex"), ICON_VERTEXSEL), - ATTR_INFO(ATTR_DOMAIN_EDGE, N_("Edge"), ICON_EDGESEL), - ATTR_INFO(ATTR_DOMAIN_FACE, N_("Face"), ICON_FACESEL), - ATTR_INFO(ATTR_DOMAIN_CORNER, N_("Face Corner"), ICON_NODE_CORNER), - }, - }, - { - GEO_COMPONENT_TYPE_CURVE, - N_("Curves"), - ICON_CURVE_DATA, - { - ATTR_INFO(ATTR_DOMAIN_POINT, N_("Control Point"), ICON_CURVE_BEZCIRCLE), - ATTR_INFO_NONE(ATTR_DOMAIN_EDGE), - ATTR_INFO_NONE(ATTR_DOMAIN_CORNER), - ATTR_INFO_NONE(ATTR_DOMAIN_FACE), - ATTR_INFO(ATTR_DOMAIN_CURVE, N_("Spline"), ICON_CURVE_PATH), - }, - }, - { - GEO_COMPONENT_TYPE_POINT_CLOUD, - N_("Point Cloud"), - ICON_POINTCLOUD_DATA, - { - ATTR_INFO(ATTR_DOMAIN_POINT, N_("Point"), ICON_PARTICLE_POINT), - }, - }, - { - GEO_COMPONENT_TYPE_VOLUME, - N_("Volume Grids"), - ICON_VOLUME_DATA, - {}, - }, - { - GEO_COMPONENT_TYPE_INSTANCES, - N_("Instances"), - ICON_EMPTY_AXIS, - {}, - }, -}; - -#undef ATTR_INFO -#undef ATTR_INFO_LABEL - -DatasetLayoutHierarchy dataset_layout_hierarchy() -{ - return DatasetLayoutHierarchy{ - Span{DATASET_layout_hierarchy, ARRAY_SIZE(DATASET_layout_hierarchy)}}; -} - -#ifndef NDEBUG -/** - * Debug-only sanity check for correct attribute domain initialization (order/indices must - * match AttributeDomain). This doesn't check for all possible missuses, but should catch the most - * likely mistakes. - */ -void dataset_layout_hierarchy_sanity_check(const DatasetLayoutHierarchy &hierarchy) -{ - for (const DatasetComponentLayoutInfo &component : hierarchy.components) { - for (uint i = 0; i < component.attr_domains.size(); i++) { - if (component.attr_domains[i]) { - BLI_assert(component.attr_domains[i]->type == static_cast<AttributeDomain>(i)); - } - } - } -} -#endif - -} // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.hh b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.hh deleted file mode 100644 index d463739a0fa..00000000000 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.hh +++ /dev/null @@ -1,68 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#pragma once - -#include <array> -#include <optional> - -/* Enum definitions... */ -#include "BKE_attribute.h" -#include "BKE_geometry_set.h" - -#include "BLI_span.hh" - -/* More enum definitions... */ -#include "UI_resources.h" - -#pragma once - -namespace blender::ed::spreadsheet { - -struct DatasetAttrDomainLayoutInfo { - AttributeDomain type; - const char *label; - BIFIconID icon; - - constexpr DatasetAttrDomainLayoutInfo(AttributeDomain type, const char *label, BIFIconID icon) - : type(type), label(label), icon(icon) - { - } -}; - -struct DatasetComponentLayoutInfo { - GeometryComponentType type; - const char *label; - BIFIconID icon; - /** Array of attribute-domains. Has to be fixed size based on #AttributeDomain enum, but not all - * values need displaying for all parent components. Hence the optional use. */ - using AttrDomainArray = std::array<std::optional<DatasetAttrDomainLayoutInfo>, ATTR_DOMAIN_NUM>; - const AttrDomainArray attr_domains; -}; - -struct DatasetLayoutHierarchy { - /** The components for display (with layout info like icon and label). Each component stores - * the attribute domains it wants to display (also with layout info like icon and label). */ - const Span<DatasetComponentLayoutInfo> components; -}; - -DatasetLayoutHierarchy dataset_layout_hierarchy(); - -#ifndef NDEBUG -void dataset_layout_hierarchy_sanity_check(const DatasetLayoutHierarchy &hierarchy); -#endif - -} // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc index b911c80fa63..857aa20da92 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc @@ -27,6 +27,8 @@ #include "spreadsheet_draw.hh" +#define CELL_RIGHT_PADDING (2.0f * UI_DPI_FAC) + namespace blender::ed::spreadsheet { SpreadsheetDrawer::SpreadsheetDrawer() @@ -159,7 +161,7 @@ static void draw_left_column_content(const int scroll_offset_y, params.xmin = 0; params.ymin = region->winy - drawer.top_row_height - (row_index + 1) * drawer.row_height - scroll_offset_y; - params.width = drawer.left_column_width; + params.width = drawer.left_column_width - CELL_RIGHT_PADDING; params.height = drawer.row_height; drawer.draw_left_column_cell(row_index, params); } @@ -194,7 +196,7 @@ static void draw_top_row_content(const bContext *C, params.block = first_row_block; params.xmin = left_x; params.ymin = region->winy - drawer.top_row_height; - params.width = column_width; + params.width = column_width - CELL_RIGHT_PADDING; params.height = drawer.top_row_height; drawer.draw_top_row_cell(column_index, params); @@ -242,7 +244,7 @@ static void draw_cell_contents(const bContext *C, params.xmin = left_x; params.ymin = region->winy - drawer.top_row_height - (row_index + 1) * drawer.row_height - scroll_offset_y; - params.width = column_width; + params.width = column_width - CELL_RIGHT_PADDING; params.height = drawer.row_height; drawer.draw_content_cell(row_index, column_index, params); } diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh index 8b050c2e69b..e62835d5792 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh @@ -37,6 +37,7 @@ struct SpaceSpreadsheet_Runtime { }; struct bContext; +struct ARegionType; void spreadsheet_operatortypes(void); void spreadsheet_update_context_path(const bContext *C); @@ -45,6 +46,8 @@ Object *spreadsheet_get_object_eval(const SpaceSpreadsheet *sspreadsheet, namespace blender::ed::spreadsheet { GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspreadsheet, - Object *object_eval, - const GeometryComponentType used_component_type); -} + Object *object_eval); + +void spreadsheet_data_set_region_panels_register(ARegionType ®ion_type); + +} // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc b/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc new file mode 100644 index 00000000000..8f923ea4a63 --- /dev/null +++ b/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc @@ -0,0 +1,37 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "BKE_screen.h" + +#include "BLT_translation.h" + +#include "spreadsheet_dataset_draw.hh" +#include "spreadsheet_intern.hh" + +namespace blender::ed::spreadsheet { + +void spreadsheet_data_set_region_panels_register(ARegionType ®ion_type) +{ + PanelType *panel_type = (PanelType *)MEM_callocN(sizeof(PanelType), __func__); + strcpy(panel_type->idname, "SPREADSHEET_PT_data_set"); + strcpy(panel_type->label, N_("Data Set")); + strcpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + panel_type->flag = PANEL_TYPE_NO_HEADER; + panel_type->draw = spreadsheet_data_set_panel_draw; + BLI_addtail(®ion_type.paneltypes, panel_type); +} + +} // namespace blender::ed::spreadsheet
\ No newline at end of file diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c index b541b65d676..f8d16e396d4 100644 --- a/source/blender/editors/space_text/text_draw.c +++ b/source/blender/editors/space_text/text_draw.c @@ -70,7 +70,7 @@ static void text_draw_context_init(const SpaceText *st, TextDrawContext *tdc) static void text_font_begin(const TextDrawContext *tdc) { - BLF_size(tdc->font_id, tdc->lheight_px, 72); + BLF_size(tdc->font_id, (float)tdc->lheight_px, 72); } static void text_font_end(const TextDrawContext *UNUSED(tdc)) diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index 458a1be0308..3c0ffa29bbd 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -86,6 +86,30 @@ static void test_line_start(char c, bool *r_last_state) } /** + * This function receives a character and returns its closing pair if it exists. + * \param character: Character to find the closing pair. + * \return The closing pair of the character if it exists. + */ +static char text_closing_character_pair_get(const char character) +{ + + switch (character) { + case '(': + return ')'; + case '[': + return ']'; + case '{': + return '}'; + case '"': + return '"'; + case '\'': + return '\''; + default: + return 0; + } +} + +/** * This function converts the indentation tabs from a buffer to spaces. * \param in_buf: A pointer to a cstring. * \param tab_size: The size, in spaces, of the tab character. @@ -2403,7 +2427,17 @@ static int text_delete_exec(bContext *C, wmOperator *op) } } } - + if (U.text_flag & USER_TEXT_EDIT_AUTO_CLOSE) { + const char *curr = text->curl->line + text->curc; + if (*curr != '\0') { + const char *prev = BLI_str_find_prev_char_utf8(curr, text->curl->line); + if ((curr != prev) && /* When back-spacing from the start of the line. */ + (*curr == text_closing_character_pair_get(*prev))) { + txt_move_right(text, false); + txt_backspace_char(text); + } + } + } txt_backspace_char(text); } else if (type == DEL_NEXT_WORD) { @@ -3443,6 +3477,12 @@ static int text_insert_exec(bContext *C, wmOperator *op) while (str[i]) { code = BLI_str_utf8_as_unicode_step(str, str_len, &i); done |= txt_add_char(text, code); + if (U.text_flag & USER_TEXT_EDIT_AUTO_CLOSE) { + if (text_closing_character_pair_get(code)) { + done |= txt_add_char(text, text_closing_character_pair_get(code)); + txt_move_left(text, false); + } + } } } diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 6b9da431510..48f39f835c5 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -48,58 +48,6 @@ #include "view3d_intern.h" /* bad level include */ -/* OpenGL Circle Drawing - Tables for Optimized Drawing Speed */ -/* 32 values of sin function (still same result!) */ -#define CIRCLE_RESOL 32 - -static const float sinval[CIRCLE_RESOL] = { - 0.00000000, 0.20129852, 0.39435585, 0.57126821, 0.72479278, 0.84864425, 0.93775213, - 0.98846832, 0.99871650, 0.96807711, 0.89780453, 0.79077573, 0.65137248, 0.48530196, - 0.29936312, 0.10116832, -0.10116832, -0.29936312, -0.48530196, -0.65137248, -0.79077573, - -0.89780453, -0.96807711, -0.99871650, -0.98846832, -0.93775213, -0.84864425, -0.72479278, - -0.57126821, -0.39435585, -0.20129852, 0.00000000, -}; - -/* 32 values of cos function (still same result!) */ -static const float cosval[CIRCLE_RESOL] = { - 1.00000000, 0.97952994, 0.91895781, 0.82076344, 0.68896691, 0.52896401, 0.34730525, - 0.15142777, -0.05064916, -0.25065253, -0.44039415, -0.61210598, -0.75875812, -0.87434661, - -0.95413925, -0.99486932, -0.99486932, -0.95413925, -0.87434661, -0.75875812, -0.61210598, - -0.44039415, -0.25065253, -0.05064916, 0.15142777, 0.34730525, 0.52896401, 0.68896691, - 0.82076344, 0.91895781, 0.97952994, 1.00000000, -}; - -static void circball_array_fill(const float verts[CIRCLE_RESOL][3], - const float cent[3], - float rad, - const float tmat[4][4]) -{ - float vx[3], vy[3]; - float *viter = (float *)verts; - - mul_v3_v3fl(vx, tmat[0], rad); - mul_v3_v3fl(vy, tmat[1], rad); - - for (uint a = 0; a < CIRCLE_RESOL; a++, viter += 3) { - viter[0] = cent[0] + sinval[a] * vx[0] + cosval[a] * vy[0]; - viter[1] = cent[1] + sinval[a] * vx[1] + cosval[a] * vy[1]; - viter[2] = cent[2] + sinval[a] * vx[2] + cosval[a] * vy[2]; - } -} - -void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], uint pos) -{ - float verts[CIRCLE_RESOL][3]; - - circball_array_fill(verts, cent, rad, tmat); - - immBegin(GPU_PRIM_LINE_LOOP, CIRCLE_RESOL); - for (int i = 0; i < CIRCLE_RESOL; i++) { - immVertex3fv(pos, verts[i]); - } - immEnd(); -} - #ifdef VIEW3D_CAMERA_BORDER_HACK uchar view3d_camera_border_hack_col[3]; bool view3d_camera_border_hack_test = false; diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 3a9c9e27ef0..e54ef3c931a 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -784,7 +784,7 @@ static void view3d_collection_drop_copy(wmDrag *drag, wmDropBox *drop) { ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, ID_GR); - RNA_string_set(drop->ptr, "name", id->name + 2); + RNA_int_set(drop->ptr, "session_uuid", (int)id->session_uuid); } static void view3d_id_drop_copy(wmDrag *drag, wmDropBox *drop) diff --git a/source/blender/editors/space_view3d/view3d_cursor_snap.c b/source/blender/editors/space_view3d/view3d_cursor_snap.c index fbdab71ec1d..ac80a70011a 100644 --- a/source/blender/editors/space_view3d/view3d_cursor_snap.c +++ b/source/blender/editors/space_view3d/view3d_cursor_snap.c @@ -95,9 +95,7 @@ typedef struct SnapCursorDataIntern { static SnapCursorDataIntern g_data_intern = { .state_default = {.prevpoint = NULL, - .snap_elem_force = (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | - SCE_SNAP_MODE_FACE | SCE_SNAP_MODE_EDGE_PERPENDICULAR | - SCE_SNAP_MODE_EDGE_MIDPOINT), + .snap_elem_force = SCE_SNAP_MODE_GEOM, .plane_axis = 2, .color_point = {255, 255, 255, 255}, .color_line = {255, 255, 255, 128}, @@ -692,7 +690,7 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state, const int orient_index = BKE_scene_orientation_get_index(scene, SCE_ORIENT_DEFAULT); const int pivot_point = scene->toolsettings->transform_pivot_point; ED_transform_calc_orientation_from_type_ex( - scene, view_layer, v3d, region->regiondata, ob, ob, orient_index, pivot_point, omat); + scene, view_layer, v3d, rv3d, ob, NULL, orient_index, pivot_point, omat); if (state->use_plane_axis_auto) { mat3_align_axis_to_v3(omat, state->plane_axis, rv3d->viewinv[2]); @@ -759,7 +757,7 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state, /** \name Callbacks * \{ */ -static bool v3d_cursor_snap_pool_fn(bContext *C) +static bool v3d_cursor_snap_poll_fn(bContext *C) { if (G.moving) { return false; @@ -770,7 +768,22 @@ static bool v3d_cursor_snap_pool_fn(bContext *C) return false; } - ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW); + ARegion *region = CTX_wm_region(C); + if (region->regiontype != RGN_TYPE_WINDOW) { + if (!region->overlap) { + return false; + } + /* Sometimes the cursor may be on an invisible part of an overlapping region. */ + const wmWindowManager *wm = CTX_wm_manager(C); + const wmEvent *event = wm->winactive->eventstate; + if (ED_region_overlap_isect_xy(region, event->xy)) { + return false; + } + /* Find the visible region under the cursor. + * TODO(Germano): Shouldn't this be the region in context? */ + region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW); + } + RegionView3D *rv3d = region->regiondata; if (rv3d->rflag & RV3D_NAVIGATING) { /* Don't draw the cursor while navigating. It can be distracting. */ @@ -883,7 +896,7 @@ static void v3d_cursor_snap_activate(void) } struct wmPaintCursor *pc = WM_paint_cursor_activate( - SPACE_VIEW3D, RGN_TYPE_WINDOW, v3d_cursor_snap_pool_fn, v3d_cursor_snap_draw_fn, NULL); + SPACE_VIEW3D, RGN_TYPE_WINDOW, v3d_cursor_snap_poll_fn, v3d_cursor_snap_draw_fn, NULL); data_intern->handle = pc; } } diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index b85b424405e..34baf68ccdd 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -3059,6 +3059,23 @@ static int viewselected_exec(bContext *C, wmOperator *op) if ((gps->flag & GP_STROKE_SELECT) && (gps->flag & GP_STROKE_3DSPACE)) { ok |= BKE_gpencil_stroke_minmax(gps, true, min, max); } + if (gps->editcurve != NULL) { + for (int i = 0; i < gps->editcurve->tot_curve_points; i++) { + BezTriple *bezt = &gps->editcurve->curve_points[i].bezt; + if ((bezt->f1 & SELECT)) { + minmax_v3v3_v3(min, max, bezt->vec[0]); + ok = true; + } + if ((bezt->f2 & SELECT)) { + minmax_v3v3_v3(min, max, bezt->vec[1]); + ok = true; + } + if ((bezt->f3 & SELECT)) { + minmax_v3v3_v3(min, max, bezt->vec[2]); + ok = true; + } + } + } } CTX_DATA_END; diff --git a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c index 07c3b6bd1d8..513fdbecc74 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c @@ -29,9 +29,11 @@ #include "BLI_math.h" #include "DNA_mesh_types.h" +#include "DNA_view3d_types.h" #include "BKE_context.h" #include "BKE_editmesh.h" +#include "BKE_global.h" #include "BKE_layer.h" #include "DEG_depsgraph.h" @@ -51,6 +53,39 @@ #include "ED_view3d.h" /* -------------------------------------------------------------------- */ +/** \name Shared Internal API + * \{ */ + +/** + * Check if drawing should be performed, clear the pre-selection in the case it's disabled. + * Without this, the gizmo would be visible while transforming. See T92954. + * + * NOTE(@campbellbarton): This is a workaround for the gizmo system, since typically poll + * would be used for this purpose. The problem with using poll is once the gizmo is visible again + * is there is a visible flicker showing the previous location before cursor motion causes the + * pre selection to be updated. While this is only a glitch, it's distracting. + * The gizmo system it's self could support this use case by tracking which gizmos draw and ensure + * gizmos always run #wmGizmoType.test_select before drawing, however pre-selection is already + * outside the scope of what gizmos are meant to be used for, so keep this workaround localized + * to this gizmo type unless this seems worth supporting for more typical use-cases. + * + * Longer term it may be better to use #wmPaintCursor instead of gizmos (as snapping preview does). + */ +static bool gizmo_preselect_poll_for_draw(const bContext *C, wmGizmo *gz) +{ + if (G.moving == false) { + RegionView3D *rv3d = CTX_wm_region_view3d(C); + if (!(rv3d && (rv3d->rflag & RV3D_NAVIGATING))) { + return true; + } + } + ED_view3d_gizmo_mesh_preselect_clear(gz); + return false; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Mesh Element (Vert/Edge/Face) Pre-Select Gizmo API * \{ */ @@ -65,8 +100,12 @@ typedef struct MeshElemGizmo3D { struct EditMesh_PreSelElem *psel; } MeshElemGizmo3D; -static void gizmo_preselect_elem_draw(const bContext *UNUSED(C), wmGizmo *gz) +static void gizmo_preselect_elem_draw(const bContext *C, wmGizmo *gz) { + if (!gizmo_preselect_poll_for_draw(C, gz)) { + return; + } + MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz; if (gz_ele->base_index != -1) { Object *ob = gz_ele->bases[gz_ele->base_index]->object; @@ -292,8 +331,12 @@ typedef struct MeshEdgeRingGizmo3D { struct EditMesh_PreSelEdgeRing *psel; } MeshEdgeRingGizmo3D; -static void gizmo_preselect_edgering_draw(const bContext *UNUSED(C), wmGizmo *gz) +static void gizmo_preselect_edgering_draw(const bContext *C, wmGizmo *gz) { + if (!gizmo_preselect_poll_for_draw(C, gz)) { + return; + } + MeshEdgeRingGizmo3D *gz_ring = (MeshEdgeRingGizmo3D *)gz; if (gz_ring->base_index != -1) { Object *ob = gz_ring->bases[gz_ring->base_index]->object; @@ -504,4 +547,33 @@ void ED_view3d_gizmo_mesh_preselect_get_active(bContext *C, } } } + +void ED_view3d_gizmo_mesh_preselect_clear(wmGizmo *gz) +{ + if (STREQ(gz->type->idname, "GIZMO_GT_mesh_preselect_elem_3d")) { + MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz; + gz_ele->base_index = -1; + gz_ele->vert_index = -1; + gz_ele->edge_index = -1; + gz_ele->face_index = -1; + } + else if (STREQ(gz->type->idname, "GIZMO_GT_mesh_preselect_edgering_3d")) { + MeshEdgeRingGizmo3D *gz_ele = (MeshEdgeRingGizmo3D *)gz; + gz_ele->base_index = -1; + gz_ele->edge_index = -1; + } + else { + BLI_assert_unreachable(); + } + + const char *prop_ids[] = {"object_index", "vert_index", "edge_index", "face_index"}; + for (int i = 0; i < ARRAY_SIZE(prop_ids); i++) { + PropertyRNA *prop = RNA_struct_find_property(gz->ptr, prop_ids[i]); + if (prop == NULL) { + continue; + } + RNA_property_int_set(gz->ptr, prop, -1); + } +} + /** \} */ diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c index 34e3b808b50..1082483dcd7 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c @@ -115,8 +115,10 @@ enum { CONSTRAIN_AXIS_Z = 2, }; -/* Constraining modes. - Off / Scene orientation / Global (or Local if Scene orientation is Global) */ +/** + * Constraining modes. + * Off / Scene orientation / Global (or Local if Scene orientation is Global). + */ enum { CONSTRAIN_MODE_OFF = 0, CONSTRAIN_MODE_1 = 1, @@ -163,7 +165,7 @@ typedef struct RulerInfo { typedef struct RulerItem { wmGizmo gz; - /* worldspace coords, middle being optional */ + /** World-space coords, middle being optional. */ float co[3][3]; int flag; @@ -643,7 +645,7 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) GPU_line_width(1.0f); BLF_enable(blf_mono_font, BLF_ROTATION); - BLF_size(blf_mono_font, 14 * U.pixelsize, U.dpi); + BLF_size(blf_mono_font, 14.0f * U.pixelsize, U.dpi); BLF_rotation(blf_mono_font, 0.0f); UI_GetThemeColor3ubv(TH_TEXT, color_text); diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index eb8c043319c..823aa3b6643 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -63,19 +63,19 @@ static int view3d_copybuffer_exec(bContext *C, wmOperator *op) char str[FILE_MAX]; int num_copied = 0; - BKE_copybuffer_begin(bmain); + BKE_copybuffer_copy_begin(bmain); /* context, selection, could be generalized */ CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { if ((ob->id.tag & LIB_TAG_DOIT) == 0) { - BKE_copybuffer_tag_ID(&ob->id); + BKE_copybuffer_copy_tag_ID(&ob->id); num_copied++; } } CTX_DATA_END; BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend"); - BKE_copybuffer_save(bmain, str, op->reports); + BKE_copybuffer_copy_end(bmain, str, op->reports); BKE_reportf(op->reports, RPT_INFO, "Copied %d selected object(s)", num_copied); diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c index cecd1765a17..8c1cab6bf14 100644 --- a/source/blender/editors/space_view3d/view3d_placement.c +++ b/source/blender/editors/space_view3d/view3d_placement.c @@ -45,10 +45,6 @@ #include "view3d_intern.h" -#define SNAP_MODE_GEOM \ - (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | \ - SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT) - static const char *view3d_gzgt_placement_id = "VIEW3D_GGT_placement"; /** @@ -1308,7 +1304,7 @@ static int idp_rna_snap_target_get_fn(struct PointerRNA *UNUSED(ptr), } /* Make sure you keep a consistent #snap_mode. */ - snap_state->snap_elem_force = SNAP_MODE_GEOM; + snap_state->snap_elem_force = SCE_SNAP_MODE_GEOM; return PLACE_SNAP_TO_GEOMETRY; } @@ -1319,7 +1315,7 @@ static void idp_rna_snap_target_set_fn(struct PointerRNA *UNUSED(ptr), short snap_mode = 0; /* #toolsettings->snap_mode. */ const enum ePlace_SnapTo snap_to = value; if (snap_to == PLACE_SNAP_TO_GEOMETRY) { - snap_mode = SNAP_MODE_GEOM; + snap_mode = SCE_SNAP_MODE_GEOM; } V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_state_get(); diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 46a664f10fa..6f0ce6c9326 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -1731,9 +1731,9 @@ void ED_view3d_xr_shading_update(wmWindowManager *wm, const View3D *v3d, const S View3DShading *xr_shading = &wm->xr.session_settings.shading; /* Flags that shouldn't be overridden by the 3D View shading. */ int flag_copy = 0; - if (v3d->shading.type != - OB_SOLID) { /* Don't set V3D_SHADING_WORLD_ORIENTATION for solid shading since it results - in distorted lighting when the view matrix has a scale factor. */ + if (v3d->shading.type != OB_SOLID) { + /* Don't set V3D_SHADING_WORLD_ORIENTATION for solid shading since it results in distorted + * lighting when the view matrix has a scale factor. */ flag_copy |= V3D_SHADING_WORLD_ORIENTATION; } diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index f212c7f5747..ae4c3f02c46 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -601,8 +601,15 @@ static bool transform_modal_item_poll(const wmOperator *op, int value) if ((t->tsnap.mode & ~(SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) == 0) { return false; } - if (!validSnap(t)) { - return false; + if (value == TFM_MODAL_ADD_SNAP) { + if (!validSnap(t)) { + return false; + } + } + else { + if (!t->tsnap.selectedPoint) { + return false; + } } break; } diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 3076b3e207f..d78cd13f8b8 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -317,9 +317,9 @@ typedef struct TransSnap { /* Snapped Element Type (currently for objects only). */ char snapElem; /** snapping from this point (in global-space). */ - float snapPoint[3]; - /** to this point (in global-space). */ float snapTarget[3]; + /** to this point (in global-space). */ + float snapPoint[3]; float snapTargetGrid[3]; float snapNormal[3]; char snapNodeBorder; @@ -621,6 +621,12 @@ typedef struct TransInfo { O_SET, } orient_curr; + /** + * All values from `TransInfo.orient[].type` converted into a flag + * to allow quickly checking which orientation types are used. + */ + int orient_type_mask; + short prop_mode; /** Value taken as input, either through mouse coordinates or entered as a parameter. */ @@ -713,7 +719,8 @@ struct wmKeyMap *transform_modal_keymap(struct wmKeyConfig *keyconf); /* transform_gizmo.c */ #define GIZMO_AXIS_LINE_WIDTH 2.0f -bool gimbal_axis(struct Object *ob, float gmat[3][3]); +bool gimbal_axis_pose(struct Object *ob, const struct bPoseChannel *pchan, float gmat[3][3]); +bool gimbal_axis_object(struct Object *ob, float gmat[3][3]); void drawDial3d(const TransInfo *t); /** \} */ diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index 23ba335476c..a24491119c6 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -384,6 +384,29 @@ static void planeProjection(const TransInfo *t, const float in[3], float out[3]) add_v3_v3v3(out, in, vec); } +static short transform_orientation_or_default(const TransInfo *t) +{ + short orientation = t->orient[t->orient_curr].type; + if (orientation == V3D_ORIENT_CUSTOM_MATRIX) { + /* Use the real value of the "orient_type". */ + orientation = t->orient[O_DEFAULT].type; + } + return orientation; +} + +static const float (*transform_object_axismtx_get(const TransInfo *t, + const TransDataContainer *UNUSED(tc), + const TransData *td))[3] +{ + if (transform_orientation_or_default(t) == V3D_ORIENT_GIMBAL) { + BLI_assert(t->orient_type_mask & (1 << V3D_ORIENT_GIMBAL)); + if (t->options & (CTX_POSE_BONE | CTX_OBJECT)) { + return td->ext->axismtx_gimbal; + } + } + return td->axismtx; +} + /** * Generic callback for constant spatial constraints applied to linear motion * @@ -489,7 +512,8 @@ static void applyObjectConstraintVec(const TransInfo *t, copy_v3_v3(out, in); if (t->con.mode & CON_APPLY) { mul_m3_v3(t->spacemtx_inv, out); - mul_m3_v3(td->axismtx, out); + const float(*axismtx)[3] = transform_object_axismtx_get(t, tc, td); + mul_m3_v3(axismtx, out); if (t->flag & T_EDIT) { mul_m3_v3(tc->mat3_unit, out); } @@ -535,7 +559,8 @@ static void applyObjectConstraintSize(const TransInfo *t, float tmat[3][3]; float imat[3][3]; - invert_m3_m3(imat, td->axismtx); + const float(*axismtx)[3] = transform_object_axismtx_get(t, tc, td); + invert_m3_m3(imat, axismtx); if (!(t->con.mode & CON_AXIS0)) { r_smat[0][0] = 1.0f; @@ -551,7 +576,7 @@ static void applyObjectConstraintSize(const TransInfo *t, if (t->flag & T_EDIT) { mul_m3_m3m3(r_smat, tc->mat3_unit, r_smat); } - mul_m3_m3m3(r_smat, td->axismtx, tmat); + mul_m3_m3m3(r_smat, axismtx, tmat); } } @@ -647,7 +672,7 @@ static void applyObjectConstraintRot(const TransInfo *t, axismtx = tmp_axismtx; } else { - axismtx = td->axismtx; + axismtx = transform_object_axismtx_get(t, tc, td); } constraints_rotation_impl(t, axismtx, r_axis, r_angle); @@ -712,17 +737,13 @@ void setLocalConstraint(TransInfo *t, int mode, const char text[]) void setUserConstraint(TransInfo *t, int mode, const char ftext[]) { char text[256]; - short orientation = t->orient[t->orient_curr].type; - if (orientation == V3D_ORIENT_CUSTOM_MATRIX) { - /* Use the real value of the "orient_type". */ - orientation = t->orient[0].type; - } - + const short orientation = transform_orientation_or_default(t); const char *spacename = transform_orientations_spacename_get(t, orientation); BLI_snprintf(text, sizeof(text), ftext, spacename); switch (orientation) { case V3D_ORIENT_LOCAL: + case V3D_ORIENT_GIMBAL: setLocalConstraint(t, mode, text); break; case V3D_ORIENT_NORMAL: @@ -734,7 +755,6 @@ void setUserConstraint(TransInfo *t, int mode, const char ftext[]) case V3D_ORIENT_GLOBAL: case V3D_ORIENT_VIEW: case V3D_ORIENT_CURSOR: - case V3D_ORIENT_GIMBAL: case V3D_ORIENT_CUSTOM_MATRIX: case V3D_ORIENT_CUSTOM: default: { @@ -905,7 +925,7 @@ static void drawObjectConstraint(TransInfo *t) TransData *td = tc->data; for (int i = 0; i < tc->data_len; i++, td++) { float co[3]; - float(*axismtx)[3]; + const float(*axismtx)[3]; if (t->flag & T_PROP_EDIT) { /* we're sorted, so skip the rest */ @@ -937,13 +957,14 @@ static void drawObjectConstraint(TransInfo *t) mul_m3_m3m3(tmp_axismtx, tc->mat3_unit, td->axismtx); axismtx = tmp_axismtx; } - else if (t->options & CTX_POSE_BONE) { - mul_v3_m4v3(co, tc->mat, td->center); - axismtx = td->axismtx; - } else { - copy_v3_v3(co, td->center); - axismtx = td->axismtx; + if (t->options & CTX_POSE_BONE) { + mul_v3_m4v3(co, tc->mat, td->center); + } + else { + copy_v3_v3(co, td->center); + } + axismtx = transform_object_axismtx_get(t, tc, td); } if (t->con.mode & CON_AXIS0) { diff --git a/source/blender/editors/transform/transform_convert_action.c b/source/blender/editors/transform/transform_convert_action.c index a6658ae00a3..24d84bc2de8 100644 --- a/source/blender/editors/transform/transform_convert_action.c +++ b/source/blender/editors/transform/transform_convert_action.c @@ -159,8 +159,11 @@ static void TimeToTransData( copy_v2_v2(td2d->ih2, td2d->h2); /* Setup #TransData. */ - td->loc = time; /* Usually #td2d->loc is used here. But this is for when the original location is - not float[3]. */ + + /* Usually #td2d->loc is used here. + * But this is for when the original location is not float[3]. */ + td->loc = time; + copy_v3_v3(td->iloc, td->loc); td->val = time; td->ival = *(time); diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c index 1bbbbc6294e..88790e9645c 100644 --- a/source/blender/editors/transform/transform_convert_armature.c +++ b/source/blender/editors/transform/transform_convert_armature.c @@ -662,6 +662,12 @@ static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, Tr mul_m3_m3m3(td->axismtx, omat, pmat); normalize_m3(td->axismtx); + if (t->orient_type_mask & (1 << V3D_ORIENT_GIMBAL)) { + if (!gimbal_axis_pose(ob, pchan, td->ext->axismtx_gimbal)) { + copy_m3_m3(td->ext->axismtx_gimbal, td->axismtx); + } + } + if (t->mode == TFM_BONE_ENVELOPE_DIST) { td->loc = NULL; td->val = &bone->dist; diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c index 7e4e0892420..4a8ebf3fc6e 100644 --- a/source/blender/editors/transform/transform_convert_object.c +++ b/source/blender/editors/transform/transform_convert_object.c @@ -181,6 +181,11 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) /* axismtx has the real orientation */ transform_orientations_create_from_axis(td->axismtx, UNPACK3(ob->obmat)); + if (t->orient_type_mask & (1 << V3D_ORIENT_GIMBAL)) { + if (!gimbal_axis_object(ob, td->ext->axismtx_gimbal)) { + copy_m3_m3(td->ext->axismtx_gimbal, td->axismtx); + } + } td->con = ob->constraints.first; diff --git a/source/blender/editors/transform/transform_data.h b/source/blender/editors/transform/transform_data.h index 15e40ec466b..6cfceedb389 100644 --- a/source/blender/editors/transform/transform_data.h +++ b/source/blender/editors/transform/transform_data.h @@ -85,6 +85,8 @@ typedef struct TransDataExtension { float isize[3]; /** Object matrix. */ float obmat[4][4]; + /** Use for #V3D_ORIENT_GIMBAL orientation. */ + float axismtx_gimbal[3][3]; /** Use instead of #TransData.smtx, * It is the same but without the #Bone.bone_mat, see #TD_PBONE_LOCAL_MTX_C. */ float l_smtx[3][3]; diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 8effb82173b..ece6a143251 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -138,6 +138,52 @@ void resetTransRestrictions(TransInfo *t) t->flag &= ~T_ALL_RESTRICTIONS; } +static void *t_view_get(TransInfo *t) +{ + if (t->spacetype == SPACE_VIEW3D) { + View3D *v3d = t->area->spacedata.first; + return (void *)v3d; + } + if (t->region) { + return (void *)&t->region->v2d; + } + return NULL; +} + +static int t_around_get(TransInfo *t) +{ + if (t->flag & T_OVERRIDE_CENTER) { + /* Avoid initialization of individual origins (#V3D_AROUND_LOCAL_ORIGINS). */ + return V3D_AROUND_CENTER_BOUNDS; + } + + ScrArea *area = t->area; + if (t->spacetype == SPACE_VIEW3D) { + /* Bend always uses the cursor. */ + if (t->mode == TFM_BEND) { + return V3D_AROUND_CURSOR; + } + return t->settings->transform_pivot_point; + } + if (t->spacetype == SPACE_IMAGE) { + SpaceImage *sima = area->spacedata.first; + return sima->around; + } + if (t->spacetype == SPACE_GRAPH) { + SpaceGraph *sipo = area->spacedata.first; + return sipo->around; + } + if (t->spacetype == SPACE_CLIP) { + SpaceClip *sclip = area->spacedata.first; + return sclip->around; + } + if (t->spacetype == SPACE_SEQ && t->region->regiontype == RGN_TYPE_PREVIEW) { + return SEQ_tool_settings_pivot_point_get(t->scene); + } + + return V3D_AROUND_CENTER_BOUNDS; +} + /** * Setup internal data, mouse, vectors * @@ -261,32 +307,13 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } if (t->spacetype == SPACE_VIEW3D) { - View3D *v3d = area->spacedata.first; bScreen *animscreen = ED_screen_animation_playing(CTX_wm_manager(C)); - t->view = v3d; t->animtimer = (animscreen) ? animscreen->animtimer : NULL; if (t->scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) { t->flag |= T_V3D_ALIGN; } - t->around = t->scene->toolsettings->transform_pivot_point; - - /* bend always uses the cursor */ - if (t->mode == TFM_BEND) { - t->around = V3D_AROUND_CURSOR; - } - - /* exceptional case */ - if (t->around == V3D_AROUND_LOCAL_ORIGINS) { - if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) { - const bool use_island = transdata_check_local_islands(t, t->around); - - if ((t->obedit_type != -1) && !use_island) { - t->options |= CTX_NO_PET; - } - } - } if (object_mode & OB_MODE_ALL_PAINT) { Paint *p = BKE_paint_get_active_from_context(C); @@ -313,10 +340,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } else if (t->spacetype == SPACE_IMAGE) { SpaceImage *sima = area->spacedata.first; - /* XXX for now, get View2D from the active region. */ - t->view = ®ion->v2d; - t->around = sima->around; - if (ED_space_image_show_uvedit(sima, OBACT(t->view_layer))) { /* UV transform */ } @@ -331,21 +354,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } /* image not in uv edit, nor in mask mode, can happen for some tools */ } - else if (t->spacetype == SPACE_NODE) { - /* XXX for now, get View2D from the active region. */ - t->view = ®ion->v2d; - t->around = V3D_AROUND_CENTER_BOUNDS; - } - else if (t->spacetype == SPACE_GRAPH) { - SpaceGraph *sipo = area->spacedata.first; - t->view = ®ion->v2d; - t->around = sipo->around; - } else if (t->spacetype == SPACE_CLIP) { SpaceClip *sclip = area->spacedata.first; - t->view = ®ion->v2d; - t->around = sclip->around; - if (ED_space_clip_check_show_trackedit(sclip)) { t->options |= CTX_MOVIECLIP; } @@ -354,20 +364,30 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } } else if (t->spacetype == SPACE_SEQ && region->regiontype == RGN_TYPE_PREVIEW) { - t->view = ®ion->v2d; - t->around = SEQ_tool_settings_pivot_point_get(t->scene); t->options |= CTX_SEQUENCER_IMAGE; } - else { - if (region) { - /* XXX: For now, get View2D from the active region. */ - t->view = ®ion->v2d; - /* XXX: For now, the center point is the midpoint of the data. */ - } - else { - t->view = NULL; + + setTransformViewAspect(t, t->aspect); + + if (op && (prop = RNA_struct_find_property(op->ptr, "center_override")) && + RNA_property_is_set(op->ptr, prop)) { + RNA_property_float_get_array(op->ptr, prop, t->center_global); + mul_v3_v3(t->center_global, t->aspect); + t->flag |= T_OVERRIDE_CENTER; + } + + t->view = t_view_get(t); + t->around = t_around_get(t); + + /* Exceptional case. */ + if (t->around == V3D_AROUND_LOCAL_ORIGINS) { + if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) { + const bool use_island = transdata_check_local_islands(t, t->around); + + if ((t->obedit_type != -1) && !use_island) { + t->options |= CTX_NO_PET; + } } - t->around = V3D_AROUND_CENTER_BOUNDS; } bool t_values_set_is_array = false; @@ -512,6 +532,15 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } } + t->orient_type_mask = 0; + for (int i = 0; i < 3; i++) { + const int type = t->orient[i].type; + if (type < V3D_ORIENT_CUSTOM_MATRIX) { + BLI_assert(type < 32); + t->orient_type_mask |= (1 << type); + } + } + transform_orientations_current_set(t, (t->con.mode & CON_APPLY) ? 2 : 0); } @@ -647,15 +676,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->flag |= T_NO_CURSOR_WRAP; } - setTransformViewAspect(t, t->aspect); - - if (op && (prop = RNA_struct_find_property(op->ptr, "center_override")) && - RNA_property_is_set(op->ptr, prop)) { - RNA_property_float_get_array(op->ptr, prop, t->center_global); - mul_v3_v3(t->center_global, t->aspect); - t->flag |= T_OVERRIDE_CENTER; - } - setTransformViewMatrices(t); initNumInput(&t->num); } diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c index e79fdc4890a..6a2353d403f 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.c +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -515,7 +515,7 @@ static void protectflag_to_drawflags_pchan(RegionView3D *rv3d, { /* Protect-flags apply to local space in pose mode, so only let them influence axis * visibility if we show the global orientation, otherwise it's confusing. */ - if (orientation_index == V3D_ORIENT_LOCAL) { + if (ELEM(orientation_index, V3D_ORIENT_LOCAL, V3D_ORIENT_GIMBAL)) { protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag); } } @@ -564,72 +564,63 @@ static bool test_rotmode_euler(short rotmode) return (ELEM(rotmode, ROT_MODE_AXISANGLE, ROT_MODE_QUAT)) ? 0 : 1; } -/** - * Return false when no gimbal for selection. - */ -bool gimbal_axis(Object *ob, float gmat[3][3]) +bool gimbal_axis_pose(Object *ob, const bPoseChannel *pchan, float gmat[3][3]) { - if (ob->mode & OB_MODE_POSE) { - bPoseChannel *pchan = BKE_pose_channel_active(ob); - - if (pchan) { - float mat[3][3], tmat[3][3], obmat[3][3]; - if (test_rotmode_euler(pchan->rotmode)) { - eulO_to_gimbal_axis(mat, pchan->eul, pchan->rotmode); - } - else if (pchan->rotmode == ROT_MODE_AXISANGLE) { - axis_angle_to_gimbal_axis(mat, pchan->rotAxis, pchan->rotAngle); - } - else { /* quat */ - return 0; - } - - /* apply bone transformation */ - mul_m3_m3m3(tmat, pchan->bone->bone_mat, mat); + float mat[3][3], tmat[3][3], obmat[3][3]; + if (test_rotmode_euler(pchan->rotmode)) { + eulO_to_gimbal_axis(mat, pchan->eul, pchan->rotmode); + } + else if (pchan->rotmode == ROT_MODE_AXISANGLE) { + axis_angle_to_gimbal_axis(mat, pchan->rotAxis, pchan->rotAngle); + } + else { /* quat */ + return 0; + } - if (pchan->parent) { - float parent_mat[3][3]; + /* apply bone transformation */ + mul_m3_m3m3(tmat, pchan->bone->bone_mat, mat); - copy_m3_m4(parent_mat, - (pchan->bone->flag & BONE_HINGE) ? pchan->parent->bone->arm_mat : - pchan->parent->pose_mat); - mul_m3_m3m3(mat, parent_mat, tmat); + if (pchan->parent) { + float parent_mat[3][3]; - /* needed if object transformation isn't identity */ - copy_m3_m4(obmat, ob->obmat); - mul_m3_m3m3(gmat, obmat, mat); - } - else { - /* needed if object transformation isn't identity */ - copy_m3_m4(obmat, ob->obmat); - mul_m3_m3m3(gmat, obmat, tmat); - } + copy_m3_m4(parent_mat, + (pchan->bone->flag & BONE_HINGE) ? pchan->parent->bone->arm_mat : + pchan->parent->pose_mat); + mul_m3_m3m3(mat, parent_mat, tmat); - normalize_m3(gmat); - return 1; - } + /* needed if object transformation isn't identity */ + copy_m3_m4(obmat, ob->obmat); + mul_m3_m3m3(gmat, obmat, mat); } else { - if (test_rotmode_euler(ob->rotmode)) { - eulO_to_gimbal_axis(gmat, ob->rot, ob->rotmode); - } - else if (ob->rotmode == ROT_MODE_AXISANGLE) { - axis_angle_to_gimbal_axis(gmat, ob->rotAxis, ob->rotAngle); - } - else { /* quat */ - return 0; - } + /* needed if object transformation isn't identity */ + copy_m3_m4(obmat, ob->obmat); + mul_m3_m3m3(gmat, obmat, tmat); + } - if (ob->parent) { - float parent_mat[3][3]; - copy_m3_m4(parent_mat, ob->parent->obmat); - normalize_m3(parent_mat); - mul_m3_m3m3(gmat, parent_mat, gmat); - } - return 1; + normalize_m3(gmat); + return true; +} + +bool gimbal_axis_object(Object *ob, float gmat[3][3]) +{ + if (test_rotmode_euler(ob->rotmode)) { + eulO_to_gimbal_axis(gmat, ob->rot, ob->rotmode); + } + else if (ob->rotmode == ROT_MODE_AXISANGLE) { + axis_angle_to_gimbal_axis(gmat, ob->rotAxis, ob->rotAngle); + } + else { /* quat */ + return 0; } - return 0; + if (ob->parent) { + float parent_mat[3][3]; + copy_m3_m4(parent_mat, ob->parent->obmat); + normalize_m3(parent_mat); + mul_m3_m3m3(gmat, parent_mat, gmat); + } + return 1; } /* centroid, boundbox, of selection */ @@ -1071,9 +1062,13 @@ int ED_transform_calc_gizmo_stats(const bContext *C, } } - /* Protect-flags apply to world space in object mode, so only let them influence axis - * visibility if we show the global orientation, otherwise it's confusing. */ if (orient_index == V3D_ORIENT_GLOBAL) { + /* Protect-flags apply to world space in object mode, + * so only let them influence axis visibility if we show the global orientation, + * otherwise it's confusing. */ + protectflag_to_drawflags(base->object->protectflag & OB_LOCK_LOC, &rv3d->twdrawflag); + } + else if (ELEM(orient_index, V3D_ORIENT_LOCAL, V3D_ORIENT_GIMBAL)) { protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag); } totsel++; diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index a1ed66c96a3..61bbe722d71 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -524,8 +524,19 @@ short ED_transform_calc_orientation_from_type_ex(const Scene *scene, { switch (orientation_index) { case V3D_ORIENT_GIMBAL: { - if (ob && gimbal_axis(ob, r_mat)) { - break; + + if (ob) { + if (ob->mode & OB_MODE_POSE) { + const bPoseChannel *pchan = BKE_pose_channel_active(ob); + if (pchan && gimbal_axis_pose(ob, pchan, r_mat)) { + break; + } + } + else { + if (gimbal_axis_object(ob, r_mat)) { + break; + } + } } /* If not gimbal, fall through to normal. */ ATTR_FALLTHROUGH; diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 7f27d5fb180..71f26ef0594 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -200,7 +200,7 @@ void drawSnapping(const struct bContext *C, TransInfo *t) if (t->spacetype == SPACE_VIEW3D) { bool draw_target = (t->tsnap.status & TARGET_INIT) && - (t->scene->toolsettings->snap_mode & SCE_SNAP_MODE_EDGE_PERPENDICULAR); + (t->tsnap.mode & SCE_SNAP_MODE_EDGE_PERPENDICULAR); if (draw_target || validSnap(t)) { const float *loc_cur = NULL; @@ -483,7 +483,7 @@ void applySnapping(TransInfo *t, float *vec) } if (t->tsnap.project && t->tsnap.mode == SCE_SNAP_MODE_FACE) { - /* The snap has already been resolved for each transdata. */ + /* A similar snap will be applied to each transdata in `applyProject`. */ return; } @@ -574,70 +574,61 @@ static bool bm_face_is_snap_target(BMFace *f, void *UNUSED(user_data)) return true; } -static void initSnappingMode(TransInfo *t) +static short snap_mode_from_scene(TransInfo *t) { ToolSettings *ts = t->settings; - /* All obedit types will match. */ - const int obedit_type = t->obedit_type; - ViewLayer *view_layer = t->view_layer; - Base *base_act = view_layer->basact; + short r_snap_mode = SCE_SNAP_MODE_INCREMENT; if (t->spacetype == SPACE_NODE) { - /* force project off when not supported */ - t->tsnap.project = 0; - - t->tsnap.mode = ts->snap_node_mode; + r_snap_mode = ts->snap_node_mode; } else if (t->spacetype == SPACE_IMAGE) { - /* force project off when not supported */ - t->tsnap.project = 0; - - t->tsnap.mode = ts->snap_uv_mode; - if ((t->tsnap.mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_uv_flag & SCE_SNAP_ABS_GRID) && + r_snap_mode = ts->snap_uv_mode; + if ((r_snap_mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_uv_flag & SCE_SNAP_ABS_GRID) && (t->mode == TFM_TRANSLATION)) { - t->tsnap.mode &= ~SCE_SNAP_MODE_INCREMENT; - t->tsnap.mode |= SCE_SNAP_MODE_GRID; + r_snap_mode &= ~SCE_SNAP_MODE_INCREMENT; + r_snap_mode |= SCE_SNAP_MODE_GRID; } } else if (t->spacetype == SPACE_SEQ) { - t->tsnap.mode = SEQ_tool_settings_snap_mode_get(t->scene); + r_snap_mode = SEQ_tool_settings_snap_mode_get(t->scene); } else if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE) && !(t->options & CTX_CAMERA)) { - /* force project off when not supported */ - if ((ts->snap_mode & SCE_SNAP_MODE_FACE) == 0) { - t->tsnap.project = 0; - } - - t->tsnap.mode = ts->snap_mode; - if ((t->tsnap.mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_flag & SCE_SNAP_ABS_GRID) && - (t->mode == TFM_TRANSLATION)) { - /* Special case in which snap to increments is transformed to snap to grid. */ - t->tsnap.mode &= ~SCE_SNAP_MODE_INCREMENT; - t->tsnap.mode |= SCE_SNAP_MODE_GRID; + /* All obedit types will match. */ + const int obedit_type = t->obedit_type; + if ((t->options & (CTX_GPENCIL_STROKES | CTX_CURSOR | CTX_OBMODE_XFORM_OBDATA)) || + ELEM(obedit_type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL, -1)) { + r_snap_mode = ts->snap_mode; + if ((r_snap_mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_flag & SCE_SNAP_ABS_GRID) && + (t->mode == TFM_TRANSLATION)) { + /* Special case in which snap to increments is transformed to snap to grid. */ + r_snap_mode &= ~SCE_SNAP_MODE_INCREMENT; + r_snap_mode |= SCE_SNAP_MODE_GRID; + } } } else if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA)) { /* No incremental snapping. */ - t->tsnap.mode = 0; - } - else { - /* Fallback. */ - t->tsnap.mode = SCE_SNAP_MODE_INCREMENT; + r_snap_mode = 0; } - if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE) && !(t->options & CTX_CAMERA)) { - /* Only 3D view or UV. */ - /* Not with camera selected in camera view. */ + return r_snap_mode; +} - setSnappingCallback(t); +static short snap_select_type_get(TransInfo *t) +{ + short r_snap_select = SNAP_ALL; + ViewLayer *view_layer = t->view_layer; + Base *base_act = view_layer->basact; + if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE) && !(t->options & CTX_CAMERA)) { + const int obedit_type = t->obedit_type; if (t->options & (CTX_GPENCIL_STROKES | CTX_CURSOR | CTX_OBMODE_XFORM_OBDATA)) { /* In "Edit Strokes" mode, * snap tool can perform snap to selected or active objects (see T49632) * TODO: perform self snap in gpencil_strokes. * * When we're moving the origins, allow snapping onto our own geometry (see T69132). */ - t->tsnap.modeSelect = SNAP_ALL; } else if ((obedit_type != -1) && ELEM(obedit_type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) { @@ -646,29 +637,44 @@ static void initSnappingMode(TransInfo *t) if ((obedit_type == OB_MESH) && (t->flag & T_PROP_EDIT)) { /* Exclude editmesh if using proportional edit */ - t->tsnap.modeSelect = SNAP_NOT_ACTIVE; + r_snap_select = SNAP_NOT_ACTIVE; } - else { - t->tsnap.modeSelect = t->tsnap.snap_self ? SNAP_ALL : SNAP_NOT_ACTIVE; + else if (!t->tsnap.snap_self) { + r_snap_select = SNAP_NOT_ACTIVE; } } else if ((obedit_type == -1) && base_act && base_act->object && (base_act->object->mode & OB_MODE_PARTICLE_EDIT)) { /* Particles edit mode. */ - t->tsnap.modeSelect = SNAP_ALL; } else if (obedit_type == -1) { /* Object mode */ - t->tsnap.modeSelect = SNAP_NOT_SELECTED; - } - else { - /* Increment if snap is not possible */ - t->tsnap.mode = SCE_SNAP_MODE_INCREMENT; + r_snap_select = SNAP_NOT_SELECTED; } } else if (ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) { - setSnappingCallback(t); - t->tsnap.modeSelect = SNAP_NOT_SELECTED; + r_snap_select = SNAP_NOT_SELECTED; + } + + return r_snap_select; +} + +static void initSnappingMode(TransInfo *t) +{ + ToolSettings *ts = t->settings; + t->tsnap.mode = snap_mode_from_scene(t); + t->tsnap.modeSelect = snap_select_type_get(t); + + if ((t->spacetype != SPACE_VIEW3D) || !(ts->snap_mode & SCE_SNAP_MODE_FACE)) { + /* Force project off when not supported. */ + t->tsnap.project = 0; + } + + if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE, SPACE_SEQ)) { + /* Not with camera selected in camera view. */ + if (!(t->options & CTX_CAMERA)) { + setSnappingCallback(t); + } } if (t->spacetype == SPACE_VIEW3D) { @@ -918,8 +924,7 @@ static void snap_calc_view3d_fn(TransInfo *t, float *UNUSED(vec)) mval[0] = t->mval[0]; mval[1] = t->mval[1]; - if (t->tsnap.mode & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | - SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) { + if (t->tsnap.mode & SCE_SNAP_MODE_GEOM) { zero_v3(no); /* objects won't set this */ snap_elem = snapObjectsTransform(t, mval, &dist_px, loc, no); found = snap_elem != 0; @@ -1249,7 +1254,7 @@ short snapObjectsTransform( t->depsgraph, t->region, t->view, - t->settings->snap_mode, + t->tsnap.mode, &(const struct SnapObjectParams){ .snap_select = t->tsnap.modeSelect, .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL, diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 3254d56d795..4b981e763f1 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -125,6 +125,8 @@ struct SnapObjectContext { const ARegion *region; const View3D *v3d; + const struct SnapObjectParams *params; + float mval[2]; float pmat[4][4]; /* perspective matrix */ float win_size[2]; /* win x and y */ @@ -444,8 +446,6 @@ static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx, typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx, Object *ob_eval, float obmat[4][4], - eSnapEditType edit_mode_type, - bool use_backface_culling, bool is_object_active, void *data); @@ -453,20 +453,16 @@ typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx, * Walks through all objects in the scene to create the list of objects to snap. */ static void iter_snap_objects(SnapObjectContext *sctx, - const struct SnapObjectParams *params, IterSnapObjsCallback sob_callback, void *data) { ViewLayer *view_layer = DEG_get_input_view_layer(sctx->runtime.depsgraph); - const eSnapSelect snap_select = params->snap_select; - const eSnapEditType edit_mode_type = params->edit_mode_type; - const bool use_backface_culling = params->use_backface_culling; + const eSnapSelect snap_select = sctx->runtime.params->snap_select; Base *base_act = view_layer->basact; if (snap_select == SNAP_ONLY_ACTIVE) { Object *obj_eval = DEG_get_evaluated_object(sctx->runtime.depsgraph, base_act->object); - sob_callback( - sctx, obj_eval, obj_eval->obmat, edit_mode_type, use_backface_culling, true, data); + sob_callback(sctx, obj_eval, obj_eval->obmat, true, data); return; } @@ -475,7 +471,7 @@ static void iter_snap_objects(SnapObjectContext *sctx, continue; } - if (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE) { + if ((snap_select == SNAP_ALL) || (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE)) { /* pass */ } else if (base->flag_legacy & BA_SNAP_FIX_DEPS_FIASCO) { @@ -483,13 +479,13 @@ static void iter_snap_objects(SnapObjectContext *sctx, } const bool is_object_active = (base == base_act); - if (snap_select == SNAP_NOT_SELECTED) { - if ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL)) { + if (snap_select == SNAP_NOT_ACTIVE) { + if (is_object_active) { continue; } } - else if (snap_select == SNAP_NOT_ACTIVE) { - if (is_object_active) { + else if (snap_select == SNAP_NOT_SELECTED) { + if ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL)) { continue; } } @@ -504,24 +500,12 @@ static void iter_snap_objects(SnapObjectContext *sctx, ListBase *lb = object_duplilist(sctx->runtime.depsgraph, sctx->scene, obj_eval); for (DupliObject *dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) { BLI_assert(DEG_is_evaluated_object(dupli_ob->ob)); - sob_callback(sctx, - dupli_ob->ob, - dupli_ob->mat, - edit_mode_type, - use_backface_culling, - is_object_active, - data); + sob_callback(sctx, dupli_ob->ob, dupli_ob->mat, is_object_active, data); } free_object_duplilist(lb); } - sob_callback(sctx, - obj_eval, - obj_eval->obmat, - edit_mode_type, - use_backface_culling, - is_object_active, - data); + sob_callback(sctx, obj_eval, obj_eval->obmat, is_object_active, data); } } @@ -597,15 +581,15 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH struct RayCastAll_Data *data = userdata; data->raycast_callback(data->bvhdata, index, ray, hit); if (hit->index != -1) { - /* get all values in worldspace */ + /* Get all values in world-space. */ float location[3], normal[3]; float depth; - /* worldspace location */ + /* World-space location. */ mul_v3_m4v3(location, (float(*)[4])data->obmat, hit->co); depth = (hit->dist + data->len_diff) / data->local_scale; - /* worldspace normal */ + /* World-space normal. */ copy_v3_v3(normal, hit->no); mul_m3_v3((float(*)[3])data->timat, normal); normalize_v3(normal); @@ -688,7 +672,6 @@ static bool raycastMesh(SnapObjectContext *sctx, const float obmat[4][4], const uint ob_index, bool use_hide, - bool use_backface_culling, /* read/write args */ float *ray_depth, /* return args */ @@ -790,8 +773,9 @@ static bool raycastMesh(SnapObjectContext *sctx, ray_normal_local, 0.0f, &hit, - use_backface_culling ? mesh_looptri_raycast_backface_culling_cb : - treedata->raycast_callback, + sctx->runtime.params->use_backface_culling ? + mesh_looptri_raycast_backface_culling_cb : + treedata->raycast_callback, treedata) != -1) { hit.dist += len_diff; hit.dist /= local_scale; @@ -799,7 +783,7 @@ static bool raycastMesh(SnapObjectContext *sctx, *ray_depth = hit.dist; copy_v3_v3(r_loc, hit.co); - /* back to worldspace */ + /* Back to world-space. */ mul_m4_v3(obmat, r_loc); if (r_no) { @@ -827,7 +811,6 @@ static bool raycastEditMesh(SnapObjectContext *sctx, BMEditMesh *em, const float obmat[4][4], const uint ob_index, - bool use_backface_culling, /* read/write args */ float *ray_depth, /* return args */ @@ -960,8 +943,9 @@ static bool raycastEditMesh(SnapObjectContext *sctx, ray_normal_local, 0.0f, &hit, - use_backface_culling ? editmesh_looptri_raycast_backface_culling_cb : - treedata->raycast_callback, + sctx->runtime.params->use_backface_culling ? + editmesh_looptri_raycast_backface_culling_cb : + treedata->raycast_callback, treedata) != -1) { hit.dist += len_diff; hit.dist /= local_scale; @@ -969,7 +953,7 @@ static bool raycastEditMesh(SnapObjectContext *sctx, *ray_depth = hit.dist; copy_v3_v3(r_loc, hit.co); - /* back to worldspace */ + /* Back to world-space. */ mul_m4_v3(obmat, r_loc); if (r_no) { @@ -1014,13 +998,8 @@ struct RaycastObjUserData { * * \note Duplicate args here are documented at #snapObjectsRay */ -static void raycast_obj_fn(SnapObjectContext *sctx, - Object *ob_eval, - float obmat[4][4], - eSnapEditType edit_mode_type, - bool use_backface_culling, - bool is_object_active, - void *data) +static void raycast_obj_fn( + SnapObjectContext *sctx, Object *ob_eval, float obmat[4][4], bool is_object_active, void *data) { struct RaycastObjUserData *dt = data; const uint ob_index = dt->ob_index++; @@ -1039,6 +1018,7 @@ static void raycast_obj_fn(SnapObjectContext *sctx, switch (ob_eval->type) { case OB_MESH: { + const eSnapEditType edit_mode_type = sctx->runtime.params->edit_mode_type; bool use_hide = false; Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide); if (me_eval == NULL) { @@ -1051,7 +1031,6 @@ static void raycast_obj_fn(SnapObjectContext *sctx, em_orig, obmat, ob_index, - use_backface_culling, ray_depth, dt->r_loc, dt->r_no, @@ -1067,7 +1046,6 @@ static void raycast_obj_fn(SnapObjectContext *sctx, obmat, ob_index, use_hide, - use_backface_culling, ray_depth, dt->r_loc, dt->r_no, @@ -1089,7 +1067,6 @@ static void raycast_obj_fn(SnapObjectContext *sctx, obmat, ob_index, false, - use_backface_culling, ray_depth, dt->r_loc, dt->r_no, @@ -1119,7 +1096,6 @@ static void raycast_obj_fn(SnapObjectContext *sctx, * Walks through all objects in the scene to find the `hit` on object surface. * * \param sctx: Snap context to store data. - * \param params: Snapping behavior. * * Read/Write Args * --------------- @@ -1139,9 +1115,6 @@ static void raycast_obj_fn(SnapObjectContext *sctx, * \param r_hit_list: List of #SnapObjectHitDepth (caller must free). */ static bool raycastObjects(SnapObjectContext *sctx, - Depsgraph *depsgraph, - const View3D *v3d, - const struct SnapObjectParams *params, const float ray_start[3], const float ray_dir[3], /* read/write args */ @@ -1156,6 +1129,8 @@ static bool raycastObjects(SnapObjectContext *sctx, float r_obmat[4][4], ListBase *r_hit_list) { + const struct SnapObjectParams *params = sctx->runtime.params; + const View3D *v3d = sctx->runtime.v3d; if (params->use_occlusion_test && v3d && XRAY_FLAG_ENABLED(v3d)) { /* General testing of occlusion geometry is disabled if the snap is not intended for the edit * cage. */ @@ -1164,9 +1139,6 @@ static bool raycastObjects(SnapObjectContext *sctx, } } - sctx->runtime.depsgraph = depsgraph; - sctx->runtime.v3d = v3d; - struct RaycastObjUserData data = { .ray_start = ray_start, .ray_dir = ray_dir, @@ -1182,7 +1154,7 @@ static bool raycastObjects(SnapObjectContext *sctx, .ret = false, }; - iter_snap_objects(sctx, params, raycast_obj_fn, &data); + iter_snap_objects(sctx, raycast_obj_fn, &data); return data.ret; } @@ -1561,7 +1533,6 @@ static void cb_snap_tri_verts(void *userdata, static short snap_mesh_polygon(SnapObjectContext *sctx, Object *ob_eval, const float obmat[4][4], - bool use_backface_culling, /* read/write args */ float *dist_px, /* return args */ @@ -1593,8 +1564,10 @@ static short snap_mesh_polygon(SnapObjectContext *sctx, BLI_assert(sod != NULL); Nearest2dUserData nearest2d; - nearest2d_data_init( - sod, sctx->runtime.view_proj == VIEW_PROJ_PERSP, use_backface_culling, &nearest2d); + nearest2d_data_init(sod, + sctx->runtime.view_proj == VIEW_PROJ_PERSP, + sctx->runtime.params->use_backface_culling, + &nearest2d); if (sod->type == SNAP_MESH) { BVHTreeFromMesh *treedata = &sod->treedata_mesh; @@ -1688,7 +1661,6 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, const float obmat[4][4], float original_dist_px, const float prev_co[3], - bool use_backface_culling, /* read/write args */ float *dist_px, /* return args */ @@ -1706,8 +1678,10 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, BLI_assert(sod != NULL); Nearest2dUserData nearest2d; - nearest2d_data_init( - sod, sctx->runtime.view_proj == VIEW_PROJ_PERSP, use_backface_culling, &nearest2d); + nearest2d_data_init(sod, + sctx->runtime.view_proj == VIEW_PROJ_PERSP, + sctx->runtime.params->use_backface_culling, + &nearest2d); int vindex[2]; nearest2d.get_edge_verts_index(*r_index, nearest2d.userdata, vindex); @@ -1875,74 +1849,38 @@ static short snapArmature(SnapObjectContext *sctx, mul_v4_m4v4(clip_planes_local[i], tobmat, sctx->runtime.clip_plane[i]); } + const eSnapSelect snap_select = sctx->runtime.params->snap_select; bool is_persp = sctx->runtime.view_proj == VIEW_PROJ_PERSP; bArmature *arm = ob_eval->data; if (arm->edbo) { LISTBASE_FOREACH (EditBone *, eBone, arm->edbo) { if (eBone->layer & arm->layer) { - /* skip hidden or moving (selected) bones */ - if ((eBone->flag & (BONE_HIDDEN_A | BONE_ROOTSEL | BONE_TIPSEL)) == 0) { - bool has_vert_snap = false; - - if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) { - has_vert_snap = test_projected_vert_dist(&neasrest_precalc, - clip_planes_local, - sctx->runtime.clip_plane_len, - is_persp, - eBone->head, - &dist_px_sq, - r_loc); - has_vert_snap |= test_projected_vert_dist(&neasrest_precalc, - clip_planes_local, - sctx->runtime.clip_plane_len, - is_persp, - eBone->tail, - &dist_px_sq, - r_loc); - - if (has_vert_snap) { - retval = SCE_SNAP_MODE_VERTEX; - } - } - if (!has_vert_snap && sctx->runtime.snap_to_flag & SCE_SNAP_MODE_EDGE) { - if (test_projected_edge_dist(&neasrest_precalc, - clip_planes_local, - sctx->runtime.clip_plane_len, - is_persp, - eBone->head, - eBone->tail, - &dist_px_sq, - r_loc)) { - retval = SCE_SNAP_MODE_EDGE; - } - } + if (eBone->flag & BONE_HIDDEN_A) { + /* Skip hidden bones. */ + continue; + } + + const bool is_selected = (eBone->flag & (BONE_ROOTSEL | BONE_TIPSEL)) != 0; + if (is_selected && snap_select == SNAP_NOT_SELECTED) { + continue; } - } - } - } - else if (ob_eval->pose && ob_eval->pose->chanbase.first) { - LISTBASE_FOREACH (bPoseChannel *, pchan, &ob_eval->pose->chanbase) { - Bone *bone = pchan->bone; - /* skip hidden bones */ - if (bone && !(bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) { bool has_vert_snap = false; - const float *head_vec = pchan->pose_head; - const float *tail_vec = pchan->pose_tail; if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) { has_vert_snap = test_projected_vert_dist(&neasrest_precalc, clip_planes_local, sctx->runtime.clip_plane_len, is_persp, - head_vec, + eBone->head, &dist_px_sq, r_loc); has_vert_snap |= test_projected_vert_dist(&neasrest_precalc, clip_planes_local, sctx->runtime.clip_plane_len, is_persp, - tail_vec, + eBone->tail, + &dist_px_sq, r_loc); @@ -1955,8 +1893,8 @@ static short snapArmature(SnapObjectContext *sctx, clip_planes_local, sctx->runtime.clip_plane_len, is_persp, - head_vec, - tail_vec, + eBone->head, + eBone->tail, &dist_px_sq, r_loc)) { retval = SCE_SNAP_MODE_EDGE; @@ -1965,6 +1903,51 @@ static short snapArmature(SnapObjectContext *sctx, } } } + else if (ob_eval->pose && ob_eval->pose->chanbase.first) { + LISTBASE_FOREACH (bPoseChannel *, pchan, &ob_eval->pose->chanbase) { + Bone *bone = pchan->bone; + /* skip hidden bones */ + if (!bone || (bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) { + continue; + } + bool has_vert_snap = false; + const float *head_vec = pchan->pose_head; + const float *tail_vec = pchan->pose_tail; + + if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) { + has_vert_snap = test_projected_vert_dist(&neasrest_precalc, + clip_planes_local, + sctx->runtime.clip_plane_len, + is_persp, + head_vec, + &dist_px_sq, + r_loc); + has_vert_snap |= test_projected_vert_dist(&neasrest_precalc, + clip_planes_local, + sctx->runtime.clip_plane_len, + is_persp, + tail_vec, + &dist_px_sq, + r_loc); + + if (has_vert_snap) { + retval = SCE_SNAP_MODE_VERTEX; + } + } + if (!has_vert_snap && sctx->runtime.snap_to_flag & SCE_SNAP_MODE_EDGE) { + if (test_projected_edge_dist(&neasrest_precalc, + clip_planes_local, + sctx->runtime.clip_plane_len, + is_persp, + head_vec, + tail_vec, + &dist_px_sq, + r_loc)) { + retval = SCE_SNAP_MODE_EDGE; + } + } + } + } if (retval) { *dist_px = sqrtf(dist_px_sq); @@ -1982,7 +1965,6 @@ static short snapArmature(SnapObjectContext *sctx, static short snapCurve(SnapObjectContext *sctx, Object *ob_eval, const float obmat[4][4], - bool use_obedit, /* read/write args */ float *dist_px, /* return args */ @@ -2007,7 +1989,7 @@ static short snapCurve(SnapObjectContext *sctx, dist_squared_to_projected_aabb_precalc( &neasrest_precalc, lpmat, sctx->runtime.win_size, sctx->runtime.mval); - use_obedit = use_obedit && BKE_object_is_in_editmode(ob_eval); + const bool use_obedit = BKE_object_is_in_editmode(ob_eval); if (use_obedit == false) { /* Test BoundBox */ @@ -2040,14 +2022,20 @@ static short snapCurve(SnapObjectContext *sctx, } bool is_persp = sctx->runtime.view_proj == VIEW_PROJ_PERSP; + bool skip_selected = sctx->runtime.params->snap_select == SNAP_NOT_SELECTED; for (Nurb *nu = (use_obedit ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) { for (int u = 0; u < nu->pntsu; u++) { if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) { if (use_obedit) { if (nu->bezt) { - /* don't snap to selected (moving) or hidden */ - if (nu->bezt[u].f2 & SELECT || nu->bezt[u].hide != 0) { + if (nu->bezt[u].hide) { + /* Skip hidden. */ + continue; + } + + bool is_selected = (nu->bezt[u].f2 & SELECT) != 0; + if (is_selected && skip_selected) { continue; } has_snap |= test_projected_vert_dist(&neasrest_precalc, @@ -2059,8 +2047,9 @@ static short snapCurve(SnapObjectContext *sctx, r_loc); /* Don't snap if handle is selected (moving), * or if it is aligning to a moving handle. */ - if (!(nu->bezt[u].f1 & SELECT) && - !(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT)) { + is_selected = (!(nu->bezt[u].f1 & SELECT) && + !(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT)) != 0; + if (!(is_selected && skip_selected)) { has_snap |= test_projected_vert_dist(&neasrest_precalc, clip_planes_local, clip_plane_len, @@ -2069,8 +2058,10 @@ static short snapCurve(SnapObjectContext *sctx, &dist_px_sq, r_loc); } - if (!(nu->bezt[u].f3 & SELECT) && - !(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT)) { + + is_selected = (!(nu->bezt[u].f3 & SELECT) && + !(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT)) != 0; + if (!(is_selected && skip_selected)) { has_snap |= test_projected_vert_dist(&neasrest_precalc, clip_planes_local, clip_plane_len, @@ -2081,10 +2072,16 @@ static short snapCurve(SnapObjectContext *sctx, } } else { - /* don't snap to selected (moving) or hidden */ - if (nu->bp[u].f1 & SELECT || nu->bp[u].hide != 0) { + if (nu->bp[u].hide) { + /* Skip hidden. */ continue; } + + bool is_selected = (nu->bp[u].f1 & SELECT) != 0; + if (is_selected && skip_selected) { + continue; + } + has_snap |= test_projected_vert_dist(&neasrest_precalc, clip_planes_local, clip_plane_len, @@ -2291,7 +2288,6 @@ static short snapMesh(SnapObjectContext *sctx, Mesh *me_eval, const float obmat[4][4], bool use_hide, - bool use_backface_culling, /* read/write args */ float *dist_px, /* return args */ @@ -2362,8 +2358,10 @@ static short snapMesh(SnapObjectContext *sctx, } Nearest2dUserData nearest2d; - nearest2d_data_init( - sod, sctx->runtime.view_proj == VIEW_PROJ_PERSP, use_backface_culling, &nearest2d); + nearest2d_data_init(sod, + sctx->runtime.view_proj == VIEW_PROJ_PERSP, + sctx->runtime.params->use_backface_culling, + &nearest2d); BVHTreeNearest nearest = { .index = -1, @@ -2481,7 +2479,6 @@ static short snapEditMesh(SnapObjectContext *sctx, Object *ob_eval, BMEditMesh *em, const float obmat[4][4], - bool use_backface_culling, /* read/write args */ float *dist_px, /* return args */ @@ -2582,8 +2579,10 @@ static short snapEditMesh(SnapObjectContext *sctx, } Nearest2dUserData nearest2d; - nearest2d_data_init( - sod, sctx->runtime.view_proj == VIEW_PROJ_PERSP, use_backface_culling, &nearest2d); + nearest2d_data_init(sod, + sctx->runtime.view_proj == VIEW_PROJ_PERSP, + sctx->runtime.params->use_backface_culling, + &nearest2d); BVHTreeNearest nearest = { .index = -1, @@ -2678,8 +2677,6 @@ struct SnapObjUserData { static void snap_obj_fn(SnapObjectContext *sctx, Object *ob_eval, float obmat[4][4], - eSnapEditType edit_mode_type, - bool use_backface_culling, bool UNUSED(is_object_active), void *data) { @@ -2688,20 +2685,14 @@ static void snap_obj_fn(SnapObjectContext *sctx, switch (ob_eval->type) { case OB_MESH: { + const eSnapEditType edit_mode_type = sctx->runtime.params->edit_mode_type; bool use_hide; Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide); if (me_eval == NULL) { /* Operators only update the editmesh looptris of the original mesh. */ BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob_eval)); - retval = snapEditMesh(sctx, - ob_eval, - em_orig, - obmat, - use_backface_culling, - dt->dist_px, - dt->r_loc, - dt->r_no, - dt->r_index); + retval = snapEditMesh( + sctx, ob_eval, em_orig, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); break; } if (ob_eval->dt == OB_BOUNDBOX) { @@ -2709,45 +2700,22 @@ static void snap_obj_fn(SnapObjectContext *sctx, return; } - retval = snapMesh(sctx, - ob_eval, - me_eval, - obmat, - use_hide, - use_backface_culling, - dt->dist_px, - dt->r_loc, - dt->r_no, - dt->r_index); + retval = snapMesh( + sctx, ob_eval, me_eval, obmat, use_hide, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); break; } case OB_ARMATURE: retval = snapArmature(sctx, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); break; case OB_CURVE: - retval = snapCurve(sctx, - ob_eval, - obmat, - edit_mode_type == SNAP_GEOM_EDIT, - dt->dist_px, - dt->r_loc, - dt->r_no, - dt->r_index); + retval = snapCurve(sctx, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); break; /* Use ATTR_FALLTHROUGH if we want to snap to the generated mesh. */ case OB_SURF: case OB_FONT: { Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval); if (mesh_eval) { - retval |= snapMesh(sctx, - ob_eval, - mesh_eval, - obmat, - false, - use_backface_culling, - dt->dist_px, - dt->r_loc, - dt->r_no, - dt->r_index); + retval |= snapMesh( + sctx, ob_eval, mesh_eval, obmat, false, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); } break; } @@ -2780,8 +2748,6 @@ static void snap_obj_fn(SnapObjectContext *sctx, * Walks through all objects in the scene to find the closest snap element ray. * * \param sctx: Snap context to store data. - * \param snapdata: struct generated in `get_snapdata`. - * \param params: Parameters for control snap behavior. * * Read/Write Args * --------------- @@ -2799,7 +2765,6 @@ static void snap_obj_fn(SnapObjectContext *sctx, * \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances). */ static short snapObjectsRay(SnapObjectContext *sctx, - const struct SnapObjectParams *params, /* read/write args */ /* Parameters below cannot be const, because they are assigned to a * non-const variable (readability-non-const-parameter). */ @@ -2821,7 +2786,7 @@ static short snapObjectsRay(SnapObjectContext *sctx, .ret = 0, }; - iter_snap_objects(sctx, params, snap_obj_fn, &data); + iter_snap_objects(sctx, snap_obj_fn, &data); return data.ret; } @@ -2892,19 +2857,12 @@ bool ED_transform_snap_object_project_ray_ex(SnapObjectContext *sctx, Object **r_ob, float r_obmat[4][4]) { - return raycastObjects(sctx, - depsgraph, - v3d, - params, - ray_start, - ray_normal, - ray_depth, - r_loc, - r_no, - r_index, - r_ob, - r_obmat, - NULL); + sctx->runtime.params = params; + sctx->runtime.depsgraph = depsgraph; + sctx->runtime.v3d = v3d; + + return raycastObjects( + sctx, ray_start, ray_normal, ray_depth, r_loc, r_no, r_index, r_ob, r_obmat, NULL); } /** @@ -2924,6 +2882,10 @@ bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx, bool sort, ListBase *r_hit_list) { + sctx->runtime.params = params; + sctx->runtime.depsgraph = depsgraph; + sctx->runtime.v3d = v3d; + if (ray_depth == -1.0f) { ray_depth = BVH_RAYCAST_DIST_MAX; } @@ -2932,19 +2894,8 @@ bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx, float ray_depth_prev = ray_depth; #endif - bool retval = raycastObjects(sctx, - depsgraph, - v3d, - params, - ray_start, - ray_normal, - &ray_depth, - NULL, - NULL, - NULL, - NULL, - NULL, - r_hit_list); + bool retval = raycastObjects( + sctx, ray_start, ray_normal, &ray_depth, NULL, NULL, NULL, NULL, NULL, r_hit_list); /* meant to be readonly for 'all' hits, ensure it is */ #ifdef DEBUG @@ -3031,6 +2982,11 @@ static short transform_snap_context_project_view3d_mixed_impl( float r_obmat[4][4], float r_face_nor[3]) { + sctx->runtime.params = params; + sctx->runtime.depsgraph = depsgraph; + sctx->runtime.region = region; + sctx->runtime.v3d = v3d; + BLI_assert((snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) != 0); @@ -3050,10 +3006,6 @@ static short transform_snap_context_project_view3d_mixed_impl( bool use_occlusion_test = params->use_occlusion_test && !XRAY_ENABLED(v3d); - sctx->runtime.depsgraph = depsgraph; - sctx->runtime.region = region; - sctx->runtime.v3d = v3d; - if (snap_to_flag & SCE_SNAP_MODE_FACE || use_occlusion_test) { float ray_start[3], ray_normal[3]; if (!ED_view3d_win_to_ray_clipped_ex( @@ -3063,19 +3015,9 @@ static short transform_snap_context_project_view3d_mixed_impl( float dummy_ray_depth = BVH_RAYCAST_DIST_MAX; - has_hit = raycastObjects(sctx, - depsgraph, - v3d, - params, - ray_start, - ray_normal, - &dummy_ray_depth, - loc, - no, - &index, - &ob_eval, - obmat, - NULL); + has_hit = raycastObjects( + sctx, ray_start, ray_normal, &dummy_ray_depth, loc, no, &index, &ob_eval, obmat, NULL); + if (has_hit) { if (r_face_nor) { copy_v3_v3(r_face_nor, no); @@ -3144,8 +3086,7 @@ static short transform_snap_context_project_view3d_mixed_impl( new_clipplane[3] += 0.01f; /* Try to snap only to the polygon. */ - elem_test = snap_mesh_polygon( - sctx, ob_eval, obmat, params->use_backface_culling, &dist_px_tmp, loc, no, &index); + elem_test = snap_mesh_polygon(sctx, ob_eval, obmat, &dist_px_tmp, loc, no, &index); if (elem_test) { elem = elem_test; } @@ -3159,7 +3100,7 @@ static short transform_snap_context_project_view3d_mixed_impl( sctx->runtime.has_occlusion_plane = true; } - elem_test = snapObjectsRay(sctx, params, &dist_px_tmp, loc, no, &index, &ob_eval, obmat); + elem_test = snapObjectsRay(sctx, &dist_px_tmp, loc, no, &index, &ob_eval, obmat); if (elem_test) { elem = elem_test; } @@ -3168,16 +3109,8 @@ static short transform_snap_context_project_view3d_mixed_impl( (snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR))) { sctx->runtime.snap_to_flag = snap_to_flag; - elem = snap_mesh_edge_verts_mixed(sctx, - ob_eval, - obmat, - *dist_px, - prev_co, - params->use_backface_culling, - &dist_px_tmp, - loc, - no, - &index); + elem = snap_mesh_edge_verts_mixed( + sctx, ob_eval, obmat, *dist_px, prev_co, &dist_px_tmp, loc, no, &index); } if (elem & snap_to_flag) { diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 89490e59bd8..db838bf353b 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -118,7 +118,7 @@ static bool ED_uvedit_ensure_uvs(Object *obedit) int cd_loop_uv_offset; if (em && em->bm->totface && !CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV)) { - ED_mesh_uv_texture_add(obedit->data, NULL, true, true); + ED_mesh_uv_texture_add(obedit->data, NULL, true, true, NULL); } /* Happens when there are no faces. */ diff --git a/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp b/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp index 9bf00ed7092..de7fcb7a728 100644 --- a/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp +++ b/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp @@ -190,7 +190,7 @@ void FEdgeXDetector::computeCurvatures(WXVertex *vertex) } // CURVATURE LAYER - // store all the curvature datas for each vertex + // store all the curvature data for each vertex // soc unused - real K1, K2 real cos2theta, sin2theta; diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh index 5e0302130af..fb488fdbfa9 100644 --- a/source/blender/functions/FN_field.hh +++ b/source/blender/functions/FN_field.hh @@ -248,9 +248,9 @@ class FieldInput : public FieldNode { * Get the value of this specific input based on the given context. The returned virtual array, * should live at least as long as the passed in #scope. May return null. */ - virtual const GVArray *get_varray_for_context(const FieldContext &context, - IndexMask mask, - ResourceScope &scope) const = 0; + virtual GVArray get_varray_for_context(const FieldContext &context, + IndexMask mask, + ResourceScope &scope) const = 0; virtual std::string socket_inspection_name() const; blender::StringRef debug_name() const; @@ -268,9 +268,9 @@ class FieldContext { public: ~FieldContext() = default; - virtual const GVArray *get_varray_for_input(const FieldInput &field_input, - IndexMask mask, - ResourceScope &scope) const; + virtual GVArray get_varray_for_input(const FieldInput &field_input, + IndexMask mask, + ResourceScope &scope) const; }; /** @@ -289,8 +289,8 @@ class FieldEvaluator : NonMovable, NonCopyable { const FieldContext &context_; const IndexMask mask_; Vector<GField> fields_to_evaluate_; - Vector<GVMutableArray *> dst_varrays_; - Vector<const GVArray *> evaluated_varrays_; + Vector<GVMutableArray> dst_varrays_; + Vector<GVArray> evaluated_varrays_; Vector<OutputPointerInfo> output_pointer_infos_; bool is_evaluated_ = false; @@ -317,13 +317,12 @@ class FieldEvaluator : NonMovable, NonCopyable { * \param field: Field to add to the evaluator. * \param dst: Mutable virtual array that the evaluated result for this field is be written into. */ - int add_with_destination(GField field, GVMutableArray &dst); + int add_with_destination(GField field, GVMutableArray dst); /** Same as #add_with_destination but typed. */ - template<typename T> int add_with_destination(Field<T> field, VMutableArray<T> &dst) + template<typename T> int add_with_destination(Field<T> field, VMutableArray<T> dst) { - GVMutableArray &varray = scope_.construct<GVMutableArray_For_VMutableArray<T>>(dst); - return this->add_with_destination(GField(std::move(field)), varray); + return this->add_with_destination(GField(std::move(field)), GVMutableArray(std::move(dst))); } /** @@ -342,11 +341,10 @@ class FieldEvaluator : NonMovable, NonCopyable { */ template<typename T> int add_with_destination(Field<T> field, MutableSpan<T> dst) { - GVMutableArray &varray = scope_.construct<GVMutableArray_For_MutableSpan<T>>(dst); - return this->add_with_destination(std::move(field), varray); + return this->add_with_destination(std::move(field), VMutableArray<T>::ForSpan(dst)); } - int add(GField field, const GVArray **varray_ptr); + int add(GField field, GVArray *varray_ptr); /** * \param field: Field to add to the evaluator. @@ -354,14 +352,14 @@ class FieldEvaluator : NonMovable, NonCopyable { * assigned to the given position. * \return Index of the field in the evaluator which can be used in the #get_evaluated methods. */ - template<typename T> int add(Field<T> field, const VArray<T> **varray_ptr) + template<typename T> int add(Field<T> field, VArray<T> *varray_ptr) { const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field)); - dst_varrays_.append(nullptr); - output_pointer_infos_.append( - OutputPointerInfo{varray_ptr, [](void *dst, const GVArray &varray, ResourceScope &scope) { - *(const VArray<T> **)dst = &*scope.construct<GVArray_Typed<T>>(varray); - }}); + dst_varrays_.append({}); + output_pointer_infos_.append(OutputPointerInfo{ + varray_ptr, [](void *dst, const GVArray &varray, ResourceScope &UNUSED(scope)) { + *(VArray<T> *)dst = varray.typed<T>(); + }}); return field_index; } @@ -378,14 +376,12 @@ class FieldEvaluator : NonMovable, NonCopyable { const GVArray &get_evaluated(const int field_index) const { BLI_assert(is_evaluated_); - return *evaluated_varrays_[field_index]; + return evaluated_varrays_[field_index]; } - template<typename T> const VArray<T> &get_evaluated(const int field_index) + template<typename T> VArray<T> get_evaluated(const int field_index) { - const GVArray &varray = this->get_evaluated(field_index); - GVArray_Typed<T> &typed_varray = scope_.construct<GVArray_Typed<T>>(varray); - return *typed_varray; + return this->get_evaluated(field_index).typed<T>(); } /** @@ -396,11 +392,11 @@ class FieldEvaluator : NonMovable, NonCopyable { IndexMask get_evaluated_as_mask(const int field_index); }; -Vector<const GVArray *> evaluate_fields(ResourceScope &scope, - Span<GFieldRef> fields_to_evaluate, - IndexMask mask, - const FieldContext &context, - Span<GVMutableArray *> dst_varrays = {}); +Vector<GVArray> evaluate_fields(ResourceScope &scope, + Span<GFieldRef> fields_to_evaluate, + IndexMask mask, + const FieldContext &context, + Span<GVMutableArray> dst_varrays = {}); /* -------------------------------------------------------------------- */ /** \name Utility functions for simple field creation and evaluation @@ -429,11 +425,11 @@ class IndexFieldInput final : public FieldInput { public: IndexFieldInput(); - static GVArray *get_index_varray(IndexMask mask, ResourceScope &scope); + static GVArray get_index_varray(IndexMask mask, ResourceScope &scope); - const GVArray *get_varray_for_context(const FieldContext &context, - IndexMask mask, - ResourceScope &scope) const final; + GVArray get_varray_for_context(const FieldContext &context, + IndexMask mask, + ResourceScope &scope) const final; uint64_t hash() const override; bool is_equal_to(const fn::FieldNode &other) const override; diff --git a/source/blender/functions/FN_field_cpp_type.hh b/source/blender/functions/FN_field_cpp_type.hh index 5e6f1b5a585..c3636fb3c7b 100644 --- a/source/blender/functions/FN_field_cpp_type.hh +++ b/source/blender/functions/FN_field_cpp_type.hh @@ -30,19 +30,19 @@ template<typename T> struct FieldCPPTypeParam { class FieldCPPType : public CPPType { private: - const CPPType &field_type_; + const CPPType &base_type_; public: template<typename T> FieldCPPType(FieldCPPTypeParam<Field<T>> /* unused */, StringRef debug_name) : CPPType(CPPTypeParam<Field<T>, CPPTypeFlags::None>(), debug_name), - field_type_(CPPType::get<T>()) + base_type_(CPPType::get<T>()) { } - const CPPType &field_type() const + const CPPType &base_type() const { - return field_type_; + return base_type_; } /* Ensure that #GField and #Field<T> have the same layout, to enable casting between the two. */ diff --git a/source/blender/functions/FN_generic_vector_array.hh b/source/blender/functions/FN_generic_vector_array.hh index 179e85671f8..57efa1b5ba9 100644 --- a/source/blender/functions/FN_generic_vector_array.hh +++ b/source/blender/functions/FN_generic_vector_array.hh @@ -125,8 +125,7 @@ template<typename T> class GVectorArray_TypedMutableRef { void extend(const int64_t index, const VArray<T> &values) { - GVArray_For_VArray<T> array{values}; - this->extend(index, array); + vector_array_->extend(index, values); } MutableSpan<T> operator[](const int64_t index) diff --git a/source/blender/functions/FN_generic_virtual_array.hh b/source/blender/functions/FN_generic_virtual_array.hh index 8aad017e68b..b822f3a7c33 100644 --- a/source/blender/functions/FN_generic_virtual_array.hh +++ b/source/blender/functions/FN_generic_virtual_array.hh @@ -23,8 +23,7 @@ * the data type is only known at runtime. */ -#include <optional> - +#include "BLI_timeit.hh" #include "BLI_virtual_array.hh" #include "FN_generic_array.hh" @@ -32,940 +31,845 @@ namespace blender::fn { -template<typename T> class GVArray_Typed; -template<typename T> class GVMutableArray_Typed; +/* -------------------------------------------------------------------- */ +/** \name #GVArrayImpl and #GVMutableArrayImpl. + * \{ */ class GVArray; +class GVArrayImpl; class GVMutableArray; +class GVMutableArrayImpl; -using GVArrayPtr = std::unique_ptr<GVArray>; -using GVMutableArrayPtr = std::unique_ptr<GVMutableArray>; - -/* A generically typed version of `VArray<T>`. */ -class GVArray { +/* A generically typed version of #VArrayImpl. */ +class GVArrayImpl { protected: const CPPType *type_; int64_t size_; public: - GVArray(const CPPType &type, const int64_t size) : type_(&type), size_(size) - { - BLI_assert(size_ >= 0); - } + GVArrayImpl(const CPPType &type, const int64_t size); + virtual ~GVArrayImpl() = default; - virtual ~GVArray() = default; + const CPPType &type() const; - const CPPType &type() const - { - return *type_; - } + int64_t size() const; - int64_t size() const - { - return size_; - } + virtual void get(const int64_t index, void *r_value) const; + virtual void get_to_uninitialized(const int64_t index, void *r_value) const = 0; - bool is_empty() const - { - return size_ == 0; - } + virtual bool is_span() const; + virtual GSpan get_internal_span() const; - /* Copies the value at the given index into the provided storage. The `r_value` pointer is - * expected to point to initialized memory. */ - void get(const int64_t index, void *r_value) const - { - BLI_assert(index >= 0); - BLI_assert(index < size_); - this->get_impl(index, r_value); - } + virtual bool is_single() const; + virtual void get_internal_single(void *UNUSED(r_value)) const; - /* Same as `get`, but `r_value` is expected to point to uninitialized memory. */ - void get_to_uninitialized(const int64_t index, void *r_value) const - { - BLI_assert(index >= 0); - BLI_assert(index < size_); - this->get_to_uninitialized_impl(index, r_value); - } + virtual void materialize(const IndexMask mask, void *dst) const; + virtual void materialize_to_uninitialized(const IndexMask mask, void *dst) const; - /* Returns true when the virtual array is stored as a span internally. */ - bool is_span() const - { - if (size_ == 0) { - return true; - } - return this->is_span_impl(); - } + virtual bool try_assign_VArray(void *varray) const; + virtual bool may_have_ownership() const; +}; - /* Returns the internally used span of the virtual array. This invokes undefined behavior is the - * virtual array is not stored as a span internally. */ - GSpan get_internal_span() const - { - BLI_assert(this->is_span()); - if (size_ == 0) { - return GSpan(*type_); - } - return this->get_internal_span_impl(); - } +/* A generic version of #VMutableArrayImpl. */ +class GVMutableArrayImpl : public GVArrayImpl { + public: + GVMutableArrayImpl(const CPPType &type, const int64_t size); - /* Returns true when the virtual array returns the same value for every index. */ - bool is_single() const - { - if (size_ == 1) { - return true; - } - return this->is_single_impl(); - } + virtual void set_by_copy(const int64_t index, const void *value); + virtual void set_by_relocate(const int64_t index, void *value); + virtual void set_by_move(const int64_t index, void *value) = 0; - /* Copies the value that is used for every element into `r_value`, which is expected to point to - * initialized memory. This invokes undefined behavior if the virtual array would not return the - * same value for every index. */ - void get_internal_single(void *r_value) const - { - BLI_assert(this->is_single()); - if (size_ == 1) { - this->get(0, r_value); - return; - } - this->get_internal_single_impl(r_value); - } + virtual void set_all(const void *src); - /* Same as `get_internal_single`, but `r_value` points to initialized memory. */ - void get_internal_single_to_uninitialized(void *r_value) const - { - type_->default_construct(r_value); - this->get_internal_single(r_value); - } + virtual bool try_assign_VMutableArray(void *varray) const; +}; - void materialize(void *dst) const; - void materialize(const IndexMask mask, void *dst) const; +/** \} */ - void materialize_to_uninitialized(void *dst) const; - void materialize_to_uninitialized(const IndexMask mask, void *dst) const; +/* -------------------------------------------------------------------- */ +/** \name #GVArray and #GVMutableArray + * \{ */ - template<typename T> const VArray<T> *try_get_internal_varray() const - { - BLI_assert(type_->is<T>()); - return (const VArray<T> *)this->try_get_internal_varray_impl(); - } +namespace detail { +struct GVArrayAnyExtraInfo { + const GVArrayImpl *(*get_varray)(const void *buffer) = + [](const void *UNUSED(buffer)) -> const GVArrayImpl * { return nullptr; }; - /* Create a typed virtual array for this generic virtual array. */ - template<typename T> GVArray_Typed<T> typed() const - { - return GVArray_Typed<T>(*this); - } + template<typename StorageT> static GVArrayAnyExtraInfo get(); +}; +} // namespace detail - GVArrayPtr shallow_copy() const; +class GVMutableArray; +/** + * Utility class to reduce code duplication between #GVArray and #GVMutableArray. + * It pretty much follows #VArrayCommon. Don't use this class outside of this header. + */ +class GVArrayCommon { protected: - virtual void get_impl(const int64_t index, void *r_value) const; - virtual void get_to_uninitialized_impl(const int64_t index, void *r_value) const = 0; + /** + * See #VArrayCommon for more information. The inline buffer is a bit larger here, because + * generic virtual array implementations often require a bit more space than typed ones. + */ + using Storage = Any<detail::GVArrayAnyExtraInfo, 40, 8>; - virtual bool is_span_impl() const; - virtual GSpan get_internal_span_impl() const; + const GVArrayImpl *impl_ = nullptr; + Storage storage_; - virtual bool is_single_impl() const; - virtual void get_internal_single_impl(void *UNUSED(r_value)) const; + protected: + GVArrayCommon(); + GVArrayCommon(const GVArrayCommon &other); + GVArrayCommon(GVArrayCommon &&other) noexcept; + GVArrayCommon(const GVArrayImpl *impl); + GVArrayCommon(std::shared_ptr<const GVArrayImpl> impl); + ~GVArrayCommon(); - virtual void materialize_impl(const IndexMask mask, void *dst) const; - virtual void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const; + template<typename ImplT, typename... Args> void emplace(Args &&...args); - virtual const void *try_get_internal_varray_impl() const; -}; + void copy_from(const GVArrayCommon &other); + void move_from(GVArrayCommon &&other) noexcept; + + const GVArrayImpl *impl_from_storage() const; -/* Similar to GVArray, but supports changing the elements in the virtual array. */ -class GVMutableArray : public GVArray { public: - GVMutableArray(const CPPType &type, const int64_t size) : GVArray(type, size) - { - } + const CPPType &type() const; + operator bool() const; - void set_by_copy(const int64_t index, const void *value) - { - BLI_assert(index >= 0); - BLI_assert(index < size_); - this->set_by_copy_impl(index, value); - } + int64_t size() const; + bool is_empty() const; + IndexRange index_range() const; - void set_by_move(const int64_t index, void *value) - { - BLI_assert(index >= 0); - BLI_assert(index < size_); - this->set_by_move_impl(index, value); - } + template<typename T> bool try_assign_VArray(VArray<T> &varray) const; + bool may_have_ownership() const; - void set_by_relocate(const int64_t index, void *value) - { - BLI_assert(index >= 0); - BLI_assert(index < size_); - this->set_by_relocate_impl(index, value); - } + void materialize(void *dst) const; + void materialize(const IndexMask mask, void *dst) const; - GMutableSpan get_internal_span() - { - BLI_assert(this->is_span()); - GSpan span = static_cast<const GVArray *>(this)->get_internal_span(); - return GMutableSpan(span.type(), const_cast<void *>(span.data()), span.size()); - } + void materialize_to_uninitialized(void *dst) const; + void materialize_to_uninitialized(const IndexMask mask, void *dst) const; - template<typename T> VMutableArray<T> *try_get_internal_mutable_varray() - { - BLI_assert(type_->is<T>()); - return (VMutableArray<T> *)this->try_get_internal_mutable_varray_impl(); - } + bool is_span() const; + GSpan get_internal_span() const; - /* Create a typed virtual array for this generic virtual array. */ - template<typename T> GVMutableArray_Typed<T> typed() - { - return GVMutableArray_Typed<T>(*this); - } + bool is_single() const; + void get_internal_single(void *r_value) const; + void get_internal_single_to_uninitialized(void *r_value) const; - void fill(const void *value); + void get(const int64_t index, void *r_value) const; + void get_to_uninitialized(const int64_t index, void *r_value) const; +}; - /* Copy the values from the source buffer to all elements in the virtual array. */ - void set_all(const void *src) - { - this->set_all_impl(src); - } +/** Generic version of #VArray. */ +class GVArray : public GVArrayCommon { + private: + friend GVMutableArray; - protected: - virtual void set_by_copy_impl(const int64_t index, const void *value); - virtual void set_by_relocate_impl(const int64_t index, void *value); - virtual void set_by_move_impl(const int64_t index, void *value) = 0; + public: + GVArray() = default; - virtual void set_all_impl(const void *src); + GVArray(const GVArray &other); + GVArray(GVArray &&other) noexcept; + GVArray(const GVArrayImpl *impl); + GVArray(std::shared_ptr<const GVArrayImpl> impl); - virtual void *try_get_internal_mutable_varray_impl(); -}; + template<typename T> GVArray(const VArray<T> &varray); + template<typename T> VArray<T> typed() const; -class GVArray_For_GSpan : public GVArray { - protected: - const void *data_ = nullptr; - const int64_t element_size_; + template<typename ImplT, typename... Args> static GVArray For(Args &&...args); - public: - GVArray_For_GSpan(const GSpan span) - : GVArray(span.type(), span.size()), data_(span.data()), element_size_(span.type().size()) - { - } + static GVArray ForSingle(const CPPType &type, const int64_t size, const void *value); + static GVArray ForSingleRef(const CPPType &type, const int64_t size, const void *value); + static GVArray ForSingleDefault(const CPPType &type, const int64_t size); + static GVArray ForSpan(GSpan span); + static GVArray ForGArray(GArray<> array); + static GVArray ForEmpty(const CPPType &type); - protected: - GVArray_For_GSpan(const CPPType &type, const int64_t size) - : GVArray(type, size), element_size_(type.size()) - { - } + GVArray slice(IndexRange slice) const; - void get_impl(const int64_t index, void *r_value) const override; - void get_to_uninitialized_impl(const int64_t index, void *r_value) const override; + GVArray &operator=(const GVArray &other); + GVArray &operator=(GVArray &&other) noexcept; - bool is_span_impl() const override; - GSpan get_internal_span_impl() const override; + const GVArrayImpl *get_implementation() const + { + return impl_; + } }; -class GVArray_For_Empty : public GVArray { +/** Generic version of #VMutableArray. */ +class GVMutableArray : public GVArrayCommon { public: - GVArray_For_Empty(const CPPType &type) : GVArray(type, 0) - { - } + GVMutableArray() = default; + GVMutableArray(const GVMutableArray &other); + GVMutableArray(GVMutableArray &&other) noexcept; + GVMutableArray(GVMutableArrayImpl *impl); + GVMutableArray(std::shared_ptr<GVMutableArrayImpl> impl); - protected: - void get_to_uninitialized_impl(const int64_t UNUSED(index), void *UNUSED(r_value)) const override - { - BLI_assert(false); - } -}; + template<typename T> GVMutableArray(const VMutableArray<T> &varray); + template<typename T> VMutableArray<T> typed() const; -class GVMutableArray_For_GMutableSpan : public GVMutableArray { - protected: - void *data_ = nullptr; - const int64_t element_size_; + template<typename ImplT, typename... Args> static GVMutableArray For(Args &&...args); - public: - GVMutableArray_For_GMutableSpan(const GMutableSpan span) - : GVMutableArray(span.type(), span.size()), - data_(span.data()), - element_size_(span.type().size()) - { - } + static GVMutableArray ForSpan(GMutableSpan span); - protected: - GVMutableArray_For_GMutableSpan(const CPPType &type, const int64_t size) - : GVMutableArray(type, size), element_size_(type.size()) - { - } + operator GVArray() const &; + operator GVArray() &&noexcept; - void get_impl(const int64_t index, void *r_value) const override; - void get_to_uninitialized_impl(const int64_t index, void *r_value) const override; + GVMutableArray &operator=(const GVMutableArray &other); + GVMutableArray &operator=(GVMutableArray &&other) noexcept; - void set_by_copy_impl(const int64_t index, const void *value) override; - void set_by_move_impl(const int64_t index, void *value) override; - void set_by_relocate_impl(const int64_t index, void *value) override; + GMutableSpan get_internal_span() const; - bool is_span_impl() const override; - GSpan get_internal_span_impl() const override; -}; + template<typename T> bool try_assign_VMutableArray(VMutableArray<T> &varray) const; -/* Generic virtual array where each element has the same value. The value is not owned. */ -class GVArray_For_SingleValueRef : public GVArray { - protected: - const void *value_ = nullptr; + void set_by_copy(const int64_t index, const void *value); + void set_by_move(const int64_t index, void *value); + void set_by_relocate(const int64_t index, void *value); - public: - GVArray_For_SingleValueRef(const CPPType &type, const int64_t size, const void *value) - : GVArray(type, size), value_(value) - { - } + void fill(const void *value); + void set_all(const void *src); - protected: - GVArray_For_SingleValueRef(const CPPType &type, const int64_t size) : GVArray(type, size) - { - } + GVMutableArrayImpl *get_implementation() const; - void get_impl(const int64_t index, void *r_value) const override; - void get_to_uninitialized_impl(const int64_t index, void *r_value) const override; + private: + GVMutableArrayImpl *get_impl() const; +}; - bool is_span_impl() const override; - GSpan get_internal_span_impl() const override; +/** \} */ - bool is_single_impl() const override; - void get_internal_single_impl(void *r_value) const override; +/* -------------------------------------------------------------------- */ +/** \name #GVArray_GSpan and #GVMutableArray_GSpan. + * \{ */ + +/* A generic version of VArray_Span. */ +class GVArray_GSpan : public GSpan { + private: + GVArray varray_; + void *owned_data_ = nullptr; + + public: + GVArray_GSpan(GVArray varray); + ~GVArray_GSpan(); }; -/* Same as GVArray_For_SingleValueRef, but the value is owned. */ -class GVArray_For_SingleValue : public GVArray_For_SingleValueRef { +/* A generic version of VMutableArray_Span. */ +class GVMutableArray_GSpan : public GMutableSpan { + private: + GVMutableArray varray_; + void *owned_data_ = nullptr; + bool save_has_been_called_ = false; + bool show_not_saved_warning_ = true; + public: - GVArray_For_SingleValue(const CPPType &type, const int64_t size, const void *value); - ~GVArray_For_SingleValue(); + GVMutableArray_GSpan(GVMutableArray varray, bool copy_values_to_span = true); + ~GVMutableArray_GSpan(); + + void save(); + void disable_not_applied_warning(); }; +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Conversions between generic and typed virtual arrays. + * \{ */ + /* Used to convert a typed virtual array into a generic one. */ -template<typename T> class GVArray_For_VArray : public GVArray { +template<typename T> class GVArrayImpl_For_VArray : public GVArrayImpl { protected: - const VArray<T> *varray_ = nullptr; + VArray<T> varray_; public: - GVArray_For_VArray(const VArray<T> &varray) - : GVArray(CPPType::get<T>(), varray.size()), varray_(&varray) + GVArrayImpl_For_VArray(VArray<T> varray) + : GVArrayImpl(CPPType::get<T>(), varray.size()), varray_(std::move(varray)) { } protected: - GVArray_For_VArray(const int64_t size) : GVArray(CPPType::get<T>(), size) + void get(const int64_t index, void *r_value) const override { + *(T *)r_value = varray_[index]; } - void get_impl(const int64_t index, void *r_value) const override + void get_to_uninitialized(const int64_t index, void *r_value) const override { - *(T *)r_value = varray_->get(index); + new (r_value) T(varray_[index]); } - void get_to_uninitialized_impl(const int64_t index, void *r_value) const override + bool is_span() const override { - new (r_value) T(varray_->get(index)); + return varray_.is_span(); } - bool is_span_impl() const override + GSpan get_internal_span() const override { - return varray_->is_span(); + return GSpan(varray_.get_internal_span()); } - GSpan get_internal_span_impl() const override + bool is_single() const override { - return GSpan(varray_->get_internal_span()); + return varray_.is_single(); } - bool is_single_impl() const override + void get_internal_single(void *r_value) const override { - return varray_->is_single(); + *(T *)r_value = varray_.get_internal_single(); } - void get_internal_single_impl(void *r_value) const override + void materialize(const IndexMask mask, void *dst) const override { - *(T *)r_value = varray_->get_internal_single(); + varray_.materialize(mask, MutableSpan((T *)dst, mask.min_array_size())); } - void materialize_impl(const IndexMask mask, void *dst) const override + void materialize_to_uninitialized(const IndexMask mask, void *dst) const override { - varray_->materialize(mask, MutableSpan((T *)dst, mask.min_array_size())); + varray_.materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size())); } - void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const override + bool try_assign_VArray(void *varray) const override { - varray_->materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size())); + *(VArray<T> *)varray = varray_; + return true; } - const void *try_get_internal_varray_impl() const override - { - return varray_; - } -}; - -class GVArray_For_GArray : public GVArray_For_GSpan { - protected: - GArray<> array_; - - public: - GVArray_For_GArray(GArray<> array) : GVArray_For_GSpan(array.as_span()), array_(std::move(array)) + bool may_have_ownership() const override { + return varray_.may_have_ownership(); } }; /* Used to convert any generic virtual array into a typed one. */ -template<typename T> class VArray_For_GVArray : public VArray<T> { +template<typename T> class VArrayImpl_For_GVArray : public VArrayImpl<T> { protected: - const GVArray *varray_ = nullptr; + GVArray varray_; public: - VArray_For_GVArray(const GVArray &varray) : VArray<T>(varray.size()), varray_(&varray) + VArrayImpl_For_GVArray(GVArray varray) : VArrayImpl<T>(varray.size()), varray_(std::move(varray)) { - BLI_assert(varray_->type().template is<T>()); + BLI_assert(varray_); + BLI_assert(varray_.type().template is<T>()); } protected: - VArray_For_GVArray(const int64_t size) : VArray<T>(size) - { - } - - T get_impl(const int64_t index) const override + T get(const int64_t index) const override { T value; - varray_->get(index, &value); + varray_.get(index, &value); return value; } - bool is_span_impl() const override + bool is_span() const override { - return varray_->is_span(); + return varray_.is_span(); } - Span<T> get_internal_span_impl() const override + Span<T> get_internal_span() const override { - return varray_->get_internal_span().template typed<T>(); + return varray_.get_internal_span().template typed<T>(); } - bool is_single_impl() const override + bool is_single() const override { - return varray_->is_single(); + return varray_.is_single(); } - T get_internal_single_impl() const override + T get_internal_single() const override { T value; - varray_->get_internal_single(&value); + varray_.get_internal_single(&value); return value; } -}; - -/* Used to convert an generic mutable virtual array into a typed one. */ -template<typename T> class VMutableArray_For_GVMutableArray : public VMutableArray<T> { - protected: - GVMutableArray *varray_ = nullptr; - - public: - VMutableArray_For_GVMutableArray(GVMutableArray &varray) - : VMutableArray<T>(varray.size()), varray_(&varray) - { - BLI_assert(varray.type().template is<T>()); - } - - VMutableArray_For_GVMutableArray(const int64_t size) : VMutableArray<T>(size) - { - } - - private: - T get_impl(const int64_t index) const override - { - T value; - varray_->get(index, &value); - return value; - } - - void set_impl(const int64_t index, T value) override - { - varray_->set_by_relocate(index, &value); - } - - bool is_span_impl() const override - { - return varray_->is_span(); - } - Span<T> get_internal_span_impl() const override + bool try_assign_GVArray(GVArray &varray) const override { - return varray_->get_internal_span().template typed<T>(); + varray = varray_; + return true; } - bool is_single_impl() const override + bool may_have_ownership() const override { - return varray_->is_single(); - } - - T get_internal_single_impl() const override - { - T value; - varray_->get_internal_single(&value); - return value; + return varray_.may_have_ownership(); } }; /* Used to convert any typed virtual mutable array into a generic one. */ -template<typename T> class GVMutableArray_For_VMutableArray : public GVMutableArray { +template<typename T> class GVMutableArrayImpl_For_VMutableArray : public GVMutableArrayImpl { protected: - VMutableArray<T> *varray_ = nullptr; + VMutableArray<T> varray_; public: - GVMutableArray_For_VMutableArray(VMutableArray<T> &varray) - : GVMutableArray(CPPType::get<T>(), varray.size()), varray_(&varray) + GVMutableArrayImpl_For_VMutableArray(VMutableArray<T> varray) + : GVMutableArrayImpl(CPPType::get<T>(), varray.size()), varray_(std::move(varray)) { } protected: - GVMutableArray_For_VMutableArray(const int64_t size) : GVMutableArray(CPPType::get<T>(), size) + void get(const int64_t index, void *r_value) const override { + *(T *)r_value = varray_[index]; } - void get_impl(const int64_t index, void *r_value) const override + void get_to_uninitialized(const int64_t index, void *r_value) const override { - *(T *)r_value = varray_->get(index); + new (r_value) T(varray_[index]); } - void get_to_uninitialized_impl(const int64_t index, void *r_value) const override + bool is_span() const override { - new (r_value) T(varray_->get(index)); + return varray_.is_span(); } - bool is_span_impl() const override + GSpan get_internal_span() const override { - return varray_->is_span(); - } - - GSpan get_internal_span_impl() const override - { - Span<T> span = varray_->get_internal_span(); + Span<T> span = varray_.get_internal_span(); return span; } - bool is_single_impl() const override + bool is_single() const override { - return varray_->is_single(); + return varray_.is_single(); } - void get_internal_single_impl(void *r_value) const override + void get_internal_single(void *r_value) const override { - *(T *)r_value = varray_->get_internal_single(); + *(T *)r_value = varray_.get_internal_single(); } - void set_by_copy_impl(const int64_t index, const void *value) override + void set_by_copy(const int64_t index, const void *value) override { const T &value_ = *(const T *)value; - varray_->set(index, value_); + varray_.set(index, value_); } - void set_by_relocate_impl(const int64_t index, void *value) override + void set_by_relocate(const int64_t index, void *value) override { T &value_ = *(T *)value; - varray_->set(index, std::move(value_)); + varray_.set(index, std::move(value_)); value_.~T(); } - void set_by_move_impl(const int64_t index, void *value) override + void set_by_move(const int64_t index, void *value) override { T &value_ = *(T *)value; - varray_->set(index, std::move(value_)); + varray_.set(index, std::move(value_)); } - void set_all_impl(const void *src) override + void set_all(const void *src) override { - varray_->set_all(Span((T *)src, size_)); + varray_.set_all(Span((T *)src, size_)); } - void materialize_impl(const IndexMask mask, void *dst) const override + void materialize(const IndexMask mask, void *dst) const override { - varray_->materialize(mask, MutableSpan((T *)dst, mask.min_array_size())); + varray_.materialize(mask, MutableSpan((T *)dst, mask.min_array_size())); } - void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const override + void materialize_to_uninitialized(const IndexMask mask, void *dst) const override { - varray_->materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size())); + varray_.materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size())); } - const void *try_get_internal_varray_impl() const override + bool try_assign_VArray(void *varray) const override { - return (const VArray<T> *)varray_; + *(VArray<T> *)varray = varray_; + return true; } - void *try_get_internal_mutable_varray_impl() override + bool try_assign_VMutableArray(void *varray) const override { - return varray_; + *(VMutableArray<T> *)varray = varray_; + return true; } -}; - -/* A generic version of VArray_Span. */ -class GVArray_GSpan : public GSpan { - private: - const GVArray &varray_; - void *owned_data_ = nullptr; - - public: - GVArray_GSpan(const GVArray &varray); - ~GVArray_GSpan(); -}; - -/* A generic version of VMutableArray_Span. */ -class GVMutableArray_GSpan : public GMutableSpan { - private: - GVMutableArray &varray_; - void *owned_data_ = nullptr; - bool save_has_been_called_ = false; - bool show_not_saved_warning_ = true; - - public: - GVMutableArray_GSpan(GVMutableArray &varray, bool copy_values_to_span = true); - ~GVMutableArray_GSpan(); - - void save(); - void disable_not_applied_warning(); -}; - -/* Similar to GVArray_GSpan, but the resulting span is typed. */ -template<typename T> class GVArray_Span : public Span<T> { - private: - GVArray_GSpan varray_gspan_; - public: - GVArray_Span(const GVArray &varray) : varray_gspan_(varray) + bool may_have_ownership() const override { - BLI_assert(varray.type().is<T>()); - this->data_ = (const T *)varray_gspan_.data(); - this->size_ = varray_gspan_.size(); + return varray_.may_have_ownership(); } }; -template<typename T> class GVArray_For_OwnedVArray : public GVArray_For_VArray<T> { - private: - VArrayPtr<T> owned_varray_; +/* Used to convert an generic mutable virtual array into a typed one. */ +template<typename T> class VMutableArrayImpl_For_GVMutableArray : public VMutableArrayImpl<T> { + protected: + GVMutableArray varray_; public: - /* Takes ownership of varray and passes a reference to the base class. */ - GVArray_For_OwnedVArray(VArrayPtr<T> varray) - : GVArray_For_VArray<T>(*varray), owned_varray_(std::move(varray)) + VMutableArrayImpl_For_GVMutableArray(GVMutableArray varray) + : VMutableArrayImpl<T>(varray.size()), varray_(varray) { + BLI_assert(varray_); + BLI_assert(varray_.type().template is<T>()); } -}; -template<typename T> class VArray_For_OwnedGVArray : public VArray_For_GVArray<T> { private: - GVArrayPtr owned_varray_; - - public: - /* Takes ownership of varray and passes a reference to the base class. */ - VArray_For_OwnedGVArray(GVArrayPtr varray) - : VArray_For_GVArray<T>(*varray), owned_varray_(std::move(varray)) + T get(const int64_t index) const override { + T value; + varray_.get(index, &value); + return value; } -}; -template<typename T> -class GVMutableArray_For_OwnedVMutableArray : public GVMutableArray_For_VMutableArray<T> { - private: - VMutableArrayPtr<T> owned_varray_; - - public: - /* Takes ownership of varray and passes a reference to the base class. */ - GVMutableArray_For_OwnedVMutableArray(VMutableArrayPtr<T> varray) - : GVMutableArray_For_VMutableArray<T>(*varray), owned_varray_(std::move(varray)) + void set(const int64_t index, T value) override { + varray_.set_by_relocate(index, &value); } -}; -template<typename T> -class VMutableArray_For_OwnedGVMutableArray : public VMutableArray_For_GVMutableArray<T> { - private: - GVMutableArrayPtr owned_varray_; - - public: - /* Takes ownership of varray and passes a reference to the base class. */ - VMutableArray_For_OwnedGVMutableArray(GVMutableArrayPtr varray) - : VMutableArray_For_GVMutableArray<T>(*varray), owned_varray_(std::move(varray)) + bool is_span() const override { + return varray_.is_span(); } -}; - -/* Utility to embed a typed virtual array into a generic one. This avoids one allocation and give - * the compiler more opportunity to optimize the generic virtual array. */ -template<typename T, typename VArrayT> -class GVArray_For_EmbeddedVArray : public GVArray_For_VArray<T> { - private: - VArrayT embedded_varray_; - public: - template<typename... Args> - GVArray_For_EmbeddedVArray(const int64_t size, Args &&...args) - : GVArray_For_VArray<T>(size), embedded_varray_(std::forward<Args>(args)...) + Span<T> get_internal_span() const override { - this->varray_ = &embedded_varray_; + return varray_.get_internal_span().template typed<T>(); } -}; -/* Same as GVArray_For_EmbeddedVArray, but for mutable virtual arrays. */ -template<typename T, typename VMutableArrayT> -class GVMutableArray_For_EmbeddedVMutableArray : public GVMutableArray_For_VMutableArray<T> { - private: - VMutableArrayT embedded_varray_; - - public: - template<typename... Args> - GVMutableArray_For_EmbeddedVMutableArray(const int64_t size, Args &&...args) - : GVMutableArray_For_VMutableArray<T>(size), embedded_varray_(std::forward<Args>(args)...) + bool is_single() const override { - this->varray_ = &embedded_varray_; + return varray_.is_single(); } -}; -/* Same as VArray_For_ArrayContainer, but for a generic virtual array. */ -template<typename Container, typename T = typename Container::value_type> -class GVArray_For_ArrayContainer - : public GVArray_For_EmbeddedVArray<T, VArray_For_ArrayContainer<Container, T>> { - public: - GVArray_For_ArrayContainer(Container container) - : GVArray_For_EmbeddedVArray<T, VArray_For_ArrayContainer<Container, T>>( - container.size(), std::move(container)) + T get_internal_single() const override { + T value; + varray_.get_internal_single(&value); + return value; } -}; -/* Same as VArray_For_DerivedSpan, but for a generic virtual array. */ -template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)> -class GVArray_For_DerivedSpan - : public GVArray_For_EmbeddedVArray<ElemT, VArray_For_DerivedSpan<StructT, ElemT, GetFunc>> { - public: - GVArray_For_DerivedSpan(const Span<StructT> data) - : GVArray_For_EmbeddedVArray<ElemT, VArray_For_DerivedSpan<StructT, ElemT, GetFunc>>( - data.size(), data) + bool try_assign_GVArray(GVArray &varray) const override { + varray = varray_; + return true; } -}; -/* Same as VMutableArray_For_DerivedSpan, but for a generic virtual array. */ -template<typename StructT, - typename ElemT, - ElemT (*GetFunc)(const StructT &), - void (*SetFunc)(StructT &, ElemT)> -class GVMutableArray_For_DerivedSpan - : public GVMutableArray_For_EmbeddedVMutableArray< - ElemT, - VMutableArray_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>> { - public: - GVMutableArray_For_DerivedSpan(const MutableSpan<StructT> data) - : GVMutableArray_For_EmbeddedVMutableArray< - ElemT, - VMutableArray_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>>(data.size(), data) + bool try_assign_GVMutableArray(GVMutableArray &varray) const override { + varray = varray_; + return true; } -}; -/* Same as VArray_For_Span, but for a generic virtual array. */ -template<typename T> -class GVArray_For_Span : public GVArray_For_EmbeddedVArray<T, VArray_For_Span<T>> { - public: - GVArray_For_Span(const Span<T> data) - : GVArray_For_EmbeddedVArray<T, VArray_For_Span<T>>(data.size(), data) + bool may_have_ownership() const override { + return varray_.may_have_ownership(); } }; -/* Same as VMutableArray_For_MutableSpan, but for a generic virtual array. */ -template<typename T> -class GVMutableArray_For_MutableSpan - : public GVMutableArray_For_EmbeddedVMutableArray<T, VMutableArray_For_MutableSpan<T>> { +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #GVArrayImpl_For_GSpan and #GVMutableArrayImpl_For_GMutableSpan. + * \{ */ + +class GVArrayImpl_For_GSpan : public GVArrayImpl { + protected: + const void *data_ = nullptr; + const int64_t element_size_; + public: - GVMutableArray_For_MutableSpan(const MutableSpan<T> data) - : GVMutableArray_For_EmbeddedVMutableArray<T, VMutableArray_For_MutableSpan<T>>(data.size(), - data) - { - } + GVArrayImpl_For_GSpan(const GSpan span); + + protected: + GVArrayImpl_For_GSpan(const CPPType &type, const int64_t size); + + void get(const int64_t index, void *r_value) const override; + void get_to_uninitialized(const int64_t index, void *r_value) const override; + + bool is_span() const override; + GSpan get_internal_span() const override; }; -/** - * Utility class to create the "best" typed virtual array for a given generic virtual array. - * In most cases we don't just want to use VArray_For_GVArray, because it adds an additional - * indirection on element-access that can be avoided in many cases (e.g. when the virtual array is - * just a span or single value). - * - * This is not a virtual array itself, but is used to get a virtual array. - */ -template<typename T> class GVArray_Typed { - private: - const VArray<T> *varray_; - /* Of these optional virtual arrays, at most one is constructed at any time. */ - std::optional<VArray_For_Span<T>> varray_span_; - std::optional<VArray_For_Single<T>> varray_single_; - std::optional<VArray_For_GVArray<T>> varray_any_; - GVArrayPtr owned_gvarray_; +class GVMutableArrayImpl_For_GMutableSpan : public GVMutableArrayImpl { + protected: + void *data_ = nullptr; + const int64_t element_size_; public: - explicit GVArray_Typed(const GVArray &gvarray) - { - BLI_assert(gvarray.type().is<T>()); - if (gvarray.is_span()) { - const GSpan span = gvarray.get_internal_span(); - varray_span_.emplace(span.typed<T>()); - varray_ = &*varray_span_; - } - else if (gvarray.is_single()) { - T single_value; - gvarray.get_internal_single(&single_value); - varray_single_.emplace(single_value, gvarray.size()); - varray_ = &*varray_single_; - } - else if (const VArray<T> *internal_varray = gvarray.try_get_internal_varray<T>()) { - varray_ = internal_varray; - } - else { - varray_any_.emplace(gvarray); - varray_ = &*varray_any_; - } - } + GVMutableArrayImpl_For_GMutableSpan(const GMutableSpan span); - /* Same as the constructor above, but also takes ownership of the passed in virtual array. */ - explicit GVArray_Typed(GVArrayPtr gvarray) : GVArray_Typed(*gvarray) - { - owned_gvarray_ = std::move(gvarray); - } + protected: + GVMutableArrayImpl_For_GMutableSpan(const CPPType &type, const int64_t size); - const VArray<T> &operator*() const - { - return *varray_; - } + public: + void get(const int64_t index, void *r_value) const override; + void get_to_uninitialized(const int64_t index, void *r_value) const override; - const VArray<T> *operator->() const - { - return varray_; - } + void set_by_copy(const int64_t index, const void *value) override; + void set_by_move(const int64_t index, void *value) override; + void set_by_relocate(const int64_t index, void *value) override; - /* Support implicit cast to the typed virtual array for convenience when `varray->typed<T>()` is - * used within an expression. */ - operator const VArray<T> &() const - { - return *varray_; - } + bool is_span() const override; + GSpan get_internal_span() const override; +}; - T operator[](const int64_t index) const - { - return varray_->get(index); - } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Inline methods for #GVArrayImpl. + * \{ */ + +inline GVArrayImpl::GVArrayImpl(const CPPType &type, const int64_t size) + : type_(&type), size_(size) +{ + BLI_assert(size_ >= 0); +} + +inline const CPPType &GVArrayImpl::type() const +{ + return *type_; +} + +inline int64_t GVArrayImpl::size() const +{ + return size_; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Inline methods for #GVMutableArrayImpl. + * \{ */ + +inline void GVMutableArray::set_by_copy(const int64_t index, const void *value) +{ + BLI_assert(index >= 0); + BLI_assert(index < this->size()); + this->get_impl()->set_by_copy(index, value); +} + +inline void GVMutableArray::set_by_move(const int64_t index, void *value) +{ + BLI_assert(index >= 0); + BLI_assert(index < this->size()); + this->get_impl()->set_by_move(index, value); +} + +inline void GVMutableArray::set_by_relocate(const int64_t index, void *value) +{ + BLI_assert(index >= 0); + BLI_assert(index < this->size()); + this->get_impl()->set_by_relocate(index, value); +} - int64_t size() const - { - return varray_->size(); +template<typename T> +inline bool GVMutableArray::try_assign_VMutableArray(VMutableArray<T> &varray) const +{ + BLI_assert(impl_->type().is<T>()); + return this->get_impl()->try_assign_VMutableArray(&varray); +} + +inline GVMutableArrayImpl *GVMutableArray::get_impl() const +{ + return (GVMutableArrayImpl *)impl_; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Inline methods for #GVArrayCommon. + * \{ */ + +template<typename ImplT, typename... Args> inline void GVArrayCommon::emplace(Args &&...args) +{ + static_assert(std::is_base_of_v<GVArrayImpl, ImplT>); + if constexpr (std::is_copy_constructible_v<ImplT> && Storage::template is_inline_v<ImplT>) { + impl_ = &storage_.template emplace<ImplT>(std::forward<Args>(args)...); + } + else { + std::shared_ptr<const GVArrayImpl> ptr = std::make_shared<ImplT>(std::forward<Args>(args)...); + impl_ = &*ptr; + storage_ = std::move(ptr); + } +} + +/* Copies the value at the given index into the provided storage. The `r_value` pointer is + * expected to point to initialized memory. */ +inline void GVArrayCommon::get(const int64_t index, void *r_value) const +{ + BLI_assert(index >= 0); + BLI_assert(index < this->size()); + impl_->get(index, r_value); +} + +/* Same as `get`, but `r_value` is expected to point to uninitialized memory. */ +inline void GVArrayCommon::get_to_uninitialized(const int64_t index, void *r_value) const +{ + BLI_assert(index >= 0); + BLI_assert(index < this->size()); + impl_->get_to_uninitialized(index, r_value); +} + +template<typename T> inline bool GVArrayCommon::try_assign_VArray(VArray<T> &varray) const +{ + BLI_assert(impl_->type().is<T>()); + return impl_->try_assign_VArray(&varray); +} + +inline const CPPType &GVArrayCommon::type() const +{ + return impl_->type(); +} + +inline GVArrayCommon::operator bool() const +{ + return impl_ != nullptr; +} + +inline int64_t GVArrayCommon::size() const +{ + if (impl_ == nullptr) { + return 0; + } + return impl_->size(); +} + +inline bool GVArrayCommon::is_empty() const +{ + return this->size() == 0; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Inline methods for #GVArray. + * \{ */ + +namespace detail { +template<typename StorageT> inline GVArrayAnyExtraInfo GVArrayAnyExtraInfo::get() +{ + static_assert(std::is_base_of_v<GVArrayImpl, StorageT> || + std::is_same_v<StorageT, const GVArrayImpl *> || + std::is_same_v<StorageT, std::shared_ptr<const GVArrayImpl>>); + + if constexpr (std::is_base_of_v<GVArrayImpl, StorageT>) { + return {[](const void *buffer) { + return static_cast<const GVArrayImpl *>((const StorageT *)buffer); + }}; + } + else if constexpr (std::is_same_v<StorageT, const GVArrayImpl *>) { + return {[](const void *buffer) { return *(const StorageT *)buffer; }}; + } + else if constexpr (std::is_same_v<StorageT, std::shared_ptr<const GVArrayImpl>>) { + return {[](const void *buffer) { return ((const StorageT *)buffer)->get(); }}; + } + else { + BLI_assert_unreachable(); + return {}; + } +} +} // namespace detail + +template<typename ImplT, typename... Args> inline GVArray GVArray::For(Args &&...args) +{ + static_assert(std::is_base_of_v<GVArrayImpl, ImplT>); + GVArray varray; + varray.template emplace<ImplT>(std::forward<Args>(args)...); + return varray; +} + +template<typename T> inline GVArray::GVArray(const VArray<T> &varray) +{ + if (!varray) { + return; + } + if (varray.try_assign_GVArray(*this)) { + return; + } + /* Need to check this before the span/single special cases, because otherwise we might loose + * ownership to the referenced data when #varray goes out of scope. */ + if (varray.may_have_ownership()) { + *this = GVArray::For<GVArrayImpl_For_VArray<T>>(varray); + } + else if (varray.is_span()) { + Span<T> data = varray.get_internal_span(); + *this = GVArray::ForSpan(data); + } + else if (varray.is_single()) { + T value = varray.get_internal_single(); + *this = GVArray::ForSingle(CPPType::get<T>(), varray.size(), &value); + } + else { + *this = GVArray::For<GVArrayImpl_For_VArray<T>>(varray); + } +} + +template<typename T> inline VArray<T> GVArray::typed() const +{ + if (!*this) { + return {}; + } + BLI_assert(impl_->type().is<T>()); + VArray<T> varray; + if (this->try_assign_VArray(varray)) { + return varray; + } + if (this->may_have_ownership()) { + return VArray<T>::template For<VArrayImpl_For_GVArray<T>>(*this); + } + if (this->is_span()) { + const Span<T> span = this->get_internal_span().typed<T>(); + return VArray<T>::ForSpan(span); } - - IndexRange index_range() const - { - return IndexRange(this->size()); + if (this->is_single()) { + T value; + this->get_internal_single(&value); + return VArray<T>::ForSingle(value, this->size()); } -}; + return VArray<T>::template For<VArrayImpl_For_GVArray<T>>(*this); +} -/* Same as GVArray_Typed, but for mutable virtual arrays. */ -template<typename T> class GVMutableArray_Typed { - private: - VMutableArray<T> *varray_; - std::optional<VMutableArray_For_MutableSpan<T>> varray_span_; - std::optional<VMutableArray_For_GVMutableArray<T>> varray_any_; - GVMutableArrayPtr owned_gvarray_; +/** \} */ - public: - explicit GVMutableArray_Typed(GVMutableArray &gvarray) - { - BLI_assert(gvarray.type().is<T>()); - if (gvarray.is_span()) { - const GMutableSpan span = gvarray.get_internal_span(); - varray_span_.emplace(span.typed<T>()); - varray_ = &*varray_span_; - } - else if (VMutableArray<T> *internal_varray = gvarray.try_get_internal_mutable_varray<T>()) { - varray_ = internal_varray; - } - else { - varray_any_.emplace(gvarray); - varray_ = &*varray_any_; - } - } +/* -------------------------------------------------------------------- */ +/** \name Inline methods for #GVMutableArray. + * \{ */ - explicit GVMutableArray_Typed(GVMutableArrayPtr gvarray) : GVMutableArray_Typed(*gvarray) - { - owned_gvarray_ = std::move(gvarray); - } +template<typename ImplT, typename... Args> +inline GVMutableArray GVMutableArray::For(Args &&...args) +{ + static_assert(std::is_base_of_v<GVMutableArrayImpl, ImplT>); + GVMutableArray varray; + varray.emplace<ImplT>(std::forward<Args>(args)...); + return varray; +} - VMutableArray<T> &operator*() - { - return *varray_; +template<typename T> inline GVMutableArray::GVMutableArray(const VMutableArray<T> &varray) +{ + if (!varray) { + return; } - - VMutableArray<T> *operator->() - { - return varray_; + if (varray.try_assign_GVMutableArray(*this)) { + return; } - - operator VMutableArray<T> &() - { - return *varray_; + if (varray.may_have_ownership()) { + *this = GVMutableArray::For<GVMutableArrayImpl_For_VMutableArray<T>>(varray); } - - T operator[](const int64_t index) const - { - return varray_->get(index); + else if (varray.is_span()) { + MutableSpan<T> data = varray.get_internal_span(); + *this = GVMutableArray::ForSpan(data); } - - int64_t size() const - { - return varray_->size(); + else { + *this = GVMutableArray::For<GVMutableArrayImpl_For_VMutableArray<T>>(varray); } -}; - -class GVArray_For_SlicedGVArray : public GVArray { - protected: - const GVArray &varray_; - int64_t offset_; +} - public: - GVArray_For_SlicedGVArray(const GVArray &varray, const IndexRange slice) - : GVArray(varray.type(), slice.size()), varray_(varray), offset_(slice.start()) - { - BLI_assert(slice.one_after_last() <= varray.size()); +template<typename T> inline VMutableArray<T> GVMutableArray::typed() const +{ + if (!*this) { + return {}; } - - /* TODO: Add #materialize method. */ - void get_impl(const int64_t index, void *r_value) const override; - void get_to_uninitialized_impl(const int64_t index, void *r_value) const override; -}; - -/** - * Utility class to create the "best" sliced virtual array. - */ -class GVArray_Slice { - private: - const GVArray *varray_; - /* Of these optional virtual arrays, at most one is constructed at any time. */ - std::optional<GVArray_For_GSpan> varray_span_; - std::optional<GVArray_For_SlicedGVArray> varray_any_; - - public: - GVArray_Slice(const GVArray &varray, const IndexRange slice); - - const GVArray &operator*() - { - return *varray_; + BLI_assert(this->type().is<T>()); + VMutableArray<T> varray; + if (this->try_assign_VMutableArray(varray)) { + return varray; } - - const GVArray *operator->() - { - return varray_; + if (this->may_have_ownership()) { + return VMutableArray<T>::template For<VMutableArrayImpl_For_GVMutableArray<T>>(*this); } - - operator const GVArray &() - { - return *varray_; + if (this->is_span()) { + const MutableSpan<T> span = this->get_internal_span().typed<T>(); + return VMutableArray<T>::ForSpan(span); } -}; + return VMutableArray<T>::template For<VMutableArrayImpl_For_GVMutableArray<T>>(*this); +} + +/** \} */ } // namespace blender::fn diff --git a/source/blender/functions/FN_generic_virtual_vector_array.hh b/source/blender/functions/FN_generic_virtual_vector_array.hh index 4155a55a801..b80e21eaef1 100644 --- a/source/blender/functions/FN_generic_virtual_vector_array.hh +++ b/source/blender/functions/FN_generic_virtual_vector_array.hh @@ -100,31 +100,31 @@ class GVVectorArray { } }; -class GVArray_For_GVVectorArrayIndex : public GVArray { +class GVArray_For_GVVectorArrayIndex : public GVArrayImpl { private: const GVVectorArray &vector_array_; const int64_t index_; public: GVArray_For_GVVectorArrayIndex(const GVVectorArray &vector_array, const int64_t index) - : GVArray(vector_array.type(), vector_array.get_vector_size(index)), + : GVArrayImpl(vector_array.type(), vector_array.get_vector_size(index)), vector_array_(vector_array), index_(index) { } protected: - void get_impl(const int64_t index_in_vector, void *r_value) const override; - void get_to_uninitialized_impl(const int64_t index_in_vector, void *r_value) const override; + void get(const int64_t index_in_vector, void *r_value) const override; + void get_to_uninitialized(const int64_t index_in_vector, void *r_value) const override; }; class GVVectorArray_For_SingleGVArray : public GVVectorArray { private: - const GVArray &array_; + GVArray varray_; public: - GVVectorArray_For_SingleGVArray(const GVArray &array, const int64_t size) - : GVVectorArray(array.type(), size), array_(array) + GVVectorArray_For_SingleGVArray(GVArray varray, const int64_t size) + : GVVectorArray(varray.type(), size), varray_(std::move(varray)) { } diff --git a/source/blender/functions/FN_multi_function.hh b/source/blender/functions/FN_multi_function.hh index 98788025558..3059fe59ca7 100644 --- a/source/blender/functions/FN_multi_function.hh +++ b/source/blender/functions/FN_multi_function.hh @@ -97,6 +97,8 @@ class MultiFunction { return signature_ref_->function_name; } + virtual std::string debug_name() const; + bool depends_on_context() const { return signature_ref_->depends_on_context; @@ -131,8 +133,6 @@ inline MFParamsBuilder::MFParamsBuilder(const MultiFunction &fn, const IndexMask { } -extern const MultiFunction &dummy_multi_function; - namespace multi_function_types { using fn::CPPType; using fn::GMutableSpan; diff --git a/source/blender/functions/FN_multi_function_builder.hh b/source/blender/functions/FN_multi_function_builder.hh index 0ce05cbca30..eaf9e5ce70f 100644 --- a/source/blender/functions/FN_multi_function_builder.hh +++ b/source/blender/functions/FN_multi_function_builder.hh @@ -43,7 +43,7 @@ template<typename In1, typename Out1> class CustomMF_SI_SO : public MultiFunctio MFSignature signature_; public: - CustomMF_SI_SO(StringRef name, FunctionT function) : function_(std::move(function)) + CustomMF_SI_SO(const char *name, FunctionT function) : function_(std::move(function)) { MFSignatureBuilder signature{name}; signature.single_input<In1>("In1"); @@ -53,7 +53,7 @@ template<typename In1, typename Out1> class CustomMF_SI_SO : public MultiFunctio } template<typename ElementFuncT> - CustomMF_SI_SO(StringRef name, ElementFuncT element_fn) + CustomMF_SI_SO(const char *name, ElementFuncT element_fn) : CustomMF_SI_SO(name, CustomMF_SI_SO::create_function(element_fn)) { } @@ -92,7 +92,7 @@ class CustomMF_SI_SI_SO : public MultiFunction { MFSignature signature_; public: - CustomMF_SI_SI_SO(StringRef name, FunctionT function) : function_(std::move(function)) + CustomMF_SI_SI_SO(const char *name, FunctionT function) : function_(std::move(function)) { MFSignatureBuilder signature{name}; signature.single_input<In1>("In1"); @@ -103,7 +103,7 @@ class CustomMF_SI_SI_SO : public MultiFunction { } template<typename ElementFuncT> - CustomMF_SI_SI_SO(StringRef name, ElementFuncT element_fn) + CustomMF_SI_SI_SO(const char *name, ElementFuncT element_fn) : CustomMF_SI_SI_SO(name, CustomMF_SI_SI_SO::create_function(element_fn)) { } @@ -150,7 +150,7 @@ class CustomMF_SI_SI_SI_SO : public MultiFunction { MFSignature signature_; public: - CustomMF_SI_SI_SI_SO(StringRef name, FunctionT function) : function_(std::move(function)) + CustomMF_SI_SI_SI_SO(const char *name, FunctionT function) : function_(std::move(function)) { MFSignatureBuilder signature{name}; signature.single_input<In1>("In1"); @@ -162,7 +162,7 @@ class CustomMF_SI_SI_SI_SO : public MultiFunction { } template<typename ElementFuncT> - CustomMF_SI_SI_SI_SO(StringRef name, ElementFuncT element_fn) + CustomMF_SI_SI_SI_SO(const char *name, ElementFuncT element_fn) : CustomMF_SI_SI_SI_SO(name, CustomMF_SI_SI_SI_SO::create_function(element_fn)) { } @@ -211,7 +211,7 @@ class CustomMF_SI_SI_SI_SI_SO : public MultiFunction { MFSignature signature_; public: - CustomMF_SI_SI_SI_SI_SO(StringRef name, FunctionT function) : function_(std::move(function)) + CustomMF_SI_SI_SI_SI_SO(const char *name, FunctionT function) : function_(std::move(function)) { MFSignatureBuilder signature{name}; signature.single_input<In1>("In1"); @@ -224,7 +224,7 @@ class CustomMF_SI_SI_SI_SI_SO : public MultiFunction { } template<typename ElementFuncT> - CustomMF_SI_SI_SI_SI_SO(StringRef name, ElementFuncT element_fn) + CustomMF_SI_SI_SI_SI_SO(const char *name, ElementFuncT element_fn) : CustomMF_SI_SI_SI_SI_SO(name, CustomMF_SI_SI_SI_SI_SO::create_function(element_fn)) { } @@ -265,7 +265,7 @@ template<typename Mut1> class CustomMF_SM : public MultiFunction { MFSignature signature_; public: - CustomMF_SM(StringRef name, FunctionT function) : function_(std::move(function)) + CustomMF_SM(const char *name, FunctionT function) : function_(std::move(function)) { MFSignatureBuilder signature{name}; signature.single_mutable<Mut1>("Mut1"); @@ -274,7 +274,7 @@ template<typename Mut1> class CustomMF_SM : public MultiFunction { } template<typename ElementFuncT> - CustomMF_SM(StringRef name, ElementFuncT element_fn) + CustomMF_SM(const char *name, ElementFuncT element_fn) : CustomMF_SM(name, CustomMF_SM::create_function(element_fn)) { } @@ -306,8 +306,8 @@ template<typename From, typename To> class CustomMF_Convert : public MultiFuncti static MFSignature create_signature() { - std::string name = CPPType::get<From>().name() + " to " + CPPType::get<To>().name(); - MFSignatureBuilder signature{std::move(name)}; + static std::string name = CPPType::get<From>().name() + " to " + CPPType::get<To>().name(); + MFSignatureBuilder signature{name.c_str()}; signature.single_input<From>("Input"); signature.single_output<To>("Output"); return signature.build(); @@ -372,9 +372,7 @@ template<typename T> class CustomMF_Constant : public MultiFunction { template<typename U> CustomMF_Constant(U &&value) : value_(std::forward<U>(value)) { MFSignatureBuilder signature{"Constant"}; - std::stringstream ss; - ss << value_; - signature.single_output<T>(ss.str()); + signature.single_output<T>("Value"); signature_ = signature.build(); this->set_signature(&signature_); } @@ -414,9 +412,7 @@ class CustomMF_DefaultOutput : public MultiFunction { MFSignature signature_; public: - CustomMF_DefaultOutput(StringRef name, - Span<MFDataType> input_types, - Span<MFDataType> output_types); + CustomMF_DefaultOutput(Span<MFDataType> input_types, Span<MFDataType> output_types); void call(IndexMask mask, MFParams params, MFContext context) const override; }; @@ -425,7 +421,7 @@ class CustomMF_GenericCopy : public MultiFunction { MFSignature signature_; public: - CustomMF_GenericCopy(StringRef name, MFDataType data_type); + CustomMF_GenericCopy(MFDataType data_type); void call(IndexMask mask, MFParams params, MFContext context) const override; }; diff --git a/source/blender/functions/FN_multi_function_params.hh b/source/blender/functions/FN_multi_function_params.hh index d187985de9d..5c7e75230f3 100644 --- a/source/blender/functions/FN_multi_function_params.hh +++ b/source/blender/functions/FN_multi_function_params.hh @@ -40,7 +40,7 @@ class MFParamsBuilder { const MFSignature *signature_; IndexMask mask_; int64_t min_array_size_; - Vector<const GVArray *> virtual_arrays_; + Vector<GVArray> virtual_arrays_; Vector<GMutableSpan> mutable_spans_; Vector<const GVVectorArray *> virtual_vector_arrays_; Vector<GVectorArray *> vector_arrays_; @@ -68,24 +68,22 @@ class MFParamsBuilder { template<typename T> void add_readonly_single_input(const T *value, StringRef expected_name = "") { this->add_readonly_single_input( - scope_.construct<GVArray_For_SingleValueRef>(CPPType::get<T>(), min_array_size_, value), - expected_name); + GVArray::ForSingleRef(CPPType::get<T>(), min_array_size_, value), expected_name); } void add_readonly_single_input(const GSpan span, StringRef expected_name = "") { - this->add_readonly_single_input(scope_.construct<GVArray_For_GSpan>(span), expected_name); + this->add_readonly_single_input(GVArray::ForSpan(span), expected_name); } void add_readonly_single_input(GPointer value, StringRef expected_name = "") { this->add_readonly_single_input( - scope_.construct<GVArray_For_SingleValueRef>(*value.type(), min_array_size_, value.get()), - expected_name); + GVArray::ForSingleRef(*value.type(), min_array_size_, value.get()), expected_name); } - void add_readonly_single_input(const GVArray &ref, StringRef expected_name = "") + void add_readonly_single_input(GVArray varray, StringRef expected_name = "") { - this->assert_current_param_type(MFParamType::ForSingleInput(ref.type()), expected_name); - BLI_assert(ref.size() >= min_array_size_); - virtual_arrays_.append(&ref); + this->assert_current_param_type(MFParamType::ForSingleInput(varray.type()), expected_name); + BLI_assert(varray.size() >= min_array_size_); + virtual_arrays_.append(varray); } void add_readonly_vector_input(const GVectorArray &vector_array, StringRef expected_name = "") @@ -221,16 +219,16 @@ class MFParams { { } - template<typename T> const VArray<T> &readonly_single_input(int param_index, StringRef name = "") + template<typename T> VArray<T> readonly_single_input(int param_index, StringRef name = "") { - const GVArray &array = this->readonly_single_input(param_index, name); - return builder_->scope_.construct<GVArray_Typed<T>>(array); + const GVArray &varray = this->readonly_single_input(param_index, name); + return varray.typed<T>(); } const GVArray &readonly_single_input(int param_index, StringRef name = "") { this->assert_correct_param(param_index, name, MFParamType::SingleInput); int data_index = builder_->signature_->data_index(param_index); - return *builder_->virtual_arrays_[data_index]; + return builder_->virtual_arrays_[data_index]; } /** diff --git a/source/blender/functions/FN_multi_function_procedure_executor.hh b/source/blender/functions/FN_multi_function_procedure_executor.hh index 9c8b59739b8..b12e3a91210 100644 --- a/source/blender/functions/FN_multi_function_procedure_executor.hh +++ b/source/blender/functions/FN_multi_function_procedure_executor.hh @@ -31,7 +31,7 @@ class MFProcedureExecutor : public MultiFunction { const MFProcedure &procedure_; public: - MFProcedureExecutor(std::string name, const MFProcedure &procedure); + MFProcedureExecutor(const MFProcedure &procedure); void call(IndexMask mask, MFParams params, MFContext context) const override; }; diff --git a/source/blender/functions/FN_multi_function_signature.hh b/source/blender/functions/FN_multi_function_signature.hh index d05948cc645..3c991bc9c56 100644 --- a/source/blender/functions/FN_multi_function_signature.hh +++ b/source/blender/functions/FN_multi_function_signature.hh @@ -30,8 +30,15 @@ namespace blender::fn { struct MFSignature { - std::string function_name; - Vector<std::string> param_names; + /** + * The name should be statically allocated so that it lives longer than this signature. This is + * used instead of an #std::string because of the overhead when many functions are created. + * If the name of the function has to be more dynamic for debugging purposes, override + * #MultiFunction::debug_name() instead. Then the dynamic name will only be computed when it is + * actually needed. + */ + const char *function_name; + Vector<const char *> param_names; Vector<MFParamType> param_types; Vector<int> param_data_indices; bool depends_on_context = false; @@ -51,9 +58,9 @@ class MFSignatureBuilder { int vector_array_count_ = 0; public: - MFSignatureBuilder(std::string function_name) + MFSignatureBuilder(const char *function_name) { - signature_.function_name = std::move(function_name); + signature_.function_name = function_name; } MFSignature build() const @@ -63,23 +70,23 @@ class MFSignatureBuilder { /* Input Parameter Types */ - template<typename T> void single_input(StringRef name) + template<typename T> void single_input(const char *name) { this->single_input(name, CPPType::get<T>()); } - void single_input(StringRef name, const CPPType &type) + void single_input(const char *name, const CPPType &type) { this->input(name, MFDataType::ForSingle(type)); } - template<typename T> void vector_input(StringRef name) + template<typename T> void vector_input(const char *name) { this->vector_input(name, CPPType::get<T>()); } - void vector_input(StringRef name, const CPPType &base_type) + void vector_input(const char *name, const CPPType &base_type) { this->input(name, MFDataType::ForVector(base_type)); } - void input(StringRef name, MFDataType data_type) + void input(const char *name, MFDataType data_type) { signature_.param_names.append(name); signature_.param_types.append(MFParamType(MFParamType::Input, data_type)); @@ -96,23 +103,23 @@ class MFSignatureBuilder { /* Output Parameter Types */ - template<typename T> void single_output(StringRef name) + template<typename T> void single_output(const char *name) { this->single_output(name, CPPType::get<T>()); } - void single_output(StringRef name, const CPPType &type) + void single_output(const char *name, const CPPType &type) { this->output(name, MFDataType::ForSingle(type)); } - template<typename T> void vector_output(StringRef name) + template<typename T> void vector_output(const char *name) { this->vector_output(name, CPPType::get<T>()); } - void vector_output(StringRef name, const CPPType &base_type) + void vector_output(const char *name, const CPPType &base_type) { this->output(name, MFDataType::ForVector(base_type)); } - void output(StringRef name, MFDataType data_type) + void output(const char *name, MFDataType data_type) { signature_.param_names.append(name); signature_.param_types.append(MFParamType(MFParamType::Output, data_type)); @@ -129,23 +136,23 @@ class MFSignatureBuilder { /* Mutable Parameter Types */ - template<typename T> void single_mutable(StringRef name) + template<typename T> void single_mutable(const char *name) { this->single_mutable(name, CPPType::get<T>()); } - void single_mutable(StringRef name, const CPPType &type) + void single_mutable(const char *name, const CPPType &type) { this->mutable_(name, MFDataType::ForSingle(type)); } - template<typename T> void vector_mutable(StringRef name) + template<typename T> void vector_mutable(const char *name) { this->vector_mutable(name, CPPType::get<T>()); } - void vector_mutable(StringRef name, const CPPType &base_type) + void vector_mutable(const char *name, const CPPType &base_type) { this->mutable_(name, MFDataType::ForVector(base_type)); } - void mutable_(StringRef name, MFDataType data_type) + void mutable_(const char *name, MFDataType data_type) { signature_.param_names.append(name); signature_.param_types.append(MFParamType(MFParamType::Mutable, data_type)); @@ -160,7 +167,7 @@ class MFSignatureBuilder { } } - void add(StringRef name, const MFParamType ¶m_type) + void add(const char *name, const MFParamType ¶m_type) { switch (param_type.interface_type()) { case MFParamType::Input: diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc index 4de5e71c910..91b1bdfd8f0 100644 --- a/source/blender/functions/intern/field.cc +++ b/source/blender/functions/intern/field.cc @@ -81,19 +81,18 @@ static FieldTreeInfo preprocess_field_tree(Span<GFieldRef> entry_fields) /** * Retrieves the data from the context that is passed as input into the field. */ -static Vector<const GVArray *> get_field_context_inputs( +static Vector<GVArray> get_field_context_inputs( ResourceScope &scope, const IndexMask mask, const FieldContext &context, const Span<std::reference_wrapper<const FieldInput>> field_inputs) { - Vector<const GVArray *> field_context_inputs; + Vector<GVArray> field_context_inputs; for (const FieldInput &field_input : field_inputs) { - const GVArray *varray = context.get_varray_for_input(field_input, mask, scope); - if (varray == nullptr) { + GVArray varray = context.get_varray_for_input(field_input, mask, scope); + if (!varray) { const CPPType &type = field_input.cpp_type(); - varray = &scope.construct<GVArray_For_SingleValueRef>( - type, mask.min_array_size(), type.default_value()); + varray = GVArray::ForSingleDefault(type, mask.min_array_size()); } field_context_inputs.append(varray); } @@ -105,7 +104,7 @@ static Vector<const GVArray *> get_field_context_inputs( * for different indices. */ static Set<GFieldRef> find_varying_fields(const FieldTreeInfo &field_tree_info, - Span<const GVArray *> field_context_inputs) + Span<GVArray> field_context_inputs) { Set<GFieldRef> found_fields; Stack<GFieldRef> fields_to_check; @@ -114,8 +113,8 @@ static Set<GFieldRef> find_varying_fields(const FieldTreeInfo &field_tree_info, * start the tree search at the non-constant input fields and traverse through all fields that * depend on them. */ for (const int i : field_context_inputs.index_range()) { - const GVArray *varray = field_context_inputs[i]; - if (varray->is_single()) { + const GVArray &varray = field_context_inputs[i]; + if (varray.is_single()) { continue; } const FieldInput &field_input = field_tree_info.deduplicated_field_inputs[i]; @@ -238,8 +237,7 @@ static void build_multi_function_procedure_for_fields(MFProcedure &procedure, if (!already_output_variables.add(variable)) { /* One variable can be output at most once. To output the same value twice, we have to make * a copy first. */ - const MultiFunction ©_fn = scope.construct<CustomMF_GenericCopy>("copy", - variable->data_type()); + const MultiFunction ©_fn = scope.construct<CustomMF_GenericCopy>(variable->data_type()); variable = builder.add_call<1>(copy_fn, {variable})[0]; } builder.add_output_parameter(*variable); @@ -278,29 +276,42 @@ static void build_multi_function_procedure_for_fields(MFProcedure &procedure, * \return The computed virtual arrays for each provided field. If #dst_varrays is passed, the * provided virtual arrays are returned. */ -Vector<const GVArray *> evaluate_fields(ResourceScope &scope, - Span<GFieldRef> fields_to_evaluate, - IndexMask mask, - const FieldContext &context, - Span<GVMutableArray *> dst_varrays) +Vector<GVArray> evaluate_fields(ResourceScope &scope, + Span<GFieldRef> fields_to_evaluate, + IndexMask mask, + const FieldContext &context, + Span<GVMutableArray> dst_varrays) { - Vector<const GVArray *> r_varrays(fields_to_evaluate.size(), nullptr); + Vector<GVArray> r_varrays(fields_to_evaluate.size()); + Array<bool> is_output_written_to_dst(fields_to_evaluate.size(), false); const int array_size = mask.min_array_size(); + if (mask.is_empty()) { + for (const int i : fields_to_evaluate.index_range()) { + const CPPType &type = fields_to_evaluate[i].cpp_type(); + r_varrays[i] = GVArray::ForEmpty(type); + } + return r_varrays; + } + /* Destination arrays are optional. Create a small utility method to access them. */ - auto get_dst_varray_if_available = [&](int index) -> GVMutableArray * { + auto get_dst_varray = [&](int index) -> GVMutableArray { if (dst_varrays.is_empty()) { - return nullptr; + return {}; + } + const GVMutableArray &varray = dst_varrays[index]; + if (!varray) { + return {}; } - BLI_assert(dst_varrays[index] == nullptr || dst_varrays[index]->size() >= array_size); - return dst_varrays[index]; + BLI_assert(varray.size() >= array_size); + return varray; }; /* Traverse the field tree and prepare some data that is used in later steps. */ FieldTreeInfo field_tree_info = preprocess_field_tree(fields_to_evaluate); /* Get inputs that will be passed into the field when evaluated. */ - Vector<const GVArray *> field_context_inputs = get_field_context_inputs( + Vector<GVArray> field_context_inputs = get_field_context_inputs( scope, mask, context, field_tree_info.deduplicated_field_inputs); /* Finish fields that output an input varray directly. For those we don't have to do any further @@ -312,7 +323,7 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, } const FieldInput &field_input = static_cast<const FieldInput &>(field.node()); const int field_input_index = field_tree_info.deduplicated_field_inputs.index_of(field_input); - const GVArray *varray = field_context_inputs[field_input_index]; + const GVArray &varray = field_context_inputs[field_input_index]; r_varrays[out_index] = varray; } @@ -325,7 +336,7 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, Vector<GFieldRef> constant_fields_to_evaluate; Vector<int> constant_field_indices; for (const int i : fields_to_evaluate.index_range()) { - if (r_varrays[i] != nullptr) { + if (r_varrays[i]) { /* Already done. */ continue; } @@ -346,7 +357,7 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, MFProcedure procedure; build_multi_function_procedure_for_fields( procedure, scope, field_tree_info, varying_fields_to_evaluate); - MFProcedureExecutor procedure_executor{"Procedure", procedure}; + MFProcedureExecutor procedure_executor{procedure}; /* Add multi threading capabilities to the field evaluation. */ const int grain_size = 10000; fn::ParallelMultiFunction parallel_procedure_executor{procedure_executor, grain_size}; @@ -357,8 +368,8 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, MFContextBuilder mf_context; /* Provide inputs to the procedure executor. */ - for (const GVArray *varray : field_context_inputs) { - mf_params.add_readonly_single_input(*varray); + for (const GVArray &varray : field_context_inputs) { + mf_params.add_readonly_single_input(varray); } for (const int i : varying_fields_to_evaluate.index_range()) { @@ -367,9 +378,9 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, const int out_index = varying_field_indices[i]; /* Try to get an existing virtual array that the result should be written into. */ - GVMutableArray *output_varray = get_dst_varray_if_available(out_index); + GVMutableArray dst_varray = get_dst_varray(out_index); void *buffer; - if (output_varray == nullptr || !output_varray->is_span()) { + if (!dst_varray || !dst_varray.is_span()) { /* Allocate a new buffer for the computed result. */ buffer = scope.linear_allocator().allocate(type.size() * array_size, type.alignment()); @@ -379,14 +390,14 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, [buffer, mask, &type]() { type.destruct_indices(buffer, mask); }); } - r_varrays[out_index] = &scope.construct<GVArray_For_GSpan>( - GSpan{type, buffer, array_size}); + r_varrays[out_index] = GVArray::ForSpan({type, buffer, array_size}); } else { /* Write the result into the existing span. */ - buffer = output_varray->get_internal_span().data(); + buffer = dst_varray.get_internal_span().data(); - r_varrays[out_index] = output_varray; + r_varrays[out_index] = dst_varray; + is_output_written_to_dst[out_index] = true; } /* Pass output buffer to the procedure executor. */ @@ -403,16 +414,13 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, MFProcedure procedure; build_multi_function_procedure_for_fields( procedure, scope, field_tree_info, constant_fields_to_evaluate); - MFProcedureExecutor procedure_executor{"Procedure", procedure}; - /* Run the code below even when the mask is empty, so that outputs are properly prepared. - * Higher level code can detect this as well and just skip evaluating the field. */ - const int mask_size = mask.is_empty() ? 0 : 1; - MFParamsBuilder mf_params{procedure_executor, mask_size}; + MFProcedureExecutor procedure_executor{procedure}; + MFParamsBuilder mf_params{procedure_executor, 1}; MFContextBuilder mf_context; /* Provide inputs to the procedure executor. */ - for (const GVArray *varray : field_context_inputs) { - mf_params.add_readonly_single_input(*varray); + for (const GVArray &varray : field_context_inputs) { + mf_params.add_readonly_single_input(varray); } for (const int i : constant_fields_to_evaluate.index_range()) { @@ -421,55 +429,52 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, /* Allocate memory where the computed value will be stored in. */ void *buffer = scope.linear_allocator().allocate(type.size(), type.alignment()); - if (!type.is_trivially_destructible() && mask_size > 0) { - BLI_assert(mask_size == 1); + if (!type.is_trivially_destructible()) { /* Destruct value in the end. */ scope.add_destruct_call([buffer, &type]() { type.destruct(buffer); }); } /* Pass output buffer to the procedure executor. */ - mf_params.add_uninitialized_single_output({type, buffer, mask_size}); + mf_params.add_uninitialized_single_output({type, buffer, 1}); /* Create virtual array that can be used after the procedure has been executed below. */ const int out_index = constant_field_indices[i]; - r_varrays[out_index] = &scope.construct<GVArray_For_SingleValueRef>( - type, array_size, buffer); + r_varrays[out_index] = GVArray::ForSingleRef(type, array_size, buffer); } - procedure_executor.call(IndexRange(mask_size), mf_params, mf_context); + procedure_executor.call(IndexRange(1), mf_params, mf_context); } - /* Copy data to supplied destination arrays if necessary. In some cases the evaluation above has - * written the computed data in the right place already. */ + /* Copy data to supplied destination arrays if necessary. In some cases the evaluation above + * has written the computed data in the right place already. */ if (!dst_varrays.is_empty()) { for (const int out_index : fields_to_evaluate.index_range()) { - GVMutableArray *output_varray = get_dst_varray_if_available(out_index); - if (output_varray == nullptr) { + GVMutableArray dst_varray = get_dst_varray(out_index); + if (!dst_varray) { /* Caller did not provide a destination for this output. */ continue; } - const GVArray *computed_varray = r_varrays[out_index]; - BLI_assert(computed_varray->type() == output_varray->type()); - if (output_varray == computed_varray) { + const GVArray &computed_varray = r_varrays[out_index]; + BLI_assert(computed_varray.type() == dst_varray.type()); + if (is_output_written_to_dst[out_index]) { /* The result has been written into the destination provided by the caller already. */ continue; } /* Still have to copy over the data in the destination provided by the caller. */ - if (output_varray->is_span()) { + if (dst_varray.is_span()) { /* Materialize into a span. */ - computed_varray->materialize_to_uninitialized(mask, - output_varray->get_internal_span().data()); + computed_varray.materialize_to_uninitialized(mask, dst_varray.get_internal_span().data()); } else { /* Slower materialize into a different structure. */ - const CPPType &type = computed_varray->type(); + const CPPType &type = computed_varray.type(); BUFFER_FOR_CPP_TYPE_VALUE(type, buffer); for (const int i : mask) { - computed_varray->get_to_uninitialized(i, buffer); - output_varray->set_by_relocate(i, buffer); + computed_varray.get_to_uninitialized(i, buffer); + dst_varray.set_by_relocate(i, buffer); } } - r_varrays[out_index] = output_varray; + r_varrays[out_index] = dst_varray; } } return r_varrays; @@ -485,8 +490,8 @@ void evaluate_constant_field(const GField &field, void *r_value) ResourceScope scope; FieldContext context; - Vector<const GVArray *> varrays = evaluate_fields(scope, {field}, IndexRange(1), context); - varrays[0]->get_to_uninitialized(0, r_value); + Vector<GVArray> varrays = evaluate_fields(scope, {field}, IndexRange(1), context); + varrays[0].get_to_uninitialized(0, r_value); } /** @@ -512,9 +517,9 @@ GField make_field_constant_if_possible(GField field) return GField{operation, 0}; } -const GVArray *FieldContext::get_varray_for_input(const FieldInput &field_input, - IndexMask mask, - ResourceScope &scope) const +GVArray FieldContext::get_varray_for_input(const FieldInput &field_input, + IndexMask mask, + ResourceScope &scope) const { /* By default ask the field input to create the varray. Another field context might overwrite * the context here. */ @@ -526,17 +531,15 @@ IndexFieldInput::IndexFieldInput() : FieldInput(CPPType::get<int>(), "Index") category_ = Category::Generated; } -GVArray *IndexFieldInput::get_index_varray(IndexMask mask, ResourceScope &scope) +GVArray IndexFieldInput::get_index_varray(IndexMask mask, ResourceScope &UNUSED(scope)) { auto index_func = [](int i) { return i; }; - return &scope.construct< - fn::GVArray_For_EmbeddedVArray<int, VArray_For_Func<int, decltype(index_func)>>>( - mask.min_array_size(), mask.min_array_size(), index_func); + return VArray<int>::ForFunc(mask.min_array_size(), index_func); } -const GVArray *IndexFieldInput::get_varray_for_context(const fn::FieldContext &UNUSED(context), - IndexMask mask, - ResourceScope &scope) const +GVArray IndexFieldInput::get_varray_for_context(const fn::FieldContext &UNUSED(context), + IndexMask mask, + ResourceScope &scope) const { /* TODO: Investigate a similar method to IndexRange::as_span() */ return get_index_varray(mask, scope); @@ -631,27 +634,26 @@ static Vector<int64_t> indices_from_selection(const VArray<bool> &selection) return indices; } -int FieldEvaluator::add_with_destination(GField field, GVMutableArray &dst) +int FieldEvaluator::add_with_destination(GField field, GVMutableArray dst) { const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field)); - dst_varrays_.append(&dst); + dst_varrays_.append(dst); output_pointer_infos_.append({}); return field_index; } int FieldEvaluator::add_with_destination(GField field, GMutableSpan dst) { - GVMutableArray &varray = scope_.construct<GVMutableArray_For_GMutableSpan>(dst); - return this->add_with_destination(std::move(field), varray); + return this->add_with_destination(std::move(field), GVMutableArray::ForSpan(dst)); } -int FieldEvaluator::add(GField field, const GVArray **varray_ptr) +int FieldEvaluator::add(GField field, GVArray *varray_ptr) { const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field)); dst_varrays_.append(nullptr); output_pointer_infos_.append(OutputPointerInfo{ varray_ptr, [](void *dst, const GVArray &varray, ResourceScope &UNUSED(scope)) { - *(const GVArray **)dst = &varray; + *(GVArray *)dst = varray; }}); return field_index; } @@ -676,7 +678,7 @@ void FieldEvaluator::evaluate() for (const int i : fields_to_evaluate_.index_range()) { OutputPointerInfo &info = output_pointer_infos_[i]; if (info.dst != nullptr) { - info.set(info.dst, *evaluated_varrays_[i], scope_); + info.set(info.dst, evaluated_varrays_[i], scope_); } } is_evaluated_ = true; @@ -684,17 +686,16 @@ void FieldEvaluator::evaluate() IndexMask FieldEvaluator::get_evaluated_as_mask(const int field_index) { - const GVArray &varray = this->get_evaluated(field_index); - GVArray_Typed<bool> typed_varray{varray}; + VArray<bool> varray = this->get_evaluated(field_index).typed<bool>(); - if (typed_varray->is_single()) { - if (typed_varray->get_internal_single()) { - return IndexRange(typed_varray.size()); + if (varray.is_single()) { + if (varray.get_internal_single()) { + return IndexRange(varray.size()); } return IndexRange(0); } - return scope_.add_value(indices_from_selection(*typed_varray)).as_span(); + return scope_.add_value(indices_from_selection(varray)).as_span(); } } // namespace blender::fn diff --git a/source/blender/functions/intern/generic_vector_array.cc b/source/blender/functions/intern/generic_vector_array.cc index ec95a283919..0d478007a5a 100644 --- a/source/blender/functions/intern/generic_vector_array.cc +++ b/source/blender/functions/intern/generic_vector_array.cc @@ -60,15 +60,14 @@ void GVectorArray::extend(const int64_t index, const GVArray &values) void GVectorArray::extend(const int64_t index, const GSpan values) { - GVArray_For_GSpan varray{values}; - this->extend(index, varray); + this->extend(index, GVArray::ForSpan(values)); } void GVectorArray::extend(IndexMask mask, const GVVectorArray &values) { for (const int i : mask) { GVArray_For_GVVectorArrayIndex array{values, i}; - this->extend(i, array); + this->extend(i, GVArray(&array)); } } diff --git a/source/blender/functions/intern/generic_virtual_array.cc b/source/blender/functions/intern/generic_virtual_array.cc index ea54f1e7c00..1fe1c2fc229 100644 --- a/source/blender/functions/intern/generic_virtual_array.cc +++ b/source/blender/functions/intern/generic_virtual_array.cc @@ -19,52 +19,10 @@ namespace blender::fn { /* -------------------------------------------------------------------- */ -/** \name #GVArray_For_ShallowCopy +/** \name #GVArrayImpl * \{ */ -class GVArray_For_ShallowCopy : public GVArray { - private: - const GVArray &varray_; - - public: - GVArray_For_ShallowCopy(const GVArray &varray) - : GVArray(varray.type(), varray.size()), varray_(varray) - { - } - - private: - void get_impl(const int64_t index, void *r_value) const override - { - varray_.get(index, r_value); - } - - void get_to_uninitialized_impl(const int64_t index, void *r_value) const override - { - varray_.get_to_uninitialized(index, r_value); - } - - void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const override - { - varray_.materialize_to_uninitialized(mask, dst); - } -}; -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name #GVArray - * \{ */ - -void GVArray::materialize(void *dst) const -{ - this->materialize(IndexMask(size_), dst); -} - -void GVArray::materialize(const IndexMask mask, void *dst) const -{ - this->materialize_impl(mask, dst); -} - -void GVArray::materialize_impl(const IndexMask mask, void *dst) const +void GVArrayImpl::materialize(const IndexMask mask, void *dst) const { for (const int64_t i : mask) { void *elem_dst = POINTER_OFFSET(dst, type_->size() * i); @@ -72,18 +30,7 @@ void GVArray::materialize_impl(const IndexMask mask, void *dst) const } } -void GVArray::materialize_to_uninitialized(void *dst) const -{ - this->materialize_to_uninitialized(IndexMask(size_), dst); -} - -void GVArray::materialize_to_uninitialized(const IndexMask mask, void *dst) const -{ - BLI_assert(mask.min_array_size() <= size_); - this->materialize_to_uninitialized_impl(mask, dst); -} - -void GVArray::materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const +void GVArrayImpl::materialize_to_uninitialized(const IndexMask mask, void *dst) const { for (const int64_t i : mask) { void *elem_dst = POINTER_OFFSET(dst, type_->size() * i); @@ -91,83 +38,75 @@ void GVArray::materialize_to_uninitialized_impl(const IndexMask mask, void *dst) } } -void GVArray::get_impl(const int64_t index, void *r_value) const +void GVArrayImpl::get(const int64_t index, void *r_value) const { type_->destruct(r_value); - this->get_to_uninitialized_impl(index, r_value); + this->get_to_uninitialized(index, r_value); } -bool GVArray::is_span_impl() const +bool GVArrayImpl::is_span() const { return false; } -GSpan GVArray::get_internal_span_impl() const +GSpan GVArrayImpl::get_internal_span() const { BLI_assert(false); return GSpan(*type_); } -bool GVArray::is_single_impl() const +bool GVArrayImpl::is_single() const { return false; } -void GVArray::get_internal_single_impl(void *UNUSED(r_value)) const +void GVArrayImpl::get_internal_single(void *UNUSED(r_value)) const { BLI_assert(false); } -const void *GVArray::try_get_internal_varray_impl() const +bool GVArrayImpl::try_assign_VArray(void *UNUSED(varray)) const { - return nullptr; + return false; } -/** - * Creates a new `std::unique_ptr<GVArray>` based on this `GVArray`. - * The lifetime of the returned virtual array must not be longer than the lifetime of this virtual - * array. - */ -GVArrayPtr GVArray::shallow_copy() const +bool GVArrayImpl::may_have_ownership() const { - if (this->is_span()) { - return std::make_unique<GVArray_For_GSpan>(this->get_internal_span()); - } - if (this->is_single()) { - BUFFER_FOR_CPP_TYPE_VALUE(*type_, buffer); - this->get_internal_single(buffer); - std::unique_ptr new_varray = std::make_unique<GVArray_For_SingleValue>(*type_, size_, buffer); - type_->destruct(buffer); - return new_varray; - } - return std::make_unique<GVArray_For_ShallowCopy>(*this); + /* Use true as default to avoid accidentally creating subclasses that have this set to false but + * actually own data. Subclasses should set the to false instead. */ + return true; } /** \} */ /* -------------------------------------------------------------------- */ -/** \name #GVMutableArray +/** \name #GVMutableArrayImpl * \{ */ -void GVMutableArray::set_by_copy_impl(const int64_t index, const void *value) +GVMutableArrayImpl::GVMutableArrayImpl(const CPPType &type, const int64_t size) + : GVArrayImpl(type, size) +{ +} + +void GVMutableArrayImpl::set_by_copy(const int64_t index, const void *value) { BUFFER_FOR_CPP_TYPE_VALUE(*type_, buffer); type_->copy_construct(value, buffer); - this->set_by_move_impl(index, buffer); + this->set_by_move(index, buffer); type_->destruct(buffer); } -void GVMutableArray::set_by_relocate_impl(const int64_t index, void *value) +void GVMutableArrayImpl::set_by_relocate(const int64_t index, void *value) { - this->set_by_move_impl(index, value); + this->set_by_move(index, value); type_->destruct(value); } -void GVMutableArray::set_all_impl(const void *src) +void GVMutableArrayImpl::set_all(const void *src) { if (this->is_span()) { - const GMutableSpan span = this->get_internal_span(); - type_->copy_assign_n(src, span.data(), size_); + const GSpan span = this->get_internal_span(); + type_->copy_assign_n(src, const_cast<void *>(span.data()), size_); } else { for (int64_t i : IndexRange(size_)) { @@ -176,149 +115,224 @@ void GVMutableArray::set_all_impl(const void *src) } } -void *GVMutableArray::try_get_internal_mutable_varray_impl() -{ - return nullptr; -} - void GVMutableArray::fill(const void *value) { if (this->is_span()) { - const GMutableSpan span = this->get_internal_span(); - type_->fill_assign_n(value, span.data(), size_); + const GSpan span = this->get_internal_span(); + this->type().fill_assign_n(value, const_cast<void *>(span.data()), this->size()); } else { - for (int64_t i : IndexRange(size_)) { + for (int64_t i : IndexRange(this->size())) { this->set_by_copy(i, value); } } } +bool GVMutableArrayImpl::try_assign_VMutableArray(void *UNUSED(varray)) const +{ + return false; +} + /** \} */ /* -------------------------------------------------------------------- */ -/** \name #GVArray_For_GSpan +/** \name #GVArrayImpl_For_GSpan * \{ */ -void GVArray_For_GSpan::get_impl(const int64_t index, void *r_value) const +GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan(const GSpan span) + : GVArrayImpl(span.type(), span.size()), data_(span.data()), element_size_(span.type().size()) +{ +} + +GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan(const CPPType &type, const int64_t size) + : GVArrayImpl(type, size), element_size_(type.size()) +{ +} + +void GVArrayImpl_For_GSpan::get(const int64_t index, void *r_value) const { type_->copy_assign(POINTER_OFFSET(data_, element_size_ * index), r_value); } -void GVArray_For_GSpan::get_to_uninitialized_impl(const int64_t index, void *r_value) const +void GVArrayImpl_For_GSpan::get_to_uninitialized(const int64_t index, void *r_value) const { type_->copy_construct(POINTER_OFFSET(data_, element_size_ * index), r_value); } -bool GVArray_For_GSpan::is_span_impl() const +bool GVArrayImpl_For_GSpan::is_span() const { return true; } -GSpan GVArray_For_GSpan::get_internal_span_impl() const +GSpan GVArrayImpl_For_GSpan::get_internal_span() const { return GSpan(*type_, data_, size_); } +/** See #VArrayImpl_For_Span_final. */ +class GVArrayImpl_For_GSpan_final final : public GVArrayImpl_For_GSpan { + public: + using GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan; + + private: + bool may_have_ownership() const override + { + return false; + } +}; + /** \} */ /* -------------------------------------------------------------------- */ -/** \name #GVMutableArray_For_GMutableSpan +/** \name #GVMutableArrayImpl_For_GMutableSpan * \{ */ -void GVMutableArray_For_GMutableSpan::get_impl(const int64_t index, void *r_value) const +GVMutableArrayImpl_For_GMutableSpan::GVMutableArrayImpl_For_GMutableSpan(const GMutableSpan span) + : GVMutableArrayImpl(span.type(), span.size()), + data_(span.data()), + element_size_(span.type().size()) +{ +} + +GVMutableArrayImpl_For_GMutableSpan::GVMutableArrayImpl_For_GMutableSpan(const CPPType &type, + const int64_t size) + : GVMutableArrayImpl(type, size), element_size_(type.size()) +{ +} + +void GVMutableArrayImpl_For_GMutableSpan::get(const int64_t index, void *r_value) const { type_->copy_assign(POINTER_OFFSET(data_, element_size_ * index), r_value); } -void GVMutableArray_For_GMutableSpan::get_to_uninitialized_impl(const int64_t index, - void *r_value) const +void GVMutableArrayImpl_For_GMutableSpan::get_to_uninitialized(const int64_t index, + void *r_value) const { type_->copy_construct(POINTER_OFFSET(data_, element_size_ * index), r_value); } -void GVMutableArray_For_GMutableSpan::set_by_copy_impl(const int64_t index, const void *value) +void GVMutableArrayImpl_For_GMutableSpan::set_by_copy(const int64_t index, const void *value) { type_->copy_assign(value, POINTER_OFFSET(data_, element_size_ * index)); } -void GVMutableArray_For_GMutableSpan::set_by_move_impl(const int64_t index, void *value) +void GVMutableArrayImpl_For_GMutableSpan::set_by_move(const int64_t index, void *value) { type_->move_construct(value, POINTER_OFFSET(data_, element_size_ * index)); } -void GVMutableArray_For_GMutableSpan::set_by_relocate_impl(const int64_t index, void *value) +void GVMutableArrayImpl_For_GMutableSpan::set_by_relocate(const int64_t index, void *value) { type_->relocate_assign(value, POINTER_OFFSET(data_, element_size_ * index)); } -bool GVMutableArray_For_GMutableSpan::is_span_impl() const +bool GVMutableArrayImpl_For_GMutableSpan::is_span() const { return true; } -GSpan GVMutableArray_For_GMutableSpan::get_internal_span_impl() const +GSpan GVMutableArrayImpl_For_GMutableSpan::get_internal_span() const { return GSpan(*type_, data_, size_); } +class GVMutableArrayImpl_For_GMutableSpan_final final + : public GVMutableArrayImpl_For_GMutableSpan { + public: + using GVMutableArrayImpl_For_GMutableSpan::GVMutableArrayImpl_For_GMutableSpan; + + private: + bool may_have_ownership() const override + { + return false; + } +}; + /** \} */ /* -------------------------------------------------------------------- */ -/** \name #GVArray_For_SingleValueRef +/** \name #GVArrayImpl_For_SingleValueRef * \{ */ -void GVArray_For_SingleValueRef::get_impl(const int64_t UNUSED(index), void *r_value) const -{ - type_->copy_assign(value_, r_value); -} +/* Generic virtual array where each element has the same value. The value is not owned. */ +class GVArrayImpl_For_SingleValueRef : public GVArrayImpl { + protected: + const void *value_ = nullptr; -void GVArray_For_SingleValueRef::get_to_uninitialized_impl(const int64_t UNUSED(index), - void *r_value) const -{ - type_->copy_construct(value_, r_value); -} + public: + GVArrayImpl_For_SingleValueRef(const CPPType &type, const int64_t size, const void *value) + : GVArrayImpl(type, size), value_(value) + { + } -bool GVArray_For_SingleValueRef::is_span_impl() const -{ - return size_ == 1; -} + protected: + GVArrayImpl_For_SingleValueRef(const CPPType &type, const int64_t size) : GVArrayImpl(type, size) + { + } -GSpan GVArray_For_SingleValueRef::get_internal_span_impl() const -{ - return GSpan{*type_, value_, 1}; -} + void get(const int64_t UNUSED(index), void *r_value) const override + { + type_->copy_assign(value_, r_value); + } + void get_to_uninitialized(const int64_t UNUSED(index), void *r_value) const override + { + type_->copy_construct(value_, r_value); + } -bool GVArray_For_SingleValueRef::is_single_impl() const -{ - return true; -} + bool is_span() const override + { + return size_ == 1; + } + GSpan get_internal_span() const override + { + return GSpan{*type_, value_, 1}; + } -void GVArray_For_SingleValueRef::get_internal_single_impl(void *r_value) const -{ - type_->copy_assign(value_, r_value); -} + bool is_single() const override + { + return true; + } + void get_internal_single(void *r_value) const override + { + type_->copy_assign(value_, r_value); + } +}; + +class GVArrayImpl_For_SingleValueRef_final final : public GVArrayImpl_For_SingleValueRef { + public: + using GVArrayImpl_For_SingleValueRef::GVArrayImpl_For_SingleValueRef; + + private: + bool may_have_ownership() const override + { + return false; + } +}; /** \} */ /* -------------------------------------------------------------------- */ -/** \name #GVArray_For_SingleValue +/** \name #GVArrayImpl_For_SingleValue * \{ */ -GVArray_For_SingleValue::GVArray_For_SingleValue(const CPPType &type, - const int64_t size, - const void *value) - : GVArray_For_SingleValueRef(type, size) -{ - value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__); - type.copy_construct(value, (void *)value_); -} +/* Same as GVArrayImpl_For_SingleValueRef, but the value is owned. */ +class GVArrayImpl_For_SingleValue : public GVArrayImpl_For_SingleValueRef, + NonCopyable, + NonMovable { + public: + GVArrayImpl_For_SingleValue(const CPPType &type, const int64_t size, const void *value) + : GVArrayImpl_For_SingleValueRef(type, size) + { + value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__); + type.copy_construct(value, (void *)value_); + } -GVArray_For_SingleValue::~GVArray_For_SingleValue() -{ - type_->destruct((void *)value_); - MEM_freeN((void *)value_); -} + ~GVArrayImpl_For_SingleValue() override + { + type_->destruct((void *)value_); + MEM_freeN((void *)value_); + } +}; /** \} */ @@ -326,7 +340,7 @@ GVArray_For_SingleValue::~GVArray_For_SingleValue() /** \name #GVArray_GSpan * \{ */ -GVArray_GSpan::GVArray_GSpan(const GVArray &varray) : GSpan(varray.type()), varray_(varray) +GVArray_GSpan::GVArray_GSpan(GVArray varray) : GSpan(varray.type()), varray_(std::move(varray)) { size_ = varray_.size(); if (varray_.is_span()) { @@ -353,8 +367,8 @@ GVArray_GSpan::~GVArray_GSpan() /** \name #GVMutableArray_GSpan * \{ */ -GVMutableArray_GSpan::GVMutableArray_GSpan(GVMutableArray &varray, const bool copy_values_to_span) - : GMutableSpan(varray.type()), varray_(varray) +GVMutableArray_GSpan::GVMutableArray_GSpan(GVMutableArray varray, const bool copy_values_to_span) + : GMutableSpan(varray.type()), varray_(std::move(varray)) { size_ = varray_.size(); if (varray_.is_span()) { @@ -405,48 +419,314 @@ void GVMutableArray_GSpan::disable_not_applied_warning() /** \} */ /* -------------------------------------------------------------------- */ -/** \name #GVArray_For_SlicedGVArray +/** \name #GVArrayImpl_For_SlicedGVArray * \{ */ -void GVArray_For_SlicedGVArray::get_impl(const int64_t index, void *r_value) const +class GVArrayImpl_For_SlicedGVArray : public GVArrayImpl { + protected: + GVArray varray_; + int64_t offset_; + + public: + GVArrayImpl_For_SlicedGVArray(GVArray varray, const IndexRange slice) + : GVArrayImpl(varray.type(), slice.size()), + varray_(std::move(varray)), + offset_(slice.start()) + { + BLI_assert(slice.one_after_last() <= varray_.size()); + } + + void get(const int64_t index, void *r_value) const override + { + varray_.get(index + offset_, r_value); + } + + void get_to_uninitialized(const int64_t index, void *r_value) const override + { + varray_.get_to_uninitialized(index + offset_, r_value); + } +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #GVArrayCommon + * \{ */ + +GVArrayCommon::GVArrayCommon() = default; + +GVArrayCommon::GVArrayCommon(const GVArrayCommon &other) : storage_(other.storage_) +{ + impl_ = this->impl_from_storage(); +} + +GVArrayCommon::GVArrayCommon(GVArrayCommon &&other) noexcept : storage_(std::move(other.storage_)) +{ + impl_ = this->impl_from_storage(); + other.storage_.reset(); + other.impl_ = nullptr; +} + +GVArrayCommon::GVArrayCommon(const GVArrayImpl *impl) : impl_(impl) +{ + storage_ = impl_; +} + +GVArrayCommon::GVArrayCommon(std::shared_ptr<const GVArrayImpl> impl) : impl_(impl.get()) +{ + if (impl) { + storage_ = std::move(impl); + } +} + +GVArrayCommon::~GVArrayCommon() = default; + +void GVArrayCommon::materialize(void *dst) const +{ + this->materialize(IndexMask(impl_->size()), dst); +} + +void GVArrayCommon::materialize(const IndexMask mask, void *dst) const +{ + impl_->materialize(mask, dst); +} + +void GVArrayCommon::materialize_to_uninitialized(void *dst) const +{ + this->materialize_to_uninitialized(IndexMask(impl_->size()), dst); +} + +void GVArrayCommon::materialize_to_uninitialized(const IndexMask mask, void *dst) const +{ + BLI_assert(mask.min_array_size() <= impl_->size()); + impl_->materialize_to_uninitialized(mask, dst); +} + +bool GVArrayCommon::may_have_ownership() const +{ + return impl_->may_have_ownership(); +} + +void GVArrayCommon::copy_from(const GVArrayCommon &other) +{ + if (this == &other) { + return; + } + storage_ = other.storage_; + impl_ = this->impl_from_storage(); +} + +void GVArrayCommon::move_from(GVArrayCommon &&other) noexcept +{ + if (this == &other) { + return; + } + storage_ = std::move(other.storage_); + impl_ = this->impl_from_storage(); + other.storage_.reset(); + other.impl_ = nullptr; +} + +/* Returns true when the virtual array is stored as a span internally. */ +bool GVArrayCommon::is_span() const +{ + if (this->is_empty()) { + return true; + } + return impl_->is_span(); +} + +/* Returns the internally used span of the virtual array. This invokes undefined behavior is the + * virtual array is not stored as a span internally. */ +GSpan GVArrayCommon::get_internal_span() const { - varray_.get(index + offset_, r_value); + BLI_assert(this->is_span()); + if (this->is_empty()) { + return GSpan(impl_->type()); + } + return impl_->get_internal_span(); } -void GVArray_For_SlicedGVArray::get_to_uninitialized_impl(const int64_t index, void *r_value) const +/* Returns true when the virtual array returns the same value for every index. */ +bool GVArrayCommon::is_single() const { - varray_.get_to_uninitialized(index + offset_, r_value); + if (impl_->size() == 1) { + return true; + } + return impl_->is_single(); +} + +/* Copies the value that is used for every element into `r_value`, which is expected to point to + * initialized memory. This invokes undefined behavior if the virtual array would not return the + * same value for every index. */ +void GVArrayCommon::get_internal_single(void *r_value) const +{ + BLI_assert(this->is_single()); + if (impl_->size() == 1) { + impl_->get(0, r_value); + return; + } + impl_->get_internal_single(r_value); +} + +/* Same as `get_internal_single`, but `r_value` points to initialized memory. */ +void GVArrayCommon::get_internal_single_to_uninitialized(void *r_value) const +{ + impl_->type().default_construct(r_value); + this->get_internal_single(r_value); +} + +const GVArrayImpl *GVArrayCommon::impl_from_storage() const +{ + return storage_.extra_info().get_varray(storage_.get()); +} + +IndexRange GVArrayCommon::index_range() const +{ + return IndexRange(this->size()); } /** \} */ /* -------------------------------------------------------------------- */ -/** \name #GVArray_Slice +/** \name #GVArray * \{ */ -GVArray_Slice::GVArray_Slice(const GVArray &varray, const IndexRange slice) +GVArray::GVArray(const GVArray &other) = default; + +GVArray::GVArray(GVArray &&other) noexcept = default; + +GVArray::GVArray(const GVArrayImpl *impl) : GVArrayCommon(impl) { - if (varray.is_span()) { - /* Create a new virtual for the sliced span. */ - const GSpan span = varray.get_internal_span(); - const GSpan sliced_span = span.slice(slice.start(), slice.size()); - varray_span_.emplace(sliced_span); - varray_ = &*varray_span_; - } - else if (varray.is_single()) { - /* Can just use the existing virtual array, because it's the same value for the indices in the - * slice anyway. */ - varray_ = &varray; - } - else { - /* Generic version when none of the above method works. - * We don't necessarily want to materialize the input varray because there might be - * large distances between the required indices. Then we would materialize many elements that - * are not accessed later on. - */ - varray_any_.emplace(varray, slice); - varray_ = &*varray_any_; +} + +GVArray::GVArray(std::shared_ptr<const GVArrayImpl> impl) : GVArrayCommon(std::move(impl)) +{ +} + +GVArray GVArray::ForSingle(const CPPType &type, const int64_t size, const void *value) +{ + return GVArray::For<GVArrayImpl_For_SingleValue>(type, size, value); +} + +GVArray GVArray::ForSingleRef(const CPPType &type, const int64_t size, const void *value) +{ + return GVArray::For<GVArrayImpl_For_SingleValueRef_final>(type, size, value); +} + +GVArray GVArray::ForSingleDefault(const CPPType &type, const int64_t size) +{ + return GVArray::ForSingleRef(type, size, type.default_value()); +} + +GVArray GVArray::ForSpan(GSpan span) +{ + return GVArray::For<GVArrayImpl_For_GSpan_final>(span); +} + +class GVArrayImpl_For_GArray : public GVArrayImpl_For_GSpan { + protected: + GArray<> array_; + + public: + GVArrayImpl_For_GArray(GArray<> array) + : GVArrayImpl_For_GSpan(array.as_span()), array_(std::move(array)) + { } +}; + +GVArray GVArray::ForGArray(GArray<> array) +{ + return GVArray::For<GVArrayImpl_For_GArray>(array); +} + +GVArray GVArray::ForEmpty(const CPPType &type) +{ + return GVArray::ForSpan(GSpan(type)); +} + +GVArray GVArray::slice(IndexRange slice) const +{ + return GVArray::For<GVArrayImpl_For_SlicedGVArray>(*this, slice); +} + +GVArray &GVArray::operator=(const GVArray &other) +{ + this->copy_from(other); + return *this; +} + +GVArray &GVArray::operator=(GVArray &&other) noexcept +{ + this->move_from(std::move(other)); + return *this; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #GVMutableArray + * \{ */ + +GVMutableArray::GVMutableArray(const GVMutableArray &other) = default; +GVMutableArray::GVMutableArray(GVMutableArray &&other) noexcept = default; + +GVMutableArray::GVMutableArray(GVMutableArrayImpl *impl) : GVArrayCommon(impl) +{ +} + +GVMutableArray::GVMutableArray(std::shared_ptr<GVMutableArrayImpl> impl) + : GVArrayCommon(std::move(impl)) +{ +} + +GVMutableArray GVMutableArray::ForSpan(GMutableSpan span) +{ + return GVMutableArray::For<GVMutableArrayImpl_For_GMutableSpan_final>(span); +} + +GVMutableArray::operator GVArray() const & +{ + GVArray varray; + varray.copy_from(*this); + return varray; +} + +GVMutableArray::operator GVArray() &&noexcept +{ + GVArray varray; + varray.move_from(std::move(*this)); + return varray; +} + +GVMutableArray &GVMutableArray::operator=(const GVMutableArray &other) +{ + this->copy_from(other); + return *this; +} + +GVMutableArray &GVMutableArray::operator=(GVMutableArray &&other) noexcept +{ + this->move_from(std::move(other)); + return *this; +} + +GVMutableArrayImpl *GVMutableArray::get_implementation() const +{ + return this->get_impl(); +} + +/* Copy the values from the source buffer to all elements in the virtual array. */ +void GVMutableArray::set_all(const void *src) +{ + this->get_impl()->set_all(src); +} + +GMutableSpan GVMutableArray::get_internal_span() const +{ + BLI_assert(this->is_span()); + const GSpan span = impl_->get_internal_span(); + return GMutableSpan(span.type(), const_cast<void *>(span.data()), span.size()); } /** \} */ diff --git a/source/blender/functions/intern/generic_virtual_vector_array.cc b/source/blender/functions/intern/generic_virtual_vector_array.cc index 6b90ce993ae..e3c0d3109fa 100644 --- a/source/blender/functions/intern/generic_virtual_vector_array.cc +++ b/source/blender/functions/intern/generic_virtual_vector_array.cc @@ -18,13 +18,13 @@ namespace blender::fn { -void GVArray_For_GVVectorArrayIndex::get_impl(const int64_t index_in_vector, void *r_value) const +void GVArray_For_GVVectorArrayIndex::get(const int64_t index_in_vector, void *r_value) const { vector_array_.get_vector_element(index_, index_in_vector, r_value); } -void GVArray_For_GVVectorArrayIndex::get_to_uninitialized_impl(const int64_t index_in_vector, - void *r_value) const +void GVArray_For_GVVectorArrayIndex::get_to_uninitialized(const int64_t index_in_vector, + void *r_value) const { type_->default_construct(r_value); vector_array_.get_vector_element(index_, index_in_vector, r_value); @@ -32,14 +32,14 @@ void GVArray_For_GVVectorArrayIndex::get_to_uninitialized_impl(const int64_t ind int64_t GVVectorArray_For_SingleGVArray::get_vector_size_impl(const int64_t UNUSED(index)) const { - return array_.size(); + return varray_.size(); } void GVVectorArray_For_SingleGVArray::get_vector_element_impl(const int64_t UNUSED(index), const int64_t index_in_vector, void *r_value) const { - array_.get(index_in_vector, r_value); + varray_.get(index_in_vector, r_value); } bool GVVectorArray_For_SingleGVArray::is_single_vector_impl() const diff --git a/source/blender/functions/intern/multi_function.cc b/source/blender/functions/intern/multi_function.cc index bb657f321ec..ee2c69068db 100644 --- a/source/blender/functions/intern/multi_function.cc +++ b/source/blender/functions/intern/multi_function.cc @@ -18,28 +18,9 @@ namespace blender::fn { -class DummyMultiFunction : public MultiFunction { - public: - DummyMultiFunction() - { - static MFSignature signature = create_signature(); - this->set_signature(&signature); - } - - static MFSignature create_signature() - { - MFSignatureBuilder signature{"Dummy"}; - return signature.build(); - } - - void call(IndexMask UNUSED(mask), - MFParams UNUSED(params), - MFContext UNUSED(context)) const override - { - } -}; - -static DummyMultiFunction dummy_multi_function_; -const MultiFunction &dummy_multi_function = dummy_multi_function_; +std::string MultiFunction::debug_name() const +{ + return signature_ref_->function_name; +} } // namespace blender::fn diff --git a/source/blender/functions/intern/multi_function_builder.cc b/source/blender/functions/intern/multi_function_builder.cc index f891f162820..24f9bbe0179 100644 --- a/source/blender/functions/intern/multi_function_builder.cc +++ b/source/blender/functions/intern/multi_function_builder.cc @@ -32,10 +32,8 @@ CustomMF_GenericConstant::CustomMF_GenericConstant(const CPPType &type, } value_ = value; - MFSignatureBuilder signature{"Constant " + type.name()}; - std::stringstream ss; - type.print_or_default(value, ss, type.name()); - signature.single_output(ss.str(), type); + MFSignatureBuilder signature{"Constant"}; + signature.single_output("Value", type); signature_ = signature.build(); this->set_signature(&signature_); } @@ -73,28 +71,11 @@ bool CustomMF_GenericConstant::equals(const MultiFunction &other) const return type_.is_equal(value_, _other->value_); } -static std::string gspan_to_string(GSpan array) -{ - const CPPType &type = array.type(); - std::stringstream ss; - ss << "["; - const int64_t max_amount = 5; - for (int64_t i : IndexRange(std::min(max_amount, array.size()))) { - type.print_or_default(array[i], ss, type.name()); - ss << ", "; - } - if (max_amount < array.size()) { - ss << "..."; - } - ss << "]"; - return ss.str(); -} - CustomMF_GenericConstantArray::CustomMF_GenericConstantArray(GSpan array) : array_(array) { const CPPType &type = array.type(); - MFSignatureBuilder signature{"Constant " + type.name() + " Vector"}; - signature.vector_output(gspan_to_string(array), type); + MFSignatureBuilder signature{"Constant Vector"}; + signature.vector_output("Value", type); signature_ = signature.build(); this->set_signature(&signature_); } @@ -109,12 +90,11 @@ void CustomMF_GenericConstantArray::call(IndexMask mask, } } -CustomMF_DefaultOutput::CustomMF_DefaultOutput(StringRef name, - Span<MFDataType> input_types, +CustomMF_DefaultOutput::CustomMF_DefaultOutput(Span<MFDataType> input_types, Span<MFDataType> output_types) : output_amount_(output_types.size()) { - MFSignatureBuilder signature{name}; + MFSignatureBuilder signature{"Default Output"}; for (MFDataType data_type : input_types) { signature.input("Input", data_type); } @@ -140,9 +120,9 @@ void CustomMF_DefaultOutput::call(IndexMask mask, MFParams params, MFContext UNU } } -CustomMF_GenericCopy::CustomMF_GenericCopy(StringRef name, MFDataType data_type) +CustomMF_GenericCopy::CustomMF_GenericCopy(MFDataType data_type) { - MFSignatureBuilder signature{name}; + MFSignatureBuilder signature{"Copy"}; signature.input("Input", data_type); signature.output("Output", data_type); signature_ = signature.build(); diff --git a/source/blender/functions/intern/multi_function_parallel.cc b/source/blender/functions/intern/multi_function_parallel.cc index 5a8c621f0b3..eefe647644d 100644 --- a/source/blender/functions/intern/multi_function_parallel.cc +++ b/source/blender/functions/intern/multi_function_parallel.cc @@ -54,7 +54,6 @@ void ParallelMultiFunction::call(IndexMask full_mask, MFParams params, MFContext const IndexRange input_slice_range{input_slice_start, input_slice_size}; MFParamsBuilder sub_params{fn_, sub_mask.min_array_size()}; - ResourceScope &scope = sub_params.resource_scope(); /* All parameters are sliced so that the wrapped multi-function does not have to take care of * the index offset. */ @@ -63,8 +62,7 @@ void ParallelMultiFunction::call(IndexMask full_mask, MFParams params, MFContext switch (param_type.category()) { case MFParamType::SingleInput: { const GVArray &varray = params.readonly_single_input(param_index); - const GVArray &sliced_varray = scope.construct<GVArray_Slice>(varray, input_slice_range); - sub_params.add_readonly_single_input(sliced_varray); + sub_params.add_readonly_single_input(varray.slice(input_slice_range)); break; } case MFParamType::SingleMutable: { diff --git a/source/blender/functions/intern/multi_function_procedure.cc b/source/blender/functions/intern/multi_function_procedure.cc index 986c5dff0c4..804beb7d66f 100644 --- a/source/blender/functions/intern/multi_function_procedure.cc +++ b/source/blender/functions/intern/multi_function_procedure.cc @@ -782,7 +782,7 @@ class MFProcedureDotExport { void instruction_to_string(const MFCallInstruction &instruction, std::stringstream &ss) { const MultiFunction &fn = instruction.fn(); - this->instruction_name_format(fn.name() + ": ", ss); + this->instruction_name_format(fn.debug_name() + ": ", ss); for (const int param_index : fn.param_indices()) { const MFParamType param_type = fn.param_type(param_index); const MFVariable *variable = instruction.params()[param_index]; diff --git a/source/blender/functions/intern/multi_function_procedure_executor.cc b/source/blender/functions/intern/multi_function_procedure_executor.cc index 6d2d121bafd..06c97fd1173 100644 --- a/source/blender/functions/intern/multi_function_procedure_executor.cc +++ b/source/blender/functions/intern/multi_function_procedure_executor.cc @@ -20,13 +20,12 @@ namespace blender::fn { -MFProcedureExecutor::MFProcedureExecutor(std::string name, const MFProcedure &procedure) - : procedure_(procedure) +MFProcedureExecutor::MFProcedureExecutor(const MFProcedure &procedure) : procedure_(procedure) { - MFSignatureBuilder signature(std::move(name)); + MFSignatureBuilder signature("Procedure Executor"); for (const ConstMFParameter ¶m : procedure.params()) { - signature.add(param.variable->name(), MFParamType(param.type, param.variable->data_type())); + signature.add("Parameter", MFParamType(param.type, param.variable->data_type())); } signature_ = signature.build(); @@ -66,6 +65,7 @@ struct VariableValue_GVArray : public VariableValue { VariableValue_GVArray(const GVArray &data) : VariableValue(static_type), data(data) { + BLI_assert(data); } }; @@ -756,7 +756,7 @@ class VariableState : NonCopyable, NonMovable { switch (value_->type) { case ValueType::GVArray: { - const GVArray_Typed<bool> varray{this->value_as<VariableValue_GVArray>()->data}; + const VArray<bool> varray = this->value_as<VariableValue_GVArray>()->data.typed<bool>(); for (const int i : mask) { r_indices[varray[i]].append(i); } diff --git a/source/blender/functions/tests/FN_field_test.cc b/source/blender/functions/tests/FN_field_test.cc index 041cdbd0f00..4614f9eee58 100644 --- a/source/blender/functions/tests/FN_field_test.cc +++ b/source/blender/functions/tests/FN_field_test.cc @@ -34,14 +34,12 @@ class IndexFieldInput final : public FieldInput { { } - const GVArray *get_varray_for_context(const FieldContext &UNUSED(context), - IndexMask mask, - ResourceScope &scope) const final + GVArray get_varray_for_context(const FieldContext &UNUSED(context), + IndexMask mask, + ResourceScope &UNUSED(scope)) const final { auto index_func = [](int i) { return i; }; - return &scope.construct< - GVArray_For_EmbeddedVArray<int, VArray_For_Func<int, decltype(index_func)>>>( - mask.min_array_size(), mask.min_array_size(), index_func); + return VArray<int>::ForFunc(mask.min_array_size(), index_func); } }; @@ -162,9 +160,9 @@ class TwoOutputFunction : public MultiFunction { MFSignature signature_; public: - TwoOutputFunction(StringRef name) + TwoOutputFunction() { - MFSignatureBuilder signature{name}; + MFSignatureBuilder signature{"Two Outputs"}; signature.single_input<int>("In1"); signature.single_input<int>("In2"); signature.single_output<int>("Add"); @@ -192,8 +190,8 @@ TEST(field, FunctionTwoOutputs) GField index_field_1{std::make_shared<IndexFieldInput>()}; GField index_field_2{std::make_shared<IndexFieldInput>()}; - std::shared_ptr<FieldOperation> fn = std::make_shared<FieldOperation>(FieldOperation( - std::make_unique<TwoOutputFunction>("SI_SI_SO_SO"), {index_field_1, index_field_2})); + std::shared_ptr<FieldOperation> fn = std::make_shared<FieldOperation>( + FieldOperation(std::make_unique<TwoOutputFunction>(), {index_field_1, index_field_2})); GField result_field_1{fn, 0}; GField result_field_2{fn, 1}; @@ -223,8 +221,8 @@ TEST(field, TwoFunctionsTwoOutputs) { GField index_field{std::make_shared<IndexFieldInput>()}; - std::shared_ptr<FieldOperation> fn = std::make_shared<FieldOperation>(FieldOperation( - std::make_unique<TwoOutputFunction>("SI_SI_SO_SO"), {index_field, index_field})); + std::shared_ptr<FieldOperation> fn = std::make_shared<FieldOperation>( + FieldOperation(std::make_unique<TwoOutputFunction>(), {index_field, index_field})); Array<int64_t> mask_indices = {2, 4, 6, 8}; IndexMask mask = mask_indices.as_span(); @@ -240,20 +238,20 @@ TEST(field, TwoFunctionsTwoOutputs) FieldContext field_context; FieldEvaluator field_evaluator{field_context, &mask}; - const VArray<int> *result_1 = nullptr; - const VArray<int> *result_2 = nullptr; + VArray<int> result_1; + VArray<int> result_2; field_evaluator.add(result_field_1, &result_1); field_evaluator.add(result_field_2, &result_2); field_evaluator.evaluate(); - EXPECT_EQ(result_1->get(2), 4); - EXPECT_EQ(result_1->get(4), 8); - EXPECT_EQ(result_1->get(6), 12); - EXPECT_EQ(result_1->get(8), 16); - EXPECT_EQ(result_2->get(2), 24); - EXPECT_EQ(result_2->get(4), 28); - EXPECT_EQ(result_2->get(6), 32); - EXPECT_EQ(result_2->get(8), 36); + EXPECT_EQ(result_1.get(2), 4); + EXPECT_EQ(result_1.get(4), 8); + EXPECT_EQ(result_1.get(6), 12); + EXPECT_EQ(result_1.get(8), 16); + EXPECT_EQ(result_2.get(2), 24); + EXPECT_EQ(result_2.get(4), 28); + EXPECT_EQ(result_2.get(6), 32); + EXPECT_EQ(result_2.get(8), 36); } TEST(field, SameFieldTwice) @@ -264,16 +262,16 @@ TEST(field, SameFieldTwice) FieldContext field_context; IndexMask mask{IndexRange(2)}; ResourceScope scope; - Vector<const GVArray *> results = evaluate_fields( + Vector<GVArray> results = evaluate_fields( scope, {constant_field, constant_field}, mask, field_context); - GVArray_Typed<int> varray1{*results[0]}; - GVArray_Typed<int> varray2{*results[1]}; + VArray<int> varray1 = results[0].typed<int>(); + VArray<int> varray2 = results[1].typed<int>(); - EXPECT_EQ(varray1->get(0), 10); - EXPECT_EQ(varray1->get(1), 10); - EXPECT_EQ(varray2->get(0), 10); - EXPECT_EQ(varray2->get(1), 10); + EXPECT_EQ(varray1.get(0), 10); + EXPECT_EQ(varray1.get(1), 10); + EXPECT_EQ(varray2.get(0), 10); + EXPECT_EQ(varray2.get(1), 10); } TEST(field, IgnoredOutput) @@ -283,12 +281,12 @@ TEST(field, IgnoredOutput) FieldContext field_context; FieldEvaluator field_evaluator{field_context, 10}; - const VArray<int> *results = nullptr; + VArray<int> results; field_evaluator.add(field, &results); field_evaluator.evaluate(); - EXPECT_EQ(results->get(0), 5); - EXPECT_EQ(results->get(3), 5); + EXPECT_EQ(results.get(0), 5); + EXPECT_EQ(results.get(3), 5); } } // namespace blender::fn::tests diff --git a/source/blender/functions/tests/FN_multi_function_procedure_test.cc b/source/blender/functions/tests/FN_multi_function_procedure_test.cc index 0b4b88fba3d..e3de23550c5 100644 --- a/source/blender/functions/tests/FN_multi_function_procedure_test.cc +++ b/source/blender/functions/tests/FN_multi_function_procedure_test.cc @@ -9,6 +9,43 @@ namespace blender::fn::tests { +TEST(multi_function_procedure, ConstantOutput) +{ + /** + * procedure(int *var2) { + * var1 = 5; + * var2 = var1 + var1; + * } + */ + + CustomMF_Constant<int> constant_fn{5}; + CustomMF_SI_SI_SO<int, int, int> add_fn{"Add", [](int a, int b) { return a + b; }}; + + MFProcedure procedure; + MFProcedureBuilder builder{procedure}; + + auto [var1] = builder.add_call<1>(constant_fn); + auto [var2] = builder.add_call<1>(add_fn, {var1, var1}); + builder.add_destruct(*var1); + builder.add_return(); + builder.add_output_parameter(*var2); + + EXPECT_TRUE(procedure.validate()); + + MFProcedureExecutor executor{procedure}; + + MFParamsBuilder params{executor, 2}; + MFContextBuilder context; + + Array<int> output_array(2); + params.add_uninitialized_single_output(output_array.as_mutable_span()); + + executor.call(IndexRange(2), params, context); + + EXPECT_EQ(output_array[0], 10); + EXPECT_EQ(output_array[1], 10); +} + TEST(multi_function_procedure, SimpleTest) { /** @@ -36,7 +73,7 @@ TEST(multi_function_procedure, SimpleTest) EXPECT_TRUE(procedure.validate()); - MFProcedureExecutor executor{"My Procedure", procedure}; + MFProcedureExecutor executor{procedure}; MFParamsBuilder params{executor, 3}; MFContextBuilder context; @@ -88,7 +125,7 @@ TEST(multi_function_procedure, BranchTest) EXPECT_TRUE(procedure.validate()); - MFProcedureExecutor procedure_fn{"Condition Test", procedure}; + MFProcedureExecutor procedure_fn{procedure}; MFParamsBuilder params(procedure_fn, 5); Array<int> values_a = {1, 5, 3, 6, 2}; @@ -130,7 +167,7 @@ TEST(multi_function_procedure, EvaluateOne) builder.add_return(); builder.add_output_parameter(*var2); - MFProcedureExecutor procedure_fn{"Evaluate One", procedure}; + MFProcedureExecutor procedure_fn{procedure}; MFParamsBuilder params{procedure_fn, 5}; Array<int> values_out = {1, 2, 3, 4, 5}; @@ -202,7 +239,7 @@ TEST(multi_function_procedure, SimpleLoop) EXPECT_TRUE(procedure.validate()); - MFProcedureExecutor procedure_fn{"Simple Loop", procedure}; + MFProcedureExecutor procedure_fn{procedure}; MFParamsBuilder params{procedure_fn, 5}; Array<int> counts = {4, 3, 7, 6, 4}; @@ -258,7 +295,7 @@ TEST(multi_function_procedure, Vectors) EXPECT_TRUE(procedure.validate()); - MFProcedureExecutor procedure_fn{"Vectors", procedure}; + MFProcedureExecutor procedure_fn{procedure}; MFParamsBuilder params{procedure_fn, 5}; Array<int> v1 = {5, 2, 3}; @@ -322,7 +359,7 @@ TEST(multi_function_procedure, BufferReuse) EXPECT_TRUE(procedure.validate()); - MFProcedureExecutor procedure_fn{"Buffer Reuse", procedure}; + MFProcedureExecutor procedure_fn{procedure}; Array<int> inputs = {4, 1, 6, 2, 3}; Array<int> results(5, -1); diff --git a/source/blender/functions/tests/FN_multi_function_test.cc b/source/blender/functions/tests/FN_multi_function_test.cc index d99993b35ac..20ca00cf598 100644 --- a/source/blender/functions/tests/FN_multi_function_test.cc +++ b/source/blender/functions/tests/FN_multi_function_test.cc @@ -264,7 +264,6 @@ TEST(multi_function, CustomMF_GenericConstant) { int value = 42; CustomMF_GenericConstant fn{CPPType::get<int32_t>(), (const void *)&value, false}; - EXPECT_EQ(fn.param_name(0), "42"); Array<int> outputs(4, 0); @@ -285,7 +284,6 @@ TEST(multi_function, CustomMF_GenericConstantArray) { std::array<int, 4> values = {3, 4, 5, 6}; CustomMF_GenericConstantArray fn{GSpan(Span(values))}; - EXPECT_EQ(fn.param_name(0), "[3, 4, 5, 6, ]"); GVectorArray vector_array{CPPType::get<int32_t>(), 4}; GVectorArray_TypedMutableRef<int> vector_array_ref{vector_array}; diff --git a/source/blender/geometry/intern/mesh_to_curve_convert.cc b/source/blender/geometry/intern/mesh_to_curve_convert.cc index 24f0b6308ba..7aaaec9f0c5 100644 --- a/source/blender/geometry/intern/mesh_to_curve_convert.cc +++ b/source/blender/geometry/intern/mesh_to_curve_convert.cc @@ -50,23 +50,23 @@ static void copy_attributes_to_points(CurveEval &curve, /* Copy builtin control point attributes. */ if (source_attribute_ids.contains("tilt")) { - const fn::GVArray_Typed<float> tilt_attribute = mesh_component.attribute_get_for_read<float>( + const VArray<float> tilt_attribute = mesh_component.attribute_get_for_read<float>( "tilt", ATTR_DOMAIN_POINT, 0.0f); threading::parallel_for(splines.index_range(), 256, [&](IndexRange range) { for (const int i : range) { copy_attribute_to_points<float>( - *tilt_attribute, point_to_vert_maps[i], splines[i]->tilts()); + tilt_attribute, point_to_vert_maps[i], splines[i]->tilts()); } }); source_attribute_ids.remove_contained("tilt"); } if (source_attribute_ids.contains("radius")) { - const fn::GVArray_Typed<float> radius_attribute = mesh_component.attribute_get_for_read<float>( + const VArray<float> radius_attribute = mesh_component.attribute_get_for_read<float>( "radius", ATTR_DOMAIN_POINT, 1.0f); threading::parallel_for(splines.index_range(), 256, [&](IndexRange range) { for (const int i : range) { copy_attribute_to_points<float>( - *radius_attribute, point_to_vert_maps[i], splines[i]->radii()); + radius_attribute, point_to_vert_maps[i], splines[i]->radii()); } }); source_attribute_ids.remove_contained("radius"); @@ -82,7 +82,7 @@ static void copy_attributes_to_points(CurveEval &curve, continue; } - const fn::GVArrayPtr mesh_attribute = mesh_component.attribute_try_get_for_read( + const fn::GVArray mesh_attribute = mesh_component.attribute_try_get_for_read( attribute_id, ATTR_DOMAIN_POINT); /* Some attributes might not exist if they were builtin attribute on domains that don't * have any elements, i.e. a face attribute on the output of the line primitive node. */ @@ -90,7 +90,7 @@ static void copy_attributes_to_points(CurveEval &curve, continue; } - const CustomDataType data_type = bke::cpp_type_to_custom_data_type(mesh_attribute->type()); + const CustomDataType data_type = bke::cpp_type_to_custom_data_type(mesh_attribute.type()); threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) { for (const int i : range) { @@ -101,10 +101,10 @@ static void copy_attributes_to_points(CurveEval &curve, BLI_assert(spline_attribute); /* Copy attribute based on the map for this spline. */ - attribute_math::convert_to_static_type(mesh_attribute->type(), [&](auto dummy) { + attribute_math::convert_to_static_type(mesh_attribute.type(), [&](auto dummy) { using T = decltype(dummy); copy_attribute_to_points<T>( - mesh_attribute->typed<T>(), point_to_vert_maps[i], spline_attribute->typed<T>()); + mesh_attribute.typed<T>(), point_to_vert_maps[i], spline_attribute->typed<T>()); }); } }); diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h index d8926a63307..869f93f832e 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h +++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h @@ -476,11 +476,32 @@ typedef struct LineartBoundingArea { #define LRT_MIN3_INDEX_ABC(x, y, z) (x < y ? (x < z ? a : (y < z ? b : c)) : (y < z ? b : c)) #define LRT_ABC(index) (index == 0 ? a : (index == 1 ? b : c)) +#define LRT_PABC(index) (index == 0 ? pa : (index == 1 ? pb : pc)) +#define DBL_LOOSER 1e-5 +#define LRT_DOUBLE_CLOSE_LOOSER(a, b) (((a) + DBL_LOOSER) >= (b) && ((a)-DBL_LOOSER) <= (b)) #define LRT_DOUBLE_CLOSE_ENOUGH(a, b) (((a) + DBL_EDGE_LIM) >= (b) && ((a)-DBL_EDGE_LIM) <= (b)) +#define LRT_DOUBLE_CLOSE_ENOUGH_TRI(a, b) \ + (((a) + DBL_TRIANGLE_LIM) >= (b) && ((a)-DBL_TRIANGLE_LIM) <= (b)) -BLI_INLINE int lineart_LineIntersectTest2d( - const double *a1, const double *a2, const double *b1, const double *b2, double *aRatio) +/* Notes on this function: + + * r_ratio: The ratio on segment a1-a2. When r_ratio is very close to zero or one, it + * fixes the value to zero or one, this makes it easier to identify "on the tip" situations. + * + * r_aligned: True when 1) a and b is exactly on the same straight line and 2) a and b share a + * common end-point. + * + * Important: if r_aligned is true, r_ratio will be either 0 or 1 depending on which point from + * segment a is shared with segment b. If it's a1 then r_ratio is 0, else then r_ratio is 1. This + * extra information is needed for line art occlusion stage to work correctly in such cases. + */ +BLI_INLINE int lineart_intersect_seg_seg(const double *a1, + const double *a2, + const double *b1, + const double *b2, + double *r_ratio, + bool *r_aligned) { /* Legacy intersection math aligns better with occlusion function quirks. */ /* #define USE_VECTOR_LINE_INTERSECTION */ @@ -504,27 +525,27 @@ BLI_INLINE int lineart_LineIntersectTest2d( double rr; if (fabs(a2[0] - a1[0]) > fabs(a2[1] - a1[1])) { - *aRatio = ratiod(a1[0], a2[0], rx); + *r_ratio = ratiod(a1[0], a2[0], rx); if (fabs(b2[0] - b1[0]) > fabs(b2[1] - b1[1])) { rr = ratiod(b1[0], b2[0], rx); } else { rr = ratiod(b1[1], b2[1], ry); } - if ((*aRatio) > 0 && (*aRatio) < 1 && rr > 0 && rr < 1) { + if ((*r_ratio) > 0 && (*r_ratio) < 1 && rr > 0 && rr < 1) { return 1; } return 0; } - *aRatio = ratiod(a1[1], a2[1], ry); + *r_ratio = ratiod(a1[1], a2[1], ry); if (fabs(b2[0] - b1[0]) > fabs(b2[1] - b1[1])) { rr = ratiod(b1[0], b2[0], rx); } else { rr = ratiod(b1[1], b2[1], ry); } - if ((*aRatio) > 0 && (*aRatio) < 1 && rr > 0 && rr < 1) { + if ((*r_ratio) > 0 && (*r_ratio) < 1 && rr > 0 && rr < 1) { return 1; } return 0; @@ -539,34 +560,62 @@ BLI_INLINE int lineart_LineIntersectTest2d( double x_diff = (a2[0] - a1[0]); double x_diff2 = (b2[0] - b1[0]); + *r_aligned = false; + if (LRT_DOUBLE_CLOSE_ENOUGH(x_diff, 0)) { if (LRT_DOUBLE_CLOSE_ENOUGH(x_diff2, 0)) { - *aRatio = 0; + /* This means two segments are both vertical. */ + if ((LRT_DOUBLE_CLOSE_ENOUGH(a2[0], b1[0]) && LRT_DOUBLE_CLOSE_ENOUGH(a2[1], b1[1])) || + (LRT_DOUBLE_CLOSE_ENOUGH(a2[0], b2[0]) && LRT_DOUBLE_CLOSE_ENOUGH(a2[1], b2[1]))) { + *r_aligned = true; + *r_ratio = 1; + } + else if ((LRT_DOUBLE_CLOSE_ENOUGH(a1[0], b1[0]) && LRT_DOUBLE_CLOSE_ENOUGH(a1[1], b1[1])) || + (LRT_DOUBLE_CLOSE_ENOUGH(a1[0], b2[0]) && LRT_DOUBLE_CLOSE_ENOUGH(a1[1], b2[1]))) { + *r_aligned = true; + *r_ratio = 0; + } return 0; } double r2 = ratiod(b1[0], b2[0], a1[0]); x = interpd(b2[0], b1[0], r2); y = interpd(b2[1], b1[1], r2); - *aRatio = ratio = ratiod(a1[1], a2[1], y); + *r_ratio = ratio = ratiod(a1[1], a2[1], y); } else { if (LRT_DOUBLE_CLOSE_ENOUGH(x_diff2, 0)) { ratio = ratiod(a1[0], a2[0], b1[0]); x = interpd(a2[0], a1[0], ratio); - *aRatio = ratio; + *r_ratio = ratio; } else { - k1 = (a2[1] - a1[1]) / x_diff; - k2 = (b2[1] - b1[1]) / x_diff2; - - if (k1 == k2) + double y_diff = a2[1] - a1[1], y_diff2 = b2[1] - b1[1]; + k1 = y_diff / x_diff; + k2 = y_diff2 / x_diff2; + + if (LRT_DOUBLE_CLOSE_ENOUGH_TRI(k2, k1)) { + /* This means two segments are parallel. This also handles k==0 (both completely + * horizontal) cases. */ + if ((LRT_DOUBLE_CLOSE_ENOUGH(a2[0], b1[0]) && LRT_DOUBLE_CLOSE_ENOUGH(a2[1], b1[1])) || + (LRT_DOUBLE_CLOSE_ENOUGH(a2[0], b2[0]) && LRT_DOUBLE_CLOSE_ENOUGH(a2[1], b2[1]))) { + *r_aligned = true; + *r_ratio = 1; + } + else if ((LRT_DOUBLE_CLOSE_ENOUGH(a1[0], b1[0]) && + LRT_DOUBLE_CLOSE_ENOUGH(a1[1], b1[1])) || + (LRT_DOUBLE_CLOSE_ENOUGH(a1[0], b2[0]) && + LRT_DOUBLE_CLOSE_ENOUGH(a1[1], b2[1]))) { + *r_aligned = true; + *r_ratio = 0; + } return 0; + } x = (a1[1] - b1[1] - k1 * a1[0] + k2 * b1[0]) / (k2 - k1); ratio = (x - a1[0]) / x_diff; - *aRatio = ratio; + *r_ratio = ratio; } } @@ -580,6 +629,13 @@ BLI_INLINE int lineart_LineIntersectTest2d( (b2[0] < b1[0] && x < b2[0])) return 0; + if (LRT_DOUBLE_CLOSE_ENOUGH_TRI(*r_ratio, 1)) { + *r_ratio = 1; + } + else if (LRT_DOUBLE_CLOSE_ENOUGH_TRI(*r_ratio, 0)) { + *r_ratio = 0; + } + return 1; #endif } diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c index f3110cf87b6..88dcfb89c25 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c @@ -634,6 +634,8 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb) } } } + /* Get rid of those very short "zig-zag" lines that jumps around visibility. */ + MOD_lineart_chain_discard_short(rb, DBL_EDGE_LIM); LISTBASE_FOREACH (LineartEdgeChain *, iec, &rb->chains) { lineart_bounding_area_link_chain(rb, iec); } @@ -890,6 +892,9 @@ float MOD_lineart_chain_compute_length(LineartEdgeChain *ec) float last_point[2]; eci = ec->chain.first; + if (!eci) { + return 0; + } copy_v2_v2(last_point, eci->pos); for (eci = ec->chain.first; eci; eci = eci->next) { dist = len_v2v2(eci->pos, last_point); diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index 93e9062e910..3773af70498 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -502,6 +502,10 @@ static void lineart_main_occlusion_begin(LineartRenderBuffer *rb) rb->edge_mark.last = rb->edge_mark.first; rb->floating.last = rb->floating.first; + /* This is needed because the occlusion function expects the camera vector to point towards the + * camera. */ + negate_v3_db(rb->view_vector); + TaskPool *tp = BLI_task_pool_create(NULL, TASK_PRIORITY_HIGH); for (i = 0; i < thread_count; i++) { @@ -567,20 +571,26 @@ static int lineart_point_on_line_segment(double v[2], double v0[2], double v1[2] return 0; } - if (v1[0] - v0[0]) { + if (!LRT_DOUBLE_CLOSE_ENOUGH(v1[0], v0[0])) { c1 = ratiod(v0[0], v1[0], v[0]); } - else if (v[0] == v1[0]) { - c2 = ratiod(v0[1], v1[1], v[1]); - return (c2 >= 0 && c2 <= 1); + else { + if (LRT_DOUBLE_CLOSE_ENOUGH(v[0], v1[0])) { + c2 = ratiod(v0[1], v1[1], v[1]); + return (c2 >= -DBL_TRIANGLE_LIM && c2 <= 1 + DBL_TRIANGLE_LIM); + } + return false; } - if (v1[1] - v0[1]) { + if (!LRT_DOUBLE_CLOSE_ENOUGH(v1[1], v0[1])) { c2 = ratiod(v0[1], v1[1], v[1]); } - else if (v[1] == v1[1]) { - c1 = ratiod(v0[0], v1[0], v[0]); - return (c1 >= 0 && c1 <= 1); + else { + if (LRT_DOUBLE_CLOSE_ENOUGH(v[1], v1[1])) { + c1 = ratiod(v0[0], v1[0], v[0]); + return (c1 >= -DBL_TRIANGLE_LIM && c1 <= 1 + DBL_TRIANGLE_LIM); + } + return false; } if (LRT_DOUBLE_CLOSE_ENOUGH(c1, c2) && c1 >= 0 && c1 <= 1) { @@ -1529,7 +1539,7 @@ static uint16_t lineart_identify_feature_line(LineartRenderBuffer *rb, dot_1 = dot_v3v3_db(view_vector, tri1->gn); dot_2 = dot_v3v3_db(view_vector, tri2->gn); - if ((result = dot_1 * dot_2) <= 0 && (dot_1 + dot_2)) { + if ((result = dot_1 * dot_2) <= 0 && (fabs(dot_1) + fabs(dot_2))) { edge_flag_result |= LRT_EDGE_FLAG_CONTOUR; } @@ -2305,7 +2315,7 @@ static bool lineart_edge_from_triangle(const LineartTriangle *tri, { \ index = (num < is[order[0]] ? \ order[0] : \ - (num < is[order[1]] ? order[1] : (num < is[order[2]] ? order[2] : order[2]))); \ + (num < is[order[1]] ? order[1] : (num < is[order[2]] ? order[2] : -1))); \ } /* `ia ib ic` are ordered. */ @@ -2313,7 +2323,7 @@ static bool lineart_edge_from_triangle(const LineartTriangle *tri, { \ index = (num > is[order[2]] ? \ order[2] : \ - (num > is[order[1]] ? order[1] : (num > is[order[0]] ? order[0] : order[0]))); \ + (num > is[order[1]] ? order[1] : (num > is[order[0]] ? order[0] : -1))); \ } /** @@ -2321,6 +2331,22 @@ static bool lineart_edge_from_triangle(const LineartTriangle *tri, * the occlusion status between 1(one) triangle and 1(one) line. * if returns true, then from/to will carry the occluded segments * in ratio from `e->v1` to `e->v2`. The line is later cut with these two values. + * + * TODO: (Yiming) This function uses a convoluted method that needs to be redesigned. + * + * 1) The lineart_intersect_seg_seg() and lineart_point_triangle_relation() are separate calls, + * which would potentially return results that doesn't agree, especially when it's an edge + * extruding from one of the triangle's point. To get the information using one math process can + * solve this problem. + * + * 2) Currently using discrete a/b/c/pa/pb/pc/is[3] values for storing + * intersection/edge_aligned/intersection_order info, which isn't optimal, needs a better + * representation (likely a struct) for readability and clarity of code path. + * + * I keep this function as-is because it's still fast, and more importantly the output value + * threshold is already in tune with the cutting function in the next stage. + * While current "edge aligned" fix isn't ideal, it does solve most of the precision issue + * especially in ortho camera mode. */ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl), const LineartTriangle *tri, @@ -2338,7 +2364,8 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl), double is[3] = {0}; int order[3]; int LCross = -1, RCross = -1; - int a, b, c; + int a, b, c; /* Crossing info. */ + bool pa, pb, pc; /* Parallel info. */ int st_l = 0, st_r = 0; double Lv[3]; @@ -2368,9 +2395,9 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl), } /* Check if the line visually crosses one of the edge in the triangle. */ - a = lineart_LineIntersectTest2d(LFBC, RFBC, FBC0, FBC1, &is[0]); - b = lineart_LineIntersectTest2d(LFBC, RFBC, FBC1, FBC2, &is[1]); - c = lineart_LineIntersectTest2d(LFBC, RFBC, FBC2, FBC0, &is[2]); + a = lineart_intersect_seg_seg(LFBC, RFBC, FBC0, FBC1, &is[0], &pa); + b = lineart_intersect_seg_seg(LFBC, RFBC, FBC1, FBC2, &is[1], &pb); + c = lineart_intersect_seg_seg(LFBC, RFBC, FBC2, FBC0, &is[2], &pc); /* Sort the intersection distance. */ INTERSECT_SORT_MIN_TO_MAX_3(is[0], is[1], is[2], order); @@ -2402,13 +2429,16 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl), return false; } + /* If the edge doesn't visually cross any edge of the triangle... */ if (!a && !b && !c) { + /* And if both end point from the edge is outside of the triangle... */ if (!(st_l = lineart_point_triangle_relation(LFBC, FBC0, FBC1, FBC2)) && !(st_r = lineart_point_triangle_relation(RFBC, FBC0, FBC1, FBC2))) { - return 0; /* Intersection point is not inside triangle. */ + return 0; /* We don't have any occlusion. */ } } + /* Whether two end points are inside/on_the_edge/outside of the triangle. */ st_l = lineart_point_triangle_relation(LFBC, FBC0, FBC1, FBC2); st_r = lineart_point_triangle_relation(RFBC, FBC0, FBC1, FBC2); @@ -2455,60 +2485,96 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl), cut = ratiod(e->v1->fbcoord[1], e->v2->fbcoord[1], trans[1]); } - /* Determine the pair of edges that the line has crossed. */ +#define LRT_GUARD_NOT_FOUND \ + if (LCross < 0 || RCross < 0) { \ + return false; \ + } + + /* Determine the pair of edges that the line has crossed. The "|" symbol in the comment indicates + * triangle boundary. DBL_TRIANGLE_LIM is needed to for floating point precision tolerance. */ if (st_l == 2) { + /* Left side is in the triangle. */ if (st_r == 2) { + /* | l---r | */ INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross); INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross); } else if (st_r == 1) { + /* | l------r| */ INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross); INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross); } else if (st_r == 0) { + /* | l-------|------r */ INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross); INTERSECT_JUST_GREATER(is, order, 0, RCross); } } else if (st_l == 1) { + /* Left side is on some edge of the triangle. */ if (st_r == 2) { + /* |l------r | */ INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross); INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross); } else if (st_r == 1) { + /* |l---------r| */ INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross); INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross); } else if (st_r == 0) { + /* |l----------|-------r (crossing the triangle) [OR] + * r---------|l | (not crossing the triangle) */ INTERSECT_JUST_GREATER(is, order, DBL_TRIANGLE_LIM, RCross); - if (LRT_ABC(RCross) && is[RCross] > (DBL_TRIANGLE_LIM)) { + if (RCross >= 0 && LRT_ABC(RCross) && is[RCross] > (DBL_TRIANGLE_LIM)) { INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross); } else { - INTERSECT_JUST_SMALLER(is, order, -DBL_TRIANGLE_LIM, LCross); - INTERSECT_JUST_GREATER(is, order, -DBL_TRIANGLE_LIM, RCross); + INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, RCross); + if (RCross > 0) { + INTERSECT_JUST_SMALLER(is, order, is[RCross], LCross); + } + } + LRT_GUARD_NOT_FOUND + /* We could have the edge being completely parallel to the triangle where there isn't a + * viable occlusion result. */ + if ((LRT_PABC(LCross) && !LRT_ABC(LCross)) || (LRT_PABC(RCross) && !LRT_ABC(RCross))) { + return false; } } } else if (st_l == 0) { + /* Left side is outside of the triangle. */ if (st_r == 2) { + /* l---|---r | */ INTERSECT_JUST_SMALLER(is, order, 1 - DBL_TRIANGLE_LIM, LCross); INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross); } else if (st_r == 1) { + /* |r----------|-------l (crossing the triangle) [OR] + * l---------|r | (not crossing the triangle) */ INTERSECT_JUST_SMALLER(is, order, 1 - DBL_TRIANGLE_LIM, LCross); - if (LRT_ABC(LCross) && is[LCross] < (1 - DBL_TRIANGLE_LIM)) { + if (LCross >= 0 && LRT_ABC(LCross) && is[LCross] < (1 - DBL_TRIANGLE_LIM)) { INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross); } else { - INTERSECT_JUST_SMALLER(is, order, 1 + DBL_TRIANGLE_LIM, LCross); - INTERSECT_JUST_GREATER(is, order, 1 + DBL_TRIANGLE_LIM, RCross); + INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, LCross); + if (LCross > 0) { + INTERSECT_JUST_GREATER(is, order, is[LCross], RCross); + } + } + LRT_GUARD_NOT_FOUND + /* The same logic applies as above case. */ + if ((LRT_PABC(LCross) && !LRT_ABC(LCross)) || (LRT_PABC(RCross) && !LRT_ABC(RCross))) { + return false; } } else if (st_r == 0) { - INTERSECT_JUST_GREATER(is, order, DBL_TRIANGLE_LIM, LCross); - if (LRT_ABC(LCross) && is[LCross] > DBL_TRIANGLE_LIM) { + /* l---|----|----r (crossing the triangle) [OR] + * l----r | | (not crossing the triangle) */ + INTERSECT_JUST_GREATER(is, order, -DBL_TRIANGLE_LIM, LCross); + if (LCross >= 0 && LRT_ABC(LCross)) { INTERSECT_JUST_GREATER(is, order, is[LCross], RCross); } else { @@ -2518,6 +2584,8 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl), } } + LRT_GUARD_NOT_FOUND + double LF = dot_l * dot_f, RF = dot_r * dot_f; /* Determine the start and end point of image space cut on a line. */ @@ -2938,7 +3006,7 @@ static void lineart_triangle_intersect_in_bounding_area(LineartRenderBuffer *rb, */ static void lineart_main_get_view_vector(LineartRenderBuffer *rb) { - float direction[3] = {0, 0, 1}; + float direction[3] = {0, 0, -1}; float trans[3]; float inv[4][4]; float obmat_no_scale[4][4]; @@ -3827,25 +3895,26 @@ static LineartBoundingArea *lineart_edge_first_bounding_area(LineartRenderBuffer double data[2] = {e->v1->fbcoord[0], e->v1->fbcoord[1]}; double LU[2] = {-1, 1}, RU[2] = {1, 1}, LB[2] = {-1, -1}, RB[2] = {1, -1}; double r = 1, sr = 1; + bool p_unused; if (data[0] > -1 && data[0] < 1 && data[1] > -1 && data[1] < 1) { return lineart_get_bounding_area(rb, data[0], data[1]); } - if (lineart_LineIntersectTest2d(e->v1->fbcoord, e->v2->fbcoord, LU, RU, &sr) && sr < r && - sr > 0) { + if (lineart_intersect_seg_seg(e->v1->fbcoord, e->v2->fbcoord, LU, RU, &sr, &p_unused) && + sr < r && sr > 0) { r = sr; } - if (lineart_LineIntersectTest2d(e->v1->fbcoord, e->v2->fbcoord, LB, RB, &sr) && sr < r && - sr > 0) { + if (lineart_intersect_seg_seg(e->v1->fbcoord, e->v2->fbcoord, LB, RB, &sr, &p_unused) && + sr < r && sr > 0) { r = sr; } - if (lineart_LineIntersectTest2d(e->v1->fbcoord, e->v2->fbcoord, LB, LU, &sr) && sr < r && - sr > 0) { + if (lineart_intersect_seg_seg(e->v1->fbcoord, e->v2->fbcoord, LB, LU, &sr, &p_unused) && + sr < r && sr > 0) { r = sr; } - if (lineart_LineIntersectTest2d(e->v1->fbcoord, e->v2->fbcoord, RB, RU, &sr) && sr < r && - sr > 0) { + if (lineart_intersect_seg_seg(e->v1->fbcoord, e->v2->fbcoord, RB, RU, &sr, &p_unused) && + sr < r && sr > 0) { r = sr; } interp_v2_v2v2_db(data, e->v1->fbcoord, e->v2->fbcoord, r); diff --git a/source/blender/gpu/GPU_immediate_util.h b/source/blender/gpu/GPU_immediate_util.h index 0d3d39839b2..047c3d3da00 100644 --- a/source/blender/gpu/GPU_immediate_util.h +++ b/source/blender/gpu/GPU_immediate_util.h @@ -92,6 +92,7 @@ void imm_draw_cylinder_wire_3d( void imm_draw_cylinder_fill_3d( uint pos, float base, float top, float height, int slices, int stacks); +void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], uint pos); #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/intern/gpu_immediate_util.c b/source/blender/gpu/intern/gpu_immediate_util.c index 032974db8d1..df18b89bd67 100644 --- a/source/blender/gpu/intern/gpu_immediate_util.c +++ b/source/blender/gpu/intern/gpu_immediate_util.c @@ -602,3 +602,55 @@ void imm_draw_cylinder_fill_3d( } immEnd(); } + +/* Circle Drawing - Tables for Optimized Drawing Speed */ +#define CIRCLE_RESOL 32 + +static void circball_array_fill(const float verts[CIRCLE_RESOL][3], + const float cent[3], + float rad, + const float tmat[4][4]) +{ + /* 32 values of sin function (still same result!) */ + const float sinval[CIRCLE_RESOL] = { + 0.00000000, 0.20129852, 0.39435585, 0.57126821, 0.72479278, 0.84864425, 0.93775213, + 0.98846832, 0.99871650, 0.96807711, 0.89780453, 0.79077573, 0.65137248, 0.48530196, + 0.29936312, 0.10116832, -0.10116832, -0.29936312, -0.48530196, -0.65137248, -0.79077573, + -0.89780453, -0.96807711, -0.99871650, -0.98846832, -0.93775213, -0.84864425, -0.72479278, + -0.57126821, -0.39435585, -0.20129852, 0.00000000, + }; + + /* 32 values of cos function (still same result!) */ + const float cosval[CIRCLE_RESOL] = { + 1.00000000, 0.97952994, 0.91895781, 0.82076344, 0.68896691, 0.52896401, 0.34730525, + 0.15142777, -0.05064916, -0.25065253, -0.44039415, -0.61210598, -0.75875812, -0.87434661, + -0.95413925, -0.99486932, -0.99486932, -0.95413925, -0.87434661, -0.75875812, -0.61210598, + -0.44039415, -0.25065253, -0.05064916, 0.15142777, 0.34730525, 0.52896401, 0.68896691, + 0.82076344, 0.91895781, 0.97952994, 1.00000000, + }; + + float vx[3], vy[3]; + float *viter = (float *)verts; + + mul_v3_v3fl(vx, tmat[0], rad); + mul_v3_v3fl(vy, tmat[1], rad); + + for (uint a = 0; a < CIRCLE_RESOL; a++, viter += 3) { + viter[0] = cent[0] + sinval[a] * vx[0] + cosval[a] * vy[0]; + viter[1] = cent[1] + sinval[a] * vx[1] + cosval[a] * vy[1]; + viter[2] = cent[2] + sinval[a] * vx[2] + cosval[a] * vy[2]; + } +} + +void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], uint pos) +{ + float verts[CIRCLE_RESOL][3]; + + circball_array_fill(verts, cent, rad, tmat); + + immBegin(GPU_PRIM_LINE_LOOP, CIRCLE_RESOL); + for (int i = 0; i < CIRCLE_RESOL; i++) { + immVertex3fv(pos, verts[i]); + } + immEnd(); +} diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc index 2855d5078ff..27ef75df328 100644 --- a/source/blender/gpu/opengl/gl_backend.cc +++ b/source/blender/gpu/opengl/gl_backend.cc @@ -412,6 +412,12 @@ static void detect_workarounds() if (GLContext::debug_layer_support == false) { GLContext::debug_layer_workaround = true; } + + /* Broken glGenerateMipmap on macOS 10.15.7 security update. */ + if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_MAC, GPU_DRIVER_ANY) && + strstr(renderer, "HD Graphics 4000")) { + GLContext::generate_mipmap_workaround = true; + } } // namespace blender::gpu /** Internal capabilities. */ @@ -436,6 +442,7 @@ bool GLContext::vertex_attrib_binding_support = false; /** Workarounds. */ bool GLContext::debug_layer_workaround = false; bool GLContext::unused_fb_slot_workaround = false; +bool GLContext::generate_mipmap_workaround = false; float GLContext::derivative_signs[2] = {1.0f, 1.0f}; void GLBackend::capabilities_init() diff --git a/source/blender/gpu/opengl/gl_context.hh b/source/blender/gpu/opengl/gl_context.hh index 0222adaba25..9273bfb9911 100644 --- a/source/blender/gpu/opengl/gl_context.hh +++ b/source/blender/gpu/opengl/gl_context.hh @@ -77,6 +77,7 @@ class GLContext : public Context { /** Workarounds. */ static bool debug_layer_workaround; static bool unused_fb_slot_workaround; + static bool generate_mipmap_workaround; static float derivative_signs[2]; /** VBO for missing vertex attrib binding. Avoid undefined behavior on some implementation. */ diff --git a/source/blender/gpu/opengl/gl_texture.cc b/source/blender/gpu/opengl/gl_texture.cc index db1fda63c28..f9c5a97a0bb 100644 --- a/source/blender/gpu/opengl/gl_texture.cc +++ b/source/blender/gpu/opengl/gl_texture.cc @@ -225,6 +225,8 @@ void GLTexture::update_sub_direct_state_access( break; } } + + has_pixels_ = true; } void GLTexture::update_sub( @@ -288,6 +290,8 @@ void GLTexture::update_sub( break; } } + + has_pixels_ = true; } /** @@ -307,6 +311,16 @@ void GLTexture::generate_mipmap() return; } + if (GLContext::generate_mipmap_workaround) { + /* Broken glGenerateMipmap, don't call it and render without mipmaps. + * If no top level pixels have been filled in, the levels will get filled by + * other means and there is no need to disable mipmapping. */ + if (has_pixels_) { + this->mip_range_set(0, 0); + } + return; + } + /* Down-sample from mip 0 using implementation. */ if (GLContext::direct_state_access_support) { glGenerateTextureMipmap(tex_id_); @@ -337,6 +351,8 @@ void GLTexture::clear(eGPUDataFormat data_format, const void *data) GPU_framebuffer_bind(prev_fb); } + + has_pixels_ = true; } void GLTexture::copy_to(Texture *dst_) @@ -363,6 +379,8 @@ void GLTexture::copy_to(Texture *dst_) GPU_framebuffer_blit( src->framebuffer_get(), 0, dst->framebuffer_get(), 0, to_framebuffer_bits(format_)); } + + has_pixels_ = true; } void *GLTexture::read(int mip, eGPUDataFormat type) @@ -452,6 +470,7 @@ struct GPUFrameBuffer *GLTexture::framebuffer_get() GPUTexture *gputex = reinterpret_cast<GPUTexture *>(static_cast<Texture *>(this)); framebuffer_ = GPU_framebuffer_create(name_); GPU_framebuffer_texture_attach(framebuffer_, gputex, 0, 0); + has_pixels_ = true; return framebuffer_; } diff --git a/source/blender/gpu/opengl/gl_texture.hh b/source/blender/gpu/opengl/gl_texture.hh index 2a480e71017..93c6b8d8af0 100644 --- a/source/blender/gpu/opengl/gl_texture.hh +++ b/source/blender/gpu/opengl/gl_texture.hh @@ -53,6 +53,8 @@ class GLTexture : public Texture { /** True if this texture is bound to at least one texture unit. */ /* TODO(fclem): How do we ensure thread safety here? */ bool is_bound_ = false; + /** True if pixels in the texture have been initialized. */ + bool has_pixels_ = false; public: GLTexture(const char *name); diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index c11c6d778a1..1d81653c7cd 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -58,6 +58,8 @@ #include "BLI_threads.h" #include "BLI_utildefines.h" +#include "DNA_scene_types.h" + #include "MEM_guardedalloc.h" #ifdef WITH_AVI @@ -939,14 +941,36 @@ static void ffmpeg_postprocess(struct anim *anim) } } -/* decode one video frame also considering the packet read into cur_packet */ +static void ffmpeg_decode_store_frame_pts(struct anim *anim) +{ + anim->cur_pts = av_get_pts_from_frame(anim->pFrame); + if (anim->pFrame->key_frame) { + anim->cur_key_frame_pts = anim->cur_pts; + } + + av_log(anim->pFormatCtx, + AV_LOG_DEBUG, + " FRAME DONE: cur_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n", + (anim->pFrame->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->pFrame->pts, + (int64_t)anim->cur_pts); +} + +/* decode one video frame also considering the packet read into cur_packet */ static int ffmpeg_decode_video_frame(struct anim *anim) { - int rval = 0; - av_log(anim->pFormatCtx, AV_LOG_DEBUG, " DECODE VIDEO FRAME\n"); + /* Sometimes, decoder returns more than one frame per sent packet. Check if frames are available. + * This frames must be read, otherwise decoding will fail. See T91405. */ + anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0; + if (anim->pFrameComplete) { + av_log(anim->pFormatCtx, AV_LOG_DEBUG, " DECODE FROM CODEC BUFFER\n"); + ffmpeg_decode_store_frame_pts(anim); + return 1; + } + + int rval = 0; if (anim->cur_packet->stream_index == anim->videoStream) { av_packet_unref(anim->cur_packet); anim->cur_packet->stream_index = -1; @@ -963,22 +987,11 @@ static int ffmpeg_decode_video_frame(struct anim *anim) (anim->cur_packet->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->cur_packet->pts, (anim->cur_packet->flags & AV_PKT_FLAG_KEY) ? " KEY" : ""); if (anim->cur_packet->stream_index == anim->videoStream) { - anim->pFrameComplete = 0; - avcodec_send_packet(anim->pCodecCtx, anim->cur_packet); anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0; if (anim->pFrameComplete) { - anim->cur_pts = av_get_pts_from_frame(anim->pFrame); - - if (anim->pFrame->key_frame) { - anim->cur_key_frame_pts = anim->cur_pts; - } - av_log(anim->pFormatCtx, - AV_LOG_DEBUG, - " FRAME DONE: cur_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n", - (anim->pFrame->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->pFrame->pts, - (int64_t)anim->cur_pts); + ffmpeg_decode_store_frame_pts(anim); break; } } @@ -988,22 +1001,11 @@ static int ffmpeg_decode_video_frame(struct anim *anim) if (rval == AVERROR_EOF) { /* Flush any remaining frames out of the decoder. */ - anim->pFrameComplete = 0; - avcodec_send_packet(anim->pCodecCtx, NULL); anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0; if (anim->pFrameComplete) { - anim->cur_pts = av_get_pts_from_frame(anim->pFrame); - - if (anim->pFrame->key_frame) { - anim->cur_key_frame_pts = anim->cur_pts; - } - av_log(anim->pFormatCtx, - AV_LOG_DEBUG, - " FRAME DONE (after EOF): cur_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n", - (anim->pFrame->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->pFrame->pts, - (int64_t)anim->cur_pts); + ffmpeg_decode_store_frame_pts(anim); rval = 0; } } @@ -1443,7 +1445,15 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Typ * * The issue was reported to FFmpeg under ticket #8747 in the FFmpeg tracker * and is fixed in the newer versions than 4.3.1. */ - anim->cur_frame_final = IMB_allocImBuf(anim->x, anim->y, 32, 0); + + const AVPixFmtDescriptor *pix_fmt_descriptor = av_pix_fmt_desc_get(anim->pCodecCtx->pix_fmt); + + int planes = R_IMF_PLANES_RGBA; + if ((pix_fmt_descriptor->flags & AV_PIX_FMT_FLAG_ALPHA) == 0) { + planes = R_IMF_PLANES_RGB; + } + + anim->cur_frame_final = IMB_allocImBuf(anim->x, anim->y, planes, 0); anim->cur_frame_final->rect = MEM_mallocN_aligned( (size_t)4 * anim->x * anim->y, 32, "ffmpeg ibuf"); anim->cur_frame_final->mall |= IB_rect; diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c index bbb0f3b5b22..6cd87e29c9d 100644 --- a/source/blender/imbuf/intern/indexer.c +++ b/source/blender/imbuf/intern/indexer.c @@ -183,13 +183,13 @@ struct anim_index *IMB_indexer_open(const char *name) header[12] = 0; if (memcmp(header, binary_header_str, 8) != 0) { - fprintf(stderr, "Error reading %s: Binary file type string missmatch\n", name); + fprintf(stderr, "Error reading %s: Binary file type string mismatch\n", name); fclose(fp); return NULL; } if (atoi(header + 9) != INDEX_FILE_VERSION) { - fprintf(stderr, "Error reading %s: File version missmatch\n", name); + fprintf(stderr, "Error reading %s: File version mismatch\n", name); fclose(fp); return NULL; } @@ -222,7 +222,7 @@ struct anim_index *IMB_indexer_open(const char *name) } if (UNLIKELY(items_read != idx->num_entries * 5)) { - fprintf(stderr, "Error: Element data size missmatch in: %s\n", name); + fprintf(stderr, "Error: Element data size mismatch in: %s\n", name); MEM_freeN(idx->entries); MEM_freeN(idx); fclose(fp); diff --git a/source/blender/imbuf/intern/moviecache.c b/source/blender/imbuf/intern/moviecache.c index 34c180ba1fb..773a3486233 100644 --- a/source/blender/imbuf/intern/moviecache.c +++ b/source/blender/imbuf/intern/moviecache.c @@ -122,11 +122,11 @@ static void moviecache_valfree(void *val) PRINT("%s: cache '%s' free item %p buffer %p\n", __func__, cache->name, item, item->ibuf); - BLI_mutex_lock(&limitor_lock); if (item->c_handle) { + BLI_mutex_lock(&limitor_lock); MEM_CacheLimiter_unmanage(item->c_handle); + BLI_mutex_unlock(&limitor_lock); } - BLI_mutex_unlock(&limitor_lock); if (item->ibuf) { IMB_freeImBuf(item->ibuf); @@ -242,6 +242,9 @@ static int get_item_priority(void *item_v, int default_priority) static bool get_item_destroyable(void *item_v) { MovieCacheItem *item = (MovieCacheItem *)item_v; + if (item->ibuf == NULL) { + return true; + } /* IB_BITMAPDIRTY means image was modified from inside blender and * changes are not saved to disk. * @@ -265,6 +268,7 @@ void IMB_moviecache_destruct(void) { if (limitor) { delete_MEM_CacheLimiter(limitor); + limitor = NULL; } } diff --git a/source/blender/io/alembic/exporter/abc_writer_mesh.cc b/source/blender/io/alembic/exporter/abc_writer_mesh.cc index 442ab6afcd0..7275d0addf0 100644 --- a/source/blender/io/alembic/exporter/abc_writer_mesh.cc +++ b/source/blender/io/alembic/exporter/abc_writer_mesh.cc @@ -190,6 +190,7 @@ void ABCGenericMeshWriter::do_write(HierarchyContext &context) m_custom_data_config.totpoly = mesh->totpoly; m_custom_data_config.totloop = mesh->totloop; m_custom_data_config.totvert = mesh->totvert; + m_custom_data_config.timesample_index = timesample_index_; try { if (is_subd_) { @@ -351,7 +352,7 @@ void ABCGenericMeshWriter::write_face_sets(Object *object, struct Mesh *mesh, Sc void ABCGenericMeshWriter::write_arb_geo_params(struct Mesh *me) { - if (frame_has_been_written_ || !args_.export_params->vcolors) { + if (!args_.export_params->vcolors) { return; } diff --git a/source/blender/io/alembic/intern/abc_customdata.cc b/source/blender/io/alembic/intern/abc_customdata.cc index 087d60f8896..188e8daac8f 100644 --- a/source/blender/io/alembic/intern/abc_customdata.cc +++ b/source/blender/io/alembic/intern/abc_customdata.cc @@ -176,29 +176,23 @@ static void write_uv(const OCompoundProperty &prop, UInt32ArraySample(&indices.front(), indices.size()), kFacevaryingScope); param.set(sample); + param.setTimeSampling(config.timesample_index); config.abc_uv_maps[uv_map_name] = param; } -/* Convention to write Vertex Colors: - * - C3fGeomParam/C4fGeomParam on the arbGeomParam - * - set scope as vertex varying - */ -static void write_mcol(const OCompoundProperty &prop, - const CDStreamConfig &config, - void *data, - const char *name) +static void get_cols(const CDStreamConfig &config, + std::vector<Imath::C4f> &buffer, + std::vector<uint32_t> &uvidx, + void *cd_data) { const float cscale = 1.0f / 255.0f; MPoly *polys = config.mpoly; MLoop *mloops = config.mloop; - MCol *cfaces = static_cast<MCol *>(data); - - std::vector<Imath::C4f> buffer; - std::vector<uint32_t> indices; + MCol *cfaces = static_cast<MCol *>(cd_data); buffer.reserve(config.totvert); - indices.reserve(config.totvert); + uvidx.reserve(config.totvert); Imath::C4f col; @@ -217,17 +211,44 @@ static void write_mcol(const OCompoundProperty &prop, col[3] = cface->b * cscale; buffer.push_back(col); - indices.push_back(buffer.size() - 1); + uvidx.push_back(buffer.size() - 1); } } +} + +/* Convention to write Vertex Colors: + * - C3fGeomParam/C4fGeomParam on the arbGeomParam + * - set scope as vertex varying + */ +static void write_mcol(const OCompoundProperty &prop, + CDStreamConfig &config, + void *data, + const char *name) +{ + std::vector<uint32_t> indices; + std::vector<Imath::C4f> buffer; + + get_cols(config, buffer, indices, data); + + if (indices.empty() || buffer.empty()) { + return; + } - OC4fGeomParam param(prop, name, true, kFacevaryingScope, 1); + std::string vcol_name(name); + OC4fGeomParam param = config.abc_vertex_colors[vcol_name]; + + if (!param.valid()) { + param = OC4fGeomParam(prop, name, true, kFacevaryingScope, 1); + } OC4fGeomParam::Sample sample(C4fArraySample(&buffer.front(), buffer.size()), UInt32ArraySample(&indices.front(), indices.size()), kVertexScope); param.set(sample); + param.setTimeSampling(config.timesample_index); + + config.abc_vertex_colors[vcol_name] = param; } void write_generated_coordinates(const OCompoundProperty &prop, CDStreamConfig &config) diff --git a/source/blender/io/alembic/intern/abc_customdata.h b/source/blender/io/alembic/intern/abc_customdata.h index 03e6f697f0c..5eae6307474 100644 --- a/source/blender/io/alembic/intern/abc_customdata.h +++ b/source/blender/io/alembic/intern/abc_customdata.h @@ -66,6 +66,7 @@ struct CDStreamConfig { float weight; float time; + int timesample_index; bool use_vertex_interpolation; Alembic::AbcGeom::index_t index; Alembic::AbcGeom::index_t ceil_index; @@ -82,6 +83,9 @@ struct CDStreamConfig { /* ORCO coordinates, aka Generated Coordinates. */ Alembic::AbcGeom::OV3fGeomParam abc_orco; + /* Mapping from vertex color layer name to its Alembic color data. */ + std::map<std::string, Alembic::AbcGeom::OC4fGeomParam> abc_vertex_colors; + CDStreamConfig() : mloop(NULL), totloop(0), diff --git a/source/blender/io/avi/intern/avi.c b/source/blender/io/avi/intern/avi.c index 87058693378..221e56ac793 100644 --- a/source/blender/io/avi/intern/avi.c +++ b/source/blender/io/avi/intern/avi.c @@ -591,7 +591,7 @@ AviError AVI_open_movie(const char *name, AviMovie *movie) BLI_fseek(movie->fp, size - 4, SEEK_CUR); if (GET_FCC(movie->fp) != FCC("idx1")) { - DEBUG_PRINT("bad index informatio\n"); + DEBUG_PRINT("bad index information\n"); return AVI_ERROR_FORMAT; } diff --git a/source/blender/io/collada/AnimationExporter.cpp b/source/blender/io/collada/AnimationExporter.cpp index 9ba59c0414d..56274e7e6ca 100644 --- a/source/blender/io/collada/AnimationExporter.cpp +++ b/source/blender/io/collada/AnimationExporter.cpp @@ -549,7 +549,7 @@ void AnimationExporter::add_source_parameters(COLLADASW::SourceBase::ParameterNa param.push_back("TRANSFORM"); } else { - /* assumes if axis isn't specified all axises are added */ + /* assumes if axis isn't specified all axes are added */ param.push_back("X"); param.push_back("Y"); param.push_back("Z"); diff --git a/source/blender/io/common/intern/abstract_hierarchy_iterator.cc b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc index 28d5eb59e5e..bfd91620654 100644 --- a/source/blender/io/common/intern/abstract_hierarchy_iterator.cc +++ b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc @@ -681,6 +681,15 @@ void AbstractHierarchyIterator::make_writers_particle_systems( writer = ensure_writer(&hair_context, &AbstractHierarchyIterator::create_hair_writer); break; case PART_EMITTER: + case PART_FLUID_FLIP: + case PART_FLUID_SPRAY: + case PART_FLUID_BUBBLE: + case PART_FLUID_FOAM: + case PART_FLUID_TRACER: + case PART_FLUID_SPRAYFOAM: + case PART_FLUID_SPRAYBUBBLE: + case PART_FLUID_FOAMBUBBLE: + case PART_FLUID_SPRAYFOAMBUBBLE: writer = ensure_writer(&hair_context, &AbstractHierarchyIterator::create_particle_writer); break; } diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index d829d707a71..2c04d0b06ef 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -211,11 +211,15 @@ typedef struct IDOverrideLibraryPropertyOperation { char _pad0[2]; /* Sub-item references, if needed (for arrays or collections only). - * We need both reference and local values to allow e.g. insertion into collections + * We need both reference and local values to allow e.g. insertion into RNA collections * (constraints, modifiers...). - * In collection case, if names are defined, they are used in priority. - * Names are pointers (instead of char[64]) to save some space, NULL when unset. - * Indices are -1 when unset. */ + * In RNA collection case, if names are defined, they are used in priority. + * Names are pointers (instead of char[64]) to save some space, NULL or empty string when unset. + * Indices are -1 when unset. + * + * NOTE: For insertion operations in RNA collections, reference may not actually exist in the + * linked reference data. It is used to identify the anchor of the insertion operation (i.e. the + * item after or before which the new local item should be inserted), in the local override. */ char *subitem_reference_name; char *subitem_local_name; int subitem_reference_index; diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index 6dc2d00252f..d587bd8082b 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -728,7 +728,7 @@ typedef enum eBConstraint_Flags { /* bConstraint->ownspace/tarspace */ typedef enum eBConstraint_SpaceTypes { - /** Default for all - worldspace. */ + /** Default for all - world-space. */ CONSTRAINT_SPACE_WORLD = 0, /** For all - custom space. */ CONSTRAINT_SPACE_CUSTOM = 5, diff --git a/source/blender/makesdna/DNA_fluid_types.h b/source/blender/makesdna/DNA_fluid_types.h index 0cbef540306..d8065410f2b 100644 --- a/source/blender/makesdna/DNA_fluid_types.h +++ b/source/blender/makesdna/DNA_fluid_types.h @@ -513,7 +513,7 @@ typedef struct FluidDomainSettings { float p1[3]; /* End point of BB in local space. */ float dp0[3]; /* Difference from object center to grid start point. */ float cell_size[3]; /* Size of simulation cell in local space. */ - float global_size[3]; /* Global size of domain axises. */ + float global_size[3]; /* Global size of domain axes. */ float prev_loc[3]; int shift[3]; /* Current domain shift in simulation cells. */ float shift_f[3]; /* Exact domain shift. */ @@ -694,7 +694,7 @@ typedef struct FluidDomainSettings { char openvdb_data_depth; char _pad11[7]; /* Unused. */ - /* -- Deprecated / unsed options (below). -- */ + /* -- Deprecated / unused options (below). -- */ /* View options. */ int viewsettings; diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h index 520f989452c..63e4597150c 100644 --- a/source/blender/makesdna/DNA_layer_types.h +++ b/source/blender/makesdna/DNA_layer_types.h @@ -68,7 +68,7 @@ typedef enum eViewLayerCryptomatteFlags { VIEW_LAYER_CRYPTOMATTE_OBJECT = (1 << 0), VIEW_LAYER_CRYPTOMATTE_MATERIAL = (1 << 1), VIEW_LAYER_CRYPTOMATTE_ASSET = (1 << 2), - /* VIEW_LAYER_CRYPTOMATTE_ACCURATE = (1 << 3), */ /* DEPRECATED */ + VIEW_LAYER_CRYPTOMATTE_ACCURATE = (1 << 3), } eViewLayerCryptomatteFlags; #define VIEW_LAYER_CRYPTOMATTE_ALL \ (VIEW_LAYER_CRYPTOMATTE_OBJECT | VIEW_LAYER_CRYPTOMATTE_MATERIAL | VIEW_LAYER_CRYPTOMATTE_ASSET) diff --git a/source/blender/makesdna/DNA_lightprobe_types.h b/source/blender/makesdna/DNA_lightprobe_types.h index 038de8e49cc..1a3bda34a84 100644 --- a/source/blender/makesdna/DNA_lightprobe_types.h +++ b/source/blender/makesdna/DNA_lightprobe_types.h @@ -149,7 +149,7 @@ BLI_STATIC_ASSERT_ALIGN(LightGridCache, 16) typedef struct LightCacheTexture { struct GPUTexture *tex; - /** Copy of GPU datas to create GPUTextures on file read. */ + /** Copy of GPU data to create GPUTextures on file read. */ char *data; int tex_size[3]; char data_type; diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index cfe34d83586..59cf4da26f6 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -302,7 +302,7 @@ typedef struct bNode { char _pad1[4]; - /** Entire boundbox (worldspace). */ + /** Entire boundbox (world-space). */ rctf totr; /** Optional buttons area. */ rctf butr; diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index e94541fdc7f..57c8ef200ae 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -311,7 +311,7 @@ typedef struct Object { float rotAxis[3], drotAxis[3]; /** Axis angle rotation - angle part. */ float rotAngle, drotAngle; - /** Final worldspace matrix with constraints & animsys applied. */ + /** Final world-space 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]; diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index eeff5473d16..634e97f782f 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -2066,6 +2066,9 @@ enum { #define SCE_SNAP_MODE_VOLUME (1 << 3) #define SCE_SNAP_MODE_EDGE_MIDPOINT (1 << 4) #define SCE_SNAP_MODE_EDGE_PERPENDICULAR (1 << 5) +#define SCE_SNAP_MODE_GEOM \ + (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | \ + SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT) /** #SequencerToolSettings.snap_mode */ #define SEQ_SNAP_TO_STRIPS (1 << 0) diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index 86fd6b9744a..f15767ff692 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -458,6 +458,9 @@ typedef struct ARegion_Runtime { /* The offset needed to not overlap with window scrollbars. Only used by HUD regions for now. */ int offset_x, offset_y; + + /* Maps uiBlock->name to uiBlock for faster lookups. */ + struct GHash *block_name_map; } ARegion_Runtime; typedef struct ARegion { @@ -667,7 +670,7 @@ typedef enum eRegion_Type { RGN_TYPE_FOOTER = 11, RGN_TYPE_TOOL_HEADER = 12, /* Region type used exclusively by internal code and add-ons to register draw callbacks to the XR - context (surface, mirror view). Does not represent any real region. */ + * context (surface, mirror view). Does not represent any real region. */ RGN_TYPE_XR = 13, #define RGN_TYPE_LEN (RGN_TYPE_XR + 1) diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index fc23d3c69a3..9e6cf907444 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -378,7 +378,7 @@ typedef struct TextVars { char text[512]; struct VFont *text_font; int text_blf_id; - int text_size; + float text_size; float color[4], shadow_color[4], box_color[4]; float loc[2]; float wrap_width; diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 671cc182d7e..7fb15fc8508 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -64,7 +64,7 @@ struct wmTimer; /* Defined in `buttons_intern.h`. */ typedef struct SpaceProperties_Runtime SpaceProperties_Runtime; -/* Defined in `node_intern.h`. */ +/* Defined in `node_intern.hh`. */ typedef struct SpaceNode_Runtime SpaceNode_Runtime; /* Defined in `file_intern.h`. */ @@ -1158,8 +1158,12 @@ typedef struct FileDirEntryArr { /* FileDirEntry.flags */ enum { - FILE_ENTRY_INVALID_PREVIEW = 1 << 0, /* The preview for this entry could not be generated. */ + /* The preview for this entry could not be generated. */ + FILE_ENTRY_INVALID_PREVIEW = 1 << 0, + /* The entry name needs to be freed when clearing file list. */ FILE_ENTRY_NAME_FREE = 1 << 1, + /* The preview for this entry is being loaded on another thread. */ + FILE_ENTRY_PREVIEW_LOADING = 1 << 2, }; /** \} */ diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index ee33e8666ec..2c3cd8eab77 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -128,9 +128,9 @@ typedef struct PointDensity { struct Object *object; /** `index + 1` in ob.particlesystem, non-ID pointer not allowed */ int psys; - /** cache points in worldspace, object space, ... ? */ + /** cache points in world-space, object space, ... ? */ short psys_cache_space; - /** cache points in worldspace, object space, ... ? */ + /** cache points in world-space, object space, ... ? */ short ob_cache_space; /** vertex attribute layer for color source, MAX_CUSTOMDATA_LAYER_NAME */ char vertex_attribute_name[64]; diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index f80fcb9ae78..c8fdac19b61 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -69,8 +69,9 @@ typedef struct uiFont { typedef struct uiFontStyle { /** Saved in file, 0 is default. */ short uifont_id; + char _pad1[2]; /** Actual size depends on 'global' dpi. */ - short points; + float points; /** Style hint. */ short italic, bold; /** Value is amount of pixels blur. */ @@ -82,6 +83,7 @@ typedef struct uiFontStyle { float shadowalpha; /** 1 value, typically white or black anyway. */ float shadowcolor; + char _pad2[4]; } uiFontStyle; /* this is fed to the layout engine and widget code */ @@ -650,6 +652,7 @@ typedef struct UserDef_Experimental { char no_proxy_to_override_conversion; char use_cycles_debug; char use_geometry_nodes_legacy; + char show_asset_debug_info; char SANITIZE_AFTER_HERE; /* The following options are automatically sanitized (set to 0) * when the release cycle is not alpha. */ @@ -660,7 +663,7 @@ typedef struct UserDef_Experimental { char use_sculpt_tools_tilt; char use_extended_asset_browser; char use_override_templates; - char _pad[3]; + char _pad[2]; /** `makesdna` does not allow empty structs. */ } UserDef_Experimental; @@ -938,7 +941,8 @@ typedef struct UserDef { short sequencer_proxy_setup; /* eUserpref_SeqProxySetup */ float collection_instance_empty_size; - char _pad10[2]; + char text_flag; + char _pad10[1]; char file_preview_type; /* eUserpref_File_Preview_Type */ char statusbar_flag; /* eUserpref_StatusBar_Flag */ @@ -1263,6 +1267,14 @@ typedef enum eDupli_ID_Flags { } eDupli_ID_Flags; /** + * Text Editor options + * #UserDef.text_flag + */ +typedef enum eTextEdit_Flags { + USER_TEXT_EDIT_AUTO_CLOSE = (1 << 0), +} eTextEdit_Flags; + +/** * Text draw options * #UserDef.text_render */ diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index 9b5ed133feb..3fd2f1208dd 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -64,8 +64,10 @@ typedef struct RegionView3D { /** User defined clipping planes. */ float clip[6][4]; - /** Clip in object space, - * means we can test for clipping in editmode without first going into worldspace. */ + /** + * Clip in object space, + * means we can test for clipping in edit-mode without first going into world-space. + */ float clip_local[6][4]; struct BoundBox *clipbb; @@ -94,8 +96,8 @@ typedef struct RegionView3D { /** Runtime only. */ float pixsize; /** - * View center & orbit pivot, negative of worldspace location, - * also matches -viewinv[3][0:3] in ortho mode. + * View center & orbit pivot, negative of world-space location, + * also matches `-viewinv[3][0:3]` in orthographic mode. */ float ofs[3]; /** Viewport zoom on the camera frame, see BKE_screen_view3d_zoom_to_fac. */ diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index f2e87b29c1f..a6732ca1760 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -4698,6 +4698,19 @@ static const char *cpp_classes = " inline static int sname##_##identifier##_length_wrap(PointerRNA *ptr) \\\n" " { return sname##_##identifier##_length(ptr); } \n" "\n" + "#define COLLECTION_PROPERTY_EMPTY_false(sname, identifier) \\\n" + " inline static bool sname##_##identifier##_empty_wrap(PointerRNA *ptr) \\\n" + " { \\\n" + " CollectionPropertyIterator iter; \\\n" + " sname##_##identifier##_begin(&iter, ptr); \\\n" + " bool empty = !iter.valid; \\\n" + " sname##_##identifier##_end(&iter); \\\n" + " return empty; \\\n" + " } \n" + "#define COLLECTION_PROPERTY_EMPTY_true(sname, identifier) \\\n" + " inline static bool sname##_##identifier##_empty_wrap(PointerRNA *ptr) \\\n" + " { return sname##_##identifier##_length(ptr) == 0; } \n" + "\n" "#define COLLECTION_PROPERTY_LOOKUP_INT_false(sname, identifier) \\\n" " inline static int sname##_##identifier##_lookup_int_wrap(PointerRNA *ptr, int key, " "PointerRNA *r_ptr) \\\n" @@ -4774,11 +4787,13 @@ static const char *cpp_classes = " typedef CollectionIterator<type, sname##_##identifier##_begin, \\\n" " sname##_##identifier##_next, sname##_##identifier##_end> identifier##_iterator; \\\n" " COLLECTION_PROPERTY_LENGTH_##has_length(sname, identifier) \\\n" + " COLLECTION_PROPERTY_EMPTY_##has_length(sname, identifier) \\\n" " COLLECTION_PROPERTY_LOOKUP_INT_##has_lookup_int(sname, identifier) \\\n" " COLLECTION_PROPERTY_LOOKUP_STRING_##has_lookup_string(sname, identifier) \\\n" " CollectionRef<sname, type, sname##_##identifier##_begin, \\\n" " sname##_##identifier##_next, sname##_##identifier##_end, \\\n" " sname##_##identifier##_length_wrap, \\\n" + " sname##_##identifier##_empty_wrap, \\\n" " sname##_##identifier##_lookup_int_wrap, sname##_##identifier##_lookup_string_wrap, " "collection_funcs> identifier;\n" "\n" @@ -4844,6 +4859,7 @@ static const char *cpp_classes = "typedef void (*TNextFunc)(CollectionPropertyIterator *iter);\n" "typedef void (*TEndFunc)(CollectionPropertyIterator *iter);\n" "typedef int (*TLengthFunc)(PointerRNA *ptr);\n" + "typedef bool (*TEmptyFunc)(PointerRNA *ptr);\n" "typedef int (*TLookupIntFunc)(PointerRNA *ptr, int key, PointerRNA *r_ptr);\n" "typedef int (*TLookupStringFunc)(PointerRNA *ptr, const char *key, PointerRNA *r_ptr);\n" "\n" @@ -4882,8 +4898,8 @@ static const char *cpp_classes = "};\n" "\n" "template<typename Tp, typename T, TBeginFunc Tbegin, TNextFunc Tnext, TEndFunc Tend,\n" - " TLengthFunc Tlength, TLookupIntFunc Tlookup_int, TLookupStringFunc Tlookup_string,\n" - " typename Tcollection_funcs>\n" + " TLengthFunc Tlength, TEmptyFunc Tempty, TLookupIntFunc Tlookup_int,\n" + " TLookupStringFunc Tlookup_string, typename Tcollection_funcs>\n" "class CollectionRef : public Tcollection_funcs {\n" "public:\n" " CollectionRef(const PointerRNA &p) : Tcollection_funcs(p), ptr(p) {}\n" @@ -4897,6 +4913,8 @@ static const char *cpp_classes = "" " int length()\n" " { return Tlength(&ptr); }\n" + " bool empty()\n" + " { return Tempty(&ptr); }\n" " T operator[](int key)\n" " { PointerRNA r_ptr; Tlookup_int(&ptr, key, &r_ptr); return T(r_ptr); }\n" " T operator[](const std::string &key)\n" diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c index 52c25bae45a..9068fdb6e72 100644 --- a/source/blender/makesrna/intern/rna_animation.c +++ b/source/blender/makesrna/intern/rna_animation.c @@ -761,8 +761,8 @@ bool rna_NLA_tracks_override_apply(Main *bmain, /* This is not working so well with index-based insertion, especially in case some tracks get * added to lib linked data. So we simply add locale tracks at the end of the list always, order * of override operations should ensure order of local tracks is preserved properly. */ - if (opop->subitem_local_index >= 0) { - nla_track_anchor = BLI_findlink(&anim_data_dst->nla_tracks, opop->subitem_local_index); + if (opop->subitem_reference_index >= 0) { + nla_track_anchor = BLI_findlink(&anim_data_dst->nla_tracks, opop->subitem_reference_index); } /* Otherwise we just insert in first position. */ # else @@ -773,9 +773,11 @@ bool rna_NLA_tracks_override_apply(Main *bmain, if (opop->subitem_local_index >= 0) { nla_track_src = BLI_findlink(&anim_data_src->nla_tracks, opop->subitem_local_index); } - nla_track_src = nla_track_src ? nla_track_src->next : anim_data_src->nla_tracks.first; - BLI_assert(nla_track_src != NULL); + if (nla_track_src == NULL) { + BLI_assert(nla_track_src != NULL); + return false; + } NlaTrack *nla_track_dst = BKE_nlatrack_copy(bmain, nla_track_src, true, 0); diff --git a/source/blender/makesrna/intern/rna_animviz.c b/source/blender/makesrna/intern/rna_animviz.c index b205b3d7139..1511921cef0 100644 --- a/source/blender/makesrna/intern/rna_animviz.c +++ b/source/blender/makesrna/intern/rna_animviz.c @@ -117,7 +117,7 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna) srna = RNA_def_struct(brna, "MotionPath", NULL); RNA_def_struct_sdna(srna, "bMotionPath"); RNA_def_struct_ui_text( - srna, "Motion Path", "Cache of the worldspace positions of an element over a frame range"); + srna, "Motion Path", "Cache of the world-space positions of an element over a frame range"); /* Collections */ prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_asset.c b/source/blender/makesrna/intern/rna_asset.c index 5d83da170b5..0d25a0ba079 100644 --- a/source/blender/makesrna/intern/rna_asset.c +++ b/source/blender/makesrna/intern/rna_asset.c @@ -307,7 +307,7 @@ const EnumPropertyItem *rna_asset_library_reference_itemf(bContext *UNUSED(C), PropertyRNA *UNUSED(prop), bool *r_free) { - const EnumPropertyItem *items = ED_asset_library_reference_to_rna_enum_itemf(); + const EnumPropertyItem *items = ED_asset_library_reference_to_rna_enum_itemf(true); if (!items) { *r_free = false; } diff --git a/source/blender/makesrna/intern/rna_attribute.c b/source/blender/makesrna/intern/rna_attribute.c index dbf20896463..78c15444308 100644 --- a/source/blender/makesrna/intern/rna_attribute.c +++ b/source/blender/makesrna/intern/rna_attribute.c @@ -72,6 +72,7 @@ const EnumPropertyItem rna_enum_attribute_domain_items[] = { /* Not implement yet */ // {ATTR_DOMAIN_GRIDS, "GRIDS", 0, "Grids", "Attribute on mesh multires grids"}, {ATTR_DOMAIN_CURVE, "CURVE", 0, "Spline", "Attribute on spline"}, + {ATTR_DOMAIN_INSTANCE, "INSTANCE", 0, "Instance", "Attribute on instance"}, {0, NULL, 0, NULL, NULL}, }; @@ -80,6 +81,7 @@ const EnumPropertyItem rna_enum_attribute_domain_without_corner_items[] = { {ATTR_DOMAIN_EDGE, "EDGE", 0, "Edge", "Attribute on mesh edge"}, {ATTR_DOMAIN_FACE, "FACE", 0, "Face", "Attribute on mesh faces"}, {ATTR_DOMAIN_CURVE, "CURVE", 0, "Spline", "Attribute on spline"}, + {ATTR_DOMAIN_INSTANCE, "INSTANCE", 0, "Instance", "Attribute on instance"}, {0, NULL, 0, NULL, NULL}, }; @@ -90,6 +92,7 @@ const EnumPropertyItem rna_enum_attribute_domain_with_auto_items[] = { {ATTR_DOMAIN_FACE, "FACE", 0, "Face", "Attribute on mesh faces"}, {ATTR_DOMAIN_CORNER, "CORNER", 0, "Face Corner", "Attribute on mesh face corner"}, {ATTR_DOMAIN_CURVE, "CURVE", 0, "Spline", "Attribute on spline"}, + {ATTR_DOMAIN_INSTANCE, "INSTANCE", 0, "Instance", "Attribute on instance"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 1d3b8cd9f9c..b4cf15ebfc6 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -1283,7 +1283,7 @@ static void rna_def_gpencil_options(BlenderRNA *brna) static EnumPropertyItem gppaint_mode_types_items[] = { {GPPAINT_MODE_STROKE, "STROKE", 0, "Stroke", "Vertex Color affects to Stroke only"}, {GPPAINT_MODE_FILL, "FILL", 0, "Fill", "Vertex Color affects to Fill only"}, - {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke and Fill", "Vertex Color affects to Stroke and Fill"}, + {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke & Fill", "Vertex Color affects to Stroke and Fill"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 5968c8bac8f..bde348c1848 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -3474,6 +3474,15 @@ void RNA_def_constraint(BlenderRNA *brna) RNA_def_property_enum_items(prop, rna_enum_constraint_type_items); RNA_def_property_ui_text(prop, "Type", ""); + prop = RNA_def_boolean(srna, + "is_override_data", + false, + "Override Constraint", + "In a local override object, whether this constraint comes from the " + "linked reference object, or is local to the override"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", CONSTRAINT_OVERRIDE_LIBRARY_LOCAL); + RNA_define_lib_overridable(true); prop = RNA_def_property(srna, "owner_space", PROP_ENUM, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c index 85071e8cd19..58565fecf4d 100644 --- a/source/blender/makesrna/intern/rna_depsgraph.c +++ b/source/blender/makesrna/intern/rna_depsgraph.c @@ -207,8 +207,10 @@ static bool rna_DepsgraphUpdate_is_updated_transform_get(PointerRNA *ptr) static bool rna_DepsgraphUpdate_is_updated_shading_get(PointerRNA *ptr) { + /* Assume any animated parameters can affect shading, we don't have fine + * grained enough updates to distinguish this. */ ID *id = ptr->data; - return ((id->recalc & ID_RECALC_SHADING) != 0); + return ((id->recalc & (ID_RECALC_SHADING | ID_RECALC_ANIMATION)) != 0); } static bool rna_DepsgraphUpdate_is_updated_geometry_get(PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index c4efe5a0ea1..82f3279146a 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -167,14 +167,14 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = { #ifndef RNA_RUNTIME static const EnumPropertyItem modifier_modify_color_items[] = { - {GP_MODIFY_COLOR_BOTH, "BOTH", 0, "Stroke and Fill", "Modify fill and stroke colors"}, + {GP_MODIFY_COLOR_BOTH, "BOTH", 0, "Stroke & Fill", "Modify fill and stroke colors"}, {GP_MODIFY_COLOR_STROKE, "STROKE", 0, "Stroke", "Modify stroke color only"}, {GP_MODIFY_COLOR_FILL, "FILL", 0, "Fill", "Modify fill color only"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem modifier_modify_opacity_items[] = { - {GP_MODIFY_COLOR_BOTH, "BOTH", 0, "Stroke and Fill", "Modify fill and stroke colors"}, + {GP_MODIFY_COLOR_BOTH, "BOTH", 0, "Stroke & Fill", "Modify fill and stroke colors"}, {GP_MODIFY_COLOR_STROKE, "STROKE", 0, "Stroke", "Modify stroke color only"}, {GP_MODIFY_COLOR_FILL, "FILL", 0, "Fill", "Modify fill color only"}, {GP_MODIFY_COLOR_HARDNESS, "HARDNESS", 0, "Hardness", "Modify stroke hardness"}, @@ -1450,7 +1450,7 @@ static void rna_def_modifier_gpenciltint(BlenderRNA *brna) static EnumPropertyItem tint_mode_types_items[] = { {GPPAINT_MODE_STROKE, "STROKE", 0, "Stroke", "Vertex Color affects to Stroke only"}, {GPPAINT_MODE_FILL, "FILL", 0, "Fill", "Vertex Color affects to Fill only"}, - {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke and Fill", "Vertex Color affects to Stroke and Fill"}, + {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke & Fill", "Vertex Color affects to Stroke and Fill"}, {0, NULL, 0, NULL, NULL}, }; @@ -2677,7 +2677,7 @@ static void rna_def_modifier_gpenciltexture(BlenderRNA *brna) {STROKE_AND_FILL, "STROKE_AND_FILL", 0, - "Stroke and Fill", + "Stroke & Fill", "Manipulate both stroke and fill texture coordinates"}, {0, NULL, 0, NULL, NULL}, }; @@ -3738,6 +3738,16 @@ void RNA_def_greasepencil_modifier(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Expanded", "Set modifier expanded in the user interface"); RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1); + prop = RNA_def_boolean(srna, + "is_override_data", + false, + "Override Modifier", + "In a local override object, whether this modifier comes from the linked " + "reference object, or is local to the override"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_boolean_negative_sdna( + prop, NULL, "flag", eGpencilModifierFlag_OverrideLibrary_Local); + /* types */ rna_def_modifier_gpencilnoise(brna); rna_def_modifier_gpencilsmooth(brna); diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index fbc578acb8e..5a937e6b06b 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -1507,12 +1507,15 @@ static int rna_Mesh_tot_face_get(PointerRNA *ptr) return me->edit_mesh ? me->edit_mesh->bm->totfacesel : 0; } -static PointerRNA rna_Mesh_vertex_color_new(struct Mesh *me, const char *name, const bool do_init) +static PointerRNA rna_Mesh_vertex_color_new(struct Mesh *me, + ReportList *reports, + const char *name, + const bool do_init) { PointerRNA ptr; CustomData *ldata; CustomDataLayer *cdl = NULL; - int index = ED_mesh_color_add(me, name, false, do_init); + int index = ED_mesh_color_add(me, name, false, do_init, reports); if (index != -1) { ldata = rna_mesh_ldata_helper(me); @@ -1533,13 +1536,14 @@ static void rna_Mesh_vertex_color_remove(struct Mesh *me, } static PointerRNA rna_Mesh_sculpt_vertex_color_new(struct Mesh *me, + ReportList *reports, const char *name, const bool do_init) { PointerRNA ptr; CustomData *vdata; CustomDataLayer *cdl = NULL; - int index = ED_mesh_sculpt_color_add(me, name, false, do_init); + int index = ED_mesh_sculpt_color_add(me, name, false, do_init, reports); if (index != -1) { vdata = rna_mesh_vdata_helper(me); @@ -1591,12 +1595,15 @@ DEFINE_CUSTOMDATA_PROPERTY_API( polygon, string, CD_PROP_STRING, pdata, totpoly, MeshPolygonStringPropertyLayer) # undef DEFINE_CUSTOMDATA_PROPERTY_API -static PointerRNA rna_Mesh_uv_layers_new(struct Mesh *me, const char *name, const bool do_init) +static PointerRNA rna_Mesh_uv_layers_new(struct Mesh *me, + ReportList *reports, + const char *name, + const bool do_init) { PointerRNA ptr; CustomData *ldata; CustomDataLayer *cdl = NULL; - int index = ED_mesh_uv_texture_add(me, name, false, do_init); + int index = ED_mesh_uv_texture_add(me, name, false, do_init, reports); if (index != -1) { ldata = rna_mesh_ldata_helper(me); @@ -2520,6 +2527,7 @@ static void rna_def_loop_colors(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_Mesh_vertex_color_new"); RNA_def_function_ui_description(func, "Add a vertex color layer to Mesh"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_string(func, "name", "Col", 0, "", "Vertex color name"); RNA_def_boolean(func, "do_init", @@ -2569,6 +2577,7 @@ static void rna_def_vert_colors(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_Mesh_sculpt_vertex_color_new"); RNA_def_function_ui_description(func, "Add a sculpt vertex color layer to Mesh"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_string(func, "name", "Col", 0, "", "Sculpt Vertex color name"); RNA_def_boolean(func, "do_init", @@ -2622,6 +2631,7 @@ static void rna_def_uv_layers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_struct_ui_text(srna, "UV Loop Layers", "Collection of uv loop layers"); func = RNA_def_function(srna, "new", "rna_Mesh_uv_layers_new"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Add a UV map layer to Mesh"); RNA_def_string(func, "name", "UVMap", 0, "", "UV map name"); RNA_def_boolean(func, diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 028b6b6e11f..9ad6771cda3 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -7245,6 +7245,15 @@ void RNA_def_modifier(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Active", "The active modifier in the list"); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); + prop = RNA_def_boolean(srna, + "is_override_data", + false, + "Override Modifier", + "In a local override object, whether this modifier comes from the linked " + "reference object, or is local to the override"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", eModifierFlag_OverrideLibrary_Local); + prop = RNA_def_property(srna, "use_apply_on_spline", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mode", eModifierMode_ApplyOnSpline); RNA_def_property_ui_text( diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c index d0711f28a6e..230133a8f9d 100644 --- a/source/blender/makesrna/intern/rna_nla.c +++ b/source/blender/makesrna/intern/rna_nla.c @@ -887,6 +887,15 @@ static void rna_def_nlatrack(BlenderRNA *brna) rna_api_nlatrack_strips(brna, prop); + prop = RNA_def_boolean(srna, + "is_override_data", + false, + "Override Track", + "In a local override data, whether this NLA track comes from the linked " + "reference data, or is local to the override"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", NLATRACK_OVERRIDELIBRARY_LOCAL); + RNA_define_lib_overridable(true); /* name property */ diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 53b3f07dbbc..aef3823338b 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -2805,6 +2805,7 @@ static StructRNA *rna_NodeSocket_register(Main *UNUSED(bmain), /* setup dummy socket & socket type to store static properties in */ memset(&dummyst, 0, sizeof(bNodeSocketType)); + dummyst.type = SOCK_CUSTOM; memset(&dummysock, 0, sizeof(bNodeSocket)); dummysock.typeinfo = &dummyst; diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 99865078cbe..0cb132786cd 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -1673,6 +1673,7 @@ static bConstraint *rna_Object_constraints_copy(Object *object, Main *bmain, Poi { bConstraint *con = con_ptr->data; bConstraint *new_con = BKE_constraint_copy_for_object(object, con); + new_con->flag |= CONSTRAINT_OVERRIDE_LIBRARY_LOCAL; ED_object_constraint_tag_update(bmain, object, new_con); WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT | NA_ADDED, object); @@ -1704,27 +1705,20 @@ bool rna_Object_constraints_override_apply(Main *UNUSED(bmain), /* Remember that insertion operations are defined and stored in correct order, which means that * even if we insert several items in a row, we always insert first one, then second one, etc. * So we should always find 'anchor' constraint in both _src *and* _dst. */ - bConstraint *con_anchor = NULL; - if (opop->subitem_local_name && opop->subitem_local_name[0]) { - con_anchor = BLI_findstring( - &ob_dst->constraints, opop->subitem_local_name, offsetof(bConstraint, name)); - } - if (con_anchor == NULL && opop->subitem_local_index >= 0) { - con_anchor = BLI_findlink(&ob_dst->constraints, opop->subitem_local_index); - } - /* Otherwise we just insert in first position. */ - - bConstraint *con_src = NULL; - if (opop->subitem_local_name && opop->subitem_local_name[0]) { - con_src = BLI_findstring( - &ob_src->constraints, opop->subitem_local_name, offsetof(bConstraint, name)); - } - if (con_src == NULL && opop->subitem_local_index >= 0) { - con_src = BLI_findlink(&ob_src->constraints, opop->subitem_local_index); + const size_t name_offset = offsetof(bConstraint, name); + bConstraint *con_anchor = BLI_listbase_string_or_index_find(&ob_dst->constraints, + opop->subitem_reference_name, + name_offset, + opop->subitem_reference_index); + /* If `con_anchor` is NULL, `con_src` will be inserted in first position. */ + + bConstraint *con_src = BLI_listbase_string_or_index_find( + &ob_src->constraints, opop->subitem_local_name, name_offset, opop->subitem_local_index); + + if (con_src == NULL) { + BLI_assert(con_src != NULL); + return false; } - con_src = con_src ? con_src->next : ob_src->constraints.first; - - BLI_assert(con_src != NULL); bConstraint *con_dst = BKE_constraint_duplicate_ex(con_src, 0, true); @@ -1826,25 +1820,15 @@ bool rna_Object_modifiers_override_apply(Main *bmain, /* Remember that insertion operations are defined and stored in correct order, which means that * even if we insert several items in a row, we always insert first one, then second one, etc. * So we should always find 'anchor' modifier in both _src *and* _dst. */ - ModifierData *mod_anchor = NULL; - if (opop->subitem_local_name && opop->subitem_local_name[0]) { - mod_anchor = BLI_findstring( - &ob_dst->modifiers, opop->subitem_local_name, offsetof(ModifierData, name)); - } - if (mod_anchor == NULL && opop->subitem_local_index >= 0) { - mod_anchor = BLI_findlink(&ob_dst->modifiers, opop->subitem_local_index); - } - /* Otherwise we just insert in first position. */ + const size_t name_offset = offsetof(ModifierData, name); + ModifierData *mod_anchor = BLI_listbase_string_or_index_find(&ob_dst->modifiers, + opop->subitem_reference_name, + name_offset, + opop->subitem_reference_index); + /* If `mod_anchor` is NULL, `mod_src` will be inserted in first position. */ - ModifierData *mod_src = NULL; - if (opop->subitem_local_name && opop->subitem_local_name[0]) { - mod_src = BLI_findstring( - &ob_src->modifiers, opop->subitem_local_name, offsetof(ModifierData, name)); - } - if (mod_src == NULL && opop->subitem_local_index >= 0) { - mod_src = BLI_findlink(&ob_src->modifiers, opop->subitem_local_index); - } - mod_src = mod_src ? mod_src->next : ob_src->modifiers.first; + ModifierData *mod_src = BLI_listbase_string_or_index_find( + &ob_src->modifiers, opop->subitem_local_name, name_offset, opop->subitem_local_index); if (mod_src == NULL) { BLI_assert(mod_src != NULL); @@ -1933,25 +1917,18 @@ bool rna_Object_greasepencil_modifiers_override_apply(Main *bmain, /* Remember that insertion operations are defined and stored in correct order, which means that * even if we insert several items in a row, we always insert first one, then second one, etc. * So we should always find 'anchor' modifier in both _src *and* _dst. */ - GpencilModifierData *mod_anchor = NULL; - if (opop->subitem_local_name && opop->subitem_local_name[0]) { - mod_anchor = BLI_findstring( - &ob_dst->greasepencil_modifiers, opop->subitem_local_name, offsetof(ModifierData, name)); - } - if (mod_anchor == NULL && opop->subitem_local_index >= 0) { - mod_anchor = BLI_findlink(&ob_dst->greasepencil_modifiers, opop->subitem_local_index); - } - /* Otherwise we just insert in first position. */ - - GpencilModifierData *mod_src = NULL; - if (opop->subitem_local_name && opop->subitem_local_name[0]) { - mod_src = BLI_findstring( - &ob_src->greasepencil_modifiers, opop->subitem_local_name, offsetof(ModifierData, name)); - } - if (mod_src == NULL && opop->subitem_local_index >= 0) { - mod_src = BLI_findlink(&ob_src->greasepencil_modifiers, opop->subitem_local_index); - } - mod_src = mod_src ? mod_src->next : ob_src->greasepencil_modifiers.first; + const size_t name_offset = offsetof(GpencilModifierData, name); + GpencilModifierData *mod_anchor = BLI_listbase_string_or_index_find( + &ob_dst->greasepencil_modifiers, + opop->subitem_reference_name, + name_offset, + opop->subitem_reference_index); + /* If `mod_anchor` is NULL, `mod_src` will be inserted in first position. */ + + GpencilModifierData *mod_src = BLI_listbase_string_or_index_find(&ob_src->greasepencil_modifiers, + opop->subitem_local_name, + name_offset, + opop->subitem_local_index); if (mod_src == NULL) { BLI_assert(mod_src != NULL); diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 10094ade711..63c4774d0e5 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -530,7 +530,7 @@ static int mesh_looptri_to_poly_index(Mesh *me_eval, const MLoopTri *lt) return index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly; } -/* TOOD(sergey): Make the Python API more clear that evaluation might happen, or requite +/* TODO(sergey): Make the Python API more clear that evaluation might happen, or require * passing fully evaluated depsgraph. */ static Object *eval_object_ensure(Object *ob, bContext *C, diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c index 186222d2ca0..2fca9f0af7a 100644 --- a/source/blender/makesrna/intern/rna_object_force.c +++ b/source/blender/makesrna/intern/rna_object_force.c @@ -1006,8 +1006,7 @@ static void rna_def_pointcache_common(StructRNA *srna) prop = RNA_def_property(srna, "is_frame_skip", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", PTCACHE_FRAMES_SKIPPED); RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text( - prop, "", "Some frames were skipped while baking/saving that cache"); + RNA_def_property_ui_text(prop, "", "Some frames were skipped while baking/saving that cache"); prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "name"); diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index ee509fa92d4..87173adc38f 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -650,6 +650,7 @@ static bConstraint *rna_PoseChannel_constraints_copy(ID *id, Object *ob = (Object *)id; bConstraint *con = con_ptr->data; bConstraint *new_con = BKE_constraint_copy_for_pose(ob, pchan, con); + new_con->flag |= CONSTRAINT_OVERRIDE_LIBRARY_LOCAL; ED_object_constraint_dependency_tag_update(bmain, ob, new_con); WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT | NA_ADDED, id); @@ -681,29 +682,18 @@ bool rna_PoseChannel_constraints_override_apply(Main *UNUSED(bmain), /* Remember that insertion operations are defined and stored in correct order, which means that * even if we insert several items in a row, we always insert first one, then second one, etc. * So we should always find 'anchor' constraint in both _src *and* _dst */ - bConstraint *con_anchor = NULL; - if (opop->subitem_local_name && opop->subitem_local_name[0]) { - con_anchor = BLI_findstring( - &pchan_dst->constraints, opop->subitem_local_name, offsetof(bConstraint, name)); - } - if (con_anchor == NULL && opop->subitem_local_index >= 0) { - con_anchor = BLI_findlink(&pchan_dst->constraints, opop->subitem_local_index); - } - /* Otherwise we just insert in first position. */ + const size_t name_offset = offsetof(bConstraint, name); + bConstraint *con_anchor = BLI_listbase_string_or_index_find(&pchan_dst->constraints, + opop->subitem_reference_name, + name_offset, + opop->subitem_reference_index); + /* If `con_anchor` is NULL, `con_src` will be inserted in first position. */ - bConstraint *con_src = NULL; - if (opop->subitem_local_name && opop->subitem_local_name[0]) { - con_src = BLI_findstring( - &pchan_src->constraints, opop->subitem_local_name, offsetof(bConstraint, name)); - } - if (con_src == NULL && opop->subitem_local_index >= 0) { - con_src = BLI_findlink(&pchan_src->constraints, opop->subitem_local_index); - } - con_src = con_src ? con_src->next : pchan_src->constraints.first; + bConstraint *con_src = BLI_listbase_string_or_index_find( + &pchan_src->constraints, opop->subitem_local_name, name_offset, opop->subitem_local_index); if (con_src == NULL) { - printf("%s: Could not find constraint to insert, doing nothing...\n", __func__); - BLI_assert(0); + BLI_assert(con_src != NULL); return false; } diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index 12fb7a40d13..e5009305fe5 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -1916,16 +1916,21 @@ int rna_property_override_diff_default(Main *bmain, /* Collections do not support replacement of their data (except for collections of ID * pointers), since they do not support removing, only in *some* cases, insertion. We - * also assume then that _a data is the one where things are inserted. */ + * also assume then that _a data is the one where things are inserted. + * + * NOTE: In insertion case, both 'local' and 'reference' (aka anchor) sub-item + * identifiers refer to collection items in the local override. The 'reference' may match + * an item in the linked reference data, but it can also be another local-only item added + * by a previous INSERT operation. */ if (is_valid_for_insertion && use_collection_insertion) { op = BKE_lib_override_library_property_get(override, rna_path, &created); BKE_lib_override_library_property_operation_get(op, IDOVERRIDE_LIBRARY_OP_INSERT_AFTER, - NULL, no_prop_name ? NULL : prev_propname_a, - -1, + no_prop_name ? NULL : propname_a, idx_a - 1, + idx_a, true, NULL, NULL); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 3468cab9eea..c69a69290f9 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -4166,6 +4166,13 @@ void rna_def_view_layer_common(BlenderRNA *brna, StructRNA *srna, const bool sce prop, "Cryptomatte Levels", "Sets how many unique objects can be distinguished per pixel"); RNA_def_property_ui_range(prop, 2.0, 16.0, 2.0, 0.0); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update"); + + prop = RNA_def_property(srna, "use_pass_cryptomatte_accurate", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "cryptomatte_flag", VIEW_LAYER_CRYPTOMATTE_ACCURATE); + RNA_def_property_boolean_default(prop, true); + RNA_def_property_ui_text( + prop, "Cryptomatte Accurate", "Generate a more accurate cryptomatte pass"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update"); } prop = RNA_def_property(srna, "use_solid", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index cc302c4dd89..f92043995dd 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -1366,6 +1366,28 @@ static float rna_Sequence_fps_get(PointerRNA *ptr) return SEQ_time_sequence_get_fps(scene, seq); } +static void rna_Sequence_separate(ID *id, Sequence *seqm, Main *bmain) +{ + Scene *scene = (Scene *)id; + + /* Find the appropriate seqbase */ + Editing *ed = SEQ_editing_get(scene); + ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seqm); + + LISTBASE_FOREACH_MUTABLE (Sequence *, seq, &seqm->seqbase) { + SEQ_edit_move_strip_to_seqbase(scene, &seqm->seqbase, seq, seqbase); + } + + SEQ_edit_flag_for_removal(scene, seqbase, seqm); + SEQ_edit_remove_flagged_sequences(scene, seqbase); + + /* Update depsgraph. */ + DEG_relations_tag_update(bmain); + DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); + + WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene); +} + #else static void rna_def_strip_element(BlenderRNA *brna) @@ -2250,7 +2272,7 @@ static void rna_def_filter_video(StructRNA *srna) prop = RNA_def_property(srna, "use_reverse_frames", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_REVERSE_FRAMES); RNA_def_property_ui_text(prop, "Reverse Frames", "Reverse frame order"); - RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); prop = RNA_def_property(srna, "color_multiply", PROP_FLOAT, PROP_UNSIGNED); RNA_def_property_float_sdna(prop, NULL, "mul"); @@ -2272,7 +2294,8 @@ static void rna_def_filter_video(StructRNA *srna) prop = RNA_def_property(srna, "strobe", PROP_FLOAT, PROP_NONE); RNA_def_property_range(prop, 1.0f, 30.0f); RNA_def_property_ui_text(prop, "Strobe", "Only display every nth frame"); - RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL); + RNA_def_property_update( + prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); prop = RNA_def_property(srna, "transform", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "strip->transform"); @@ -2438,6 +2461,7 @@ static void rna_def_image(BlenderRNA *brna) static void rna_def_meta(BlenderRNA *brna) { StructRNA *srna; + FunctionRNA *func; PropertyRNA *prop; srna = RNA_def_struct(brna, "MetaSequence", "Sequence"); @@ -2451,6 +2475,10 @@ static void rna_def_meta(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Sequences", "Sequences nested in meta strip"); RNA_api_sequences(brna, prop, true); + func = RNA_def_function(srna, "separate", "rna_Sequence_separate"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); + RNA_def_function_ui_description(func, "Separate meta"); + rna_def_filter_video(srna); rna_def_proxy(srna); rna_def_input(srna); @@ -2979,11 +3007,11 @@ static void rna_def_text(StructRNA *srna) RNA_def_property_pointer_funcs(prop, NULL, "rna_Sequence_text_font_set", NULL, NULL); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); - prop = RNA_def_property(srna, "font_size", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_sdna(prop, NULL, "text_size"); + prop = RNA_def_property(srna, "font_size", PROP_FLOAT, PROP_UNSIGNED); + RNA_def_property_float_sdna(prop, NULL, "text_size"); RNA_def_property_ui_text(prop, "Size", "Size of the text"); RNA_def_property_range(prop, 0.0, 2000); - RNA_def_property_ui_range(prop, 0.0f, 2000, 1, -1); + RNA_def_property_ui_range(prop, 0.0f, 2000, 10.f, 1); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c index ec6c4c2f32f..7989c316c4c 100644 --- a/source/blender/makesrna/intern/rna_sequencer_api.c +++ b/source/blender/makesrna/intern/rna_sequencer_api.c @@ -59,6 +59,7 @@ # include "SEQ_relations.h" # include "SEQ_render.h" # include "SEQ_sequencer.h" +# include "SEQ_time.h" # include "WM_api.h" @@ -69,7 +70,7 @@ static void rna_Sequence_update_rnafunc(ID *id, Sequence *self, bool do_data) ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, self); if (do_data) { - SEQ_relations_update_changed_seq_and_deps(scene, self, true, true); + SEQ_time_update_recursive(scene, self); // new_tstripdata(self); /* need 2.6x version of this. */ } diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 03976967e9f..e7bcd387eaf 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -3090,7 +3090,7 @@ static void rna_SpaceSpreadsheet_geometry_component_type_update(Main *UNUSED(bma break; } case GEO_COMPONENT_TYPE_INSTANCES: { - sspreadsheet->attribute_domain = ATTR_DOMAIN_POINT; + sspreadsheet->attribute_domain = ATTR_DOMAIN_INSTANCE; break; } case GEO_COMPONENT_TYPE_VOLUME: { diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index c73599c19ac..05ed5e096d8 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -1471,15 +1471,12 @@ static void rna_def_panel(BlenderRNA *brna) RNA_def_property_string_sdna(prop, NULL, "type->category"); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); RNA_def_property_ui_text( - prop, - "", - "The category (tab) in which the panel will be displayed, when applicable"); + prop, "", "The category (tab) in which the panel will be displayed, when applicable"); prop = RNA_def_property(srna, "bl_owner_id", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "type->owner_id"); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); - RNA_def_property_ui_text( - prop, "", "The ID owning the data displayed in the panel, if any"); + RNA_def_property_ui_text(prop, "", "The ID owning the data displayed in the panel, if any"); prop = RNA_def_property(srna, "bl_space_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "type->space_type"); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 92f7b7d7682..dd1252ffebf 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -352,6 +352,12 @@ static void rna_userdef_asset_library_name_set(PointerRNA *ptr, const char *valu BKE_preferences_asset_library_name_set(&U, library, value); } +static void rna_userdef_asset_library_path_set(PointerRNA *ptr, const char *value) +{ + bUserAssetLibrary *library = (bUserAssetLibrary *)ptr->data; + BKE_preferences_asset_library_path_set(library, value); +} + static void rna_userdef_script_autoexec_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) @@ -1136,10 +1142,11 @@ static void rna_def_userdef_theme_ui_font_style(BlenderRNA *brna) RNA_def_struct_clear_flag(srna, STRUCT_UNDO); RNA_def_struct_ui_text(srna, "Font Style", "Theme settings for Font"); - prop = RNA_def_property(srna, "points", PROP_INT, PROP_NONE); - RNA_def_property_range(prop, 6, 24); + prop = RNA_def_property(srna, "points", PROP_FLOAT, PROP_UNSIGNED); + RNA_def_property_range(prop, 6.0f, 32.0f); + RNA_def_property_ui_range(prop, 8.0f, 20.0f, 10.0f, 1); RNA_def_property_ui_text(prop, "Points", "Font size in points"); - RNA_def_property_update(prop, 0, "rna_userdef_theme_text_style_update"); + RNA_def_property_update(prop, 0, "rna_userdef_dpi_update"); prop = RNA_def_property(srna, "shadow", PROP_INT, PROP_PIXEL); RNA_def_property_range(prop, 0, 5); @@ -5024,6 +5031,14 @@ static void rna_def_userdef_edit(BlenderRNA *brna) "Collection Instance Empty Size", "Display size of the empty when new collection instances are created"); + /* Text Editor */ + + prop = RNA_def_property(srna, "use_text_edit_auto_close", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "text_flag", USER_TEXT_EDIT_AUTO_CLOSE); + RNA_def_property_ui_text( + prop, "Auto Close", "Auto close relevant characters inside the text editor"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TEXT, NULL); + /* Undo */ prop = RNA_def_property(srna, "undo_steps", PROP_INT, PROP_NONE); @@ -6100,6 +6115,7 @@ static void rna_def_userdef_filepaths_asset_library(BlenderRNA *brna) prop = RNA_def_property(srna, "path", PROP_STRING, PROP_DIRPATH); RNA_def_property_ui_text( prop, "Path", "Path to a directory with .blend files to use as an asset library"); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_userdef_asset_library_path_set"); RNA_def_property_update(prop, 0, "rna_userdef_update"); } @@ -6390,6 +6406,12 @@ static void rna_def_userdef_experimental(BlenderRNA *brna) "data-blocks as assets, not just poses"); RNA_def_property_update(prop, 0, "rna_userdef_ui_update"); + prop = RNA_def_property(srna, "show_asset_debug_info", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_ui_text(prop, + "Asset Debug Info", + "Enable some extra fields in the Asset Browser to aid in debugging"); + RNA_def_property_update(prop, 0, "rna_userdef_ui_update"); + prop = RNA_def_property(srna, "use_override_templates", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "use_override_templates", 1); RNA_def_property_ui_text( diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c index c997cd7377f..cb043643dd9 100644 --- a/source/blender/modifiers/intern/MOD_meshdeform.c +++ b/source/blender/modifiers/intern/MOD_meshdeform.c @@ -426,7 +426,7 @@ static void meshdeformModifier_do(ModifierData *md, bindcagecos = (float(*)[3])mmd->bindcagecos; for (a = 0; a < totcagevert; a++) { - /* get cage vertex in world space with binding transform */ + /* Get cage vertex in world-space with binding transform. */ float co[3]; mul_v3_m4v3(co, mmd->bindmat, dco[a]); /* compute difference with world space bind coord */ diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index a48210e4cf4..d027be0a7f6 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -88,6 +88,7 @@ #include "MOD_ui_common.h" #include "ED_object.h" +#include "ED_screen.h" #include "ED_spreadsheet.h" #include "ED_undo.h" @@ -738,7 +739,7 @@ static void initialize_group_input(NodesModifierData &nmd, if (use_attribute) { const StringRef attribute_name{IDP_String(property_attribute_name)}; auto attribute_input = std::make_shared<blender::bke::AttributeFieldInput>( - attribute_name, *socket_type.get_base_cpp_type()); + attribute_name, *socket_type.base_cpp_type); new (r_value) blender::fn::GField(std::move(attribute_input), 0); } else { @@ -962,7 +963,7 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, /* Initialize remaining group inputs. */ for (const OutputSocketRef *socket : remaining_input_sockets) { - const CPPType &cpp_type = *socket->typeinfo()->get_geometry_nodes_cpp_type(); + const CPPType &cpp_type = *socket->typeinfo()->geometry_nodes_cpp_type; void *value_in = allocator.allocate(cpp_type.size(), cpp_type.alignment()); initialize_group_input(*nmd, *socket, value_in); group_inputs.add_new({root_context, socket}, {cpp_type, value_in}); @@ -1025,17 +1026,20 @@ static void check_property_socket_sync(const Object *ob, ModifierData *md) { NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md); - int i = 0; + int geometry_socket_count = 0; + + int i; LISTBASE_FOREACH_INDEX (const bNodeSocket *, socket, &nmd->node_group->inputs, i) { /* The first socket is the special geometry socket for the modifier object. */ if (i == 0 && socket->type == SOCK_GEOMETRY) { + geometry_socket_count++; continue; } IDProperty *property = IDP_GetPropertyFromGroup(nmd->settings.properties, socket->identifier); if (property == nullptr) { if (socket->type == SOCK_GEOMETRY) { - BKE_modifier_set_error(ob, md, "Node group can only have one geometry input"); + geometry_socket_count++; } else { BKE_modifier_set_error(ob, md, "Missing property for input socket \"%s\"", socket->name); @@ -1050,15 +1054,13 @@ static void check_property_socket_sync(const Object *ob, ModifierData *md) } } - bool has_geometry_output = false; - LISTBASE_FOREACH (const bNodeSocket *, socket, &nmd->node_group->outputs) { - if (socket->type == SOCK_GEOMETRY) { - has_geometry_output = true; + if (geometry_socket_count == 1) { + if (((bNodeSocket *)nmd->node_group->inputs.first)->type != SOCK_GEOMETRY) { + BKE_modifier_set_error(ob, md, "Node group's geometry input must be the first"); } } - - if (!has_geometry_output) { - BKE_modifier_set_error(ob, md, "Node group must have a geometry output"); + else if (geometry_socket_count > 1) { + BKE_modifier_set_error(ob, md, "Node group can only have one geometry input"); } } @@ -1078,6 +1080,7 @@ static void modifyGeometry(ModifierData *md, if (tree.has_link_cycles()) { BKE_modifier_set_error(ctx->object, md, "Node group has cycles"); + geometry_set.clear(); return; } @@ -1085,17 +1088,23 @@ static void modifyGeometry(ModifierData *md, Span<const NodeRef *> input_nodes = root_tree_ref.nodes_by_type("NodeGroupInput"); Span<const NodeRef *> output_nodes = root_tree_ref.nodes_by_type("NodeGroupOutput"); if (output_nodes.size() != 1) { + BKE_modifier_set_error(ctx->object, md, "Node group must have a single output node"); + geometry_set.clear(); return; } const NodeRef &output_node = *output_nodes[0]; Span<const InputSocketRef *> group_outputs = output_node.inputs().drop_back(1); if (group_outputs.is_empty()) { + BKE_modifier_set_error(ctx->object, md, "Node group must have an output socket"); + geometry_set.clear(); return; } const InputSocketRef *first_output_socket = group_outputs[0]; if (first_output_socket->idname() != "NodeSocketGeometry") { + BKE_modifier_set_error(ctx->object, md, "Node group's first output must be a geometry"); + geometry_set.clear(); return; } @@ -1132,8 +1141,17 @@ struct AttributeSearchData { /* This class must not have a destructor, since it is used by buttons and freed with #MEM_freeN. */ BLI_STATIC_ASSERT(std::is_trivially_destructible_v<AttributeSearchData>, ""); -static NodesModifierData *get_modifier_data(Main &bmain, const AttributeSearchData &data) +static NodesModifierData *get_modifier_data(Main &bmain, + const wmWindowManager &wm, + const AttributeSearchData &data) { + if (ED_screen_animation_playing(&wm)) { + /* Work around an issue where the attribute search exec function has stale pointers when data + * is reallocated when evaluating the node tree, causing a crash. This would be solved by + * allowing the UI search data to own arbitrary memory rather than just referencing it. */ + return nullptr; + } + const Object *object = (Object *)BKE_libblock_find_session_uuid( &bmain, ID_OB, data.object_session_uid); if (object == nullptr) { @@ -1151,7 +1169,7 @@ static void attribute_search_update_fn( const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first) { AttributeSearchData &data = *static_cast<AttributeSearchData *>(arg); - const NodesModifierData *nmd = get_modifier_data(*CTX_data_main(C), data); + const NodesModifierData *nmd = get_modifier_data(*CTX_data_main(C), *CTX_wm_manager(C), data); if (nmd == nullptr) { return; } @@ -1185,7 +1203,7 @@ static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v) } AttributeSearchData &data = *static_cast<AttributeSearchData *>(data_v); const GeometryAttributeInfo &item = *static_cast<const GeometryAttributeInfo *>(item_v); - const NodesModifierData *nmd = get_modifier_data(*CTX_data_main(C), data); + const NodesModifierData *nmd = get_modifier_data(*CTX_data_main(C), *CTX_wm_manager(C), data); if (nmd == nullptr) { return; } @@ -1362,8 +1380,8 @@ static void draw_property_for_socket(const bContext &C, } else { uiLayout *row = uiLayoutRow(layout, false); + uiLayoutSetPropDecorate(row, true); uiItemR(row, md_ptr, rna_path, 0, socket.name, ICON_NONE); - uiItemDecoratorR(row, md_ptr, rna_path, 0); } } } diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc index 70d2bd9c7f5..fd2fe2161c9 100644 --- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc +++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc @@ -309,10 +309,10 @@ class LockedNode : NonCopyable, NonMovable { static const CPPType *get_socket_cpp_type(const SocketRef &socket) { const bNodeSocketType *typeinfo = socket.typeinfo(); - if (typeinfo->get_geometry_nodes_cpp_type == nullptr) { + if (typeinfo->geometry_nodes_cpp_type == nullptr) { return nullptr; } - const CPPType *type = typeinfo->get_geometry_nodes_cpp_type(); + const CPPType *type = typeinfo->geometry_nodes_cpp_type; if (type == nullptr) { return nullptr; } @@ -723,7 +723,7 @@ class GeometryNodesEvaluator { this->execute_node(node, node_state); } - this->node_task_postprocessing(node, node_state); + this->node_task_postprocessing(node, node_state, do_execute_node); } bool node_task_preprocessing(const DNode node, NodeState &node_state) @@ -1006,7 +1006,7 @@ class GeometryNodesEvaluator { } } - void node_task_postprocessing(const DNode node, NodeState &node_state) + void node_task_postprocessing(const DNode node, NodeState &node_state, bool was_executed) { this->with_locked_node(node, node_state, [&](LockedNode &locked_node) { const bool node_has_finished = this->finish_node_if_possible(locked_node); @@ -1017,8 +1017,9 @@ class GeometryNodesEvaluator { /* Either the node rescheduled itself or another node tried to schedule it while it ran. */ this->schedule_node(locked_node); } - - this->assert_expected_outputs_have_been_computed(locked_node); + if (was_executed) { + this->assert_expected_outputs_have_been_computed(locked_node); + } }); } @@ -1465,13 +1466,12 @@ class GeometryNodesEvaluator { from_type.copy_construct(from_value, to_value); return; } - const FieldCPPType *from_field_type = dynamic_cast<const FieldCPPType *>(&from_type); const FieldCPPType *to_field_type = dynamic_cast<const FieldCPPType *>(&to_type); if (from_field_type != nullptr && to_field_type != nullptr) { - const CPPType &from_base_type = from_field_type->field_type(); - const CPPType &to_base_type = to_field_type->field_type(); + const CPPType &from_base_type = from_field_type->base_type(); + const CPPType &to_base_type = to_field_type->base_type(); if (conversions_.is_convertible(from_base_type, to_base_type)) { const MultiFunction &fn = *conversions_.get_conversion_multi_function( MFDataType::ForSingle(from_base_type), MFDataType::ForSingle(to_base_type)); @@ -1494,7 +1494,7 @@ class GeometryNodesEvaluator { void construct_default_value(const CPPType &type, void *r_value) { if (const FieldCPPType *field_cpp_type = dynamic_cast<const FieldCPPType *>(&type)) { - const CPPType &base_type = field_cpp_type->field_type(); + const CPPType &base_type = field_cpp_type->base_type(); auto constant_fn = std::make_unique<fn::CustomMF_GenericConstant>( base_type, base_type.default_value(), false); auto operation = std::make_shared<fn::FieldOperation>(std::move(constant_fn)); diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c index d4aaefcfe05..0cc1627afcd 100644 --- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c +++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c @@ -74,6 +74,7 @@ static float angle_signed_on_axis_normalized_v3v3_v3(const float n[3], static float clamp_nonzero(const float value, const float epsilon) { BLI_assert(!(epsilon < 0.0f)); + /* Return closest value with `abs(value) >= epsilon`. */ if (value < 0.0f) { return min_ff(value, -epsilon); } @@ -171,15 +172,22 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, float(*poly_nors)[3] = NULL; + /* #ofs_front and #ofs_back are the offset from the original + * surface along the normal, where #oft_front is along the positive + * and #oft_back is along the negative normal. */ const float ofs_front = (smd->offset_fac + 1.0f) * 0.5f * smd->offset; const float ofs_back = ofs_front - smd->offset * smd->offset_fac; - const float ofs_front_clamped = clamp_nonzero(smd->offset > 0 ? ofs_front : ofs_back, 1e-5f); - const float ofs_back_clamped = clamp_nonzero(smd->offset > 0 ? ofs_back : ofs_front, 1e-5f); + /* #ofs_front_clamped and #ofs_back_clamped are the same as + * #ofs_front and #ofs_back, but never zero. */ + const float ofs_front_clamped = clamp_nonzero(ofs_front, 1e-5f); + const float ofs_back_clamped = clamp_nonzero(ofs_back, 1e-5f); const float offset_fac_vg = smd->offset_fac_vg; const float offset_fac_vg_inv = 1.0f - smd->offset_fac_vg; const float offset = fabsf(smd->offset) * smd->offset_clamp; const bool do_angle_clamp = smd->flag & MOD_SOLIDIFY_OFFSET_ANGLE_CLAMP; - const bool do_flip = (smd->flag & MOD_SOLIDIFY_FLIP) != 0; + /* #do_flip, flips the normals of the result. This is inverted if negative thickness + * is used, since simple soldify with negative thickness keeps the faces facing outside. */ + const bool do_flip = ((smd->flag & MOD_SOLIDIFY_FLIP) != 0) == (smd->offset > 0); const bool do_rim = smd->flag & MOD_SOLIDIFY_RIM; const bool do_shell = ((smd->flag & MOD_SOLIDIFY_RIM) && (smd->flag & MOD_SOLIDIFY_NOSHELL)) == 0; diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c index 2c28e9710ef..238952fde00 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.c +++ b/source/blender/modifiers/intern/MOD_uvproject.c @@ -192,7 +192,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd, mul_m4_m4m4(projectors[i].projmat, offsetmat, tmpmat); - /* calculate worldspace projector normal (for best projector test) */ + /* Calculate world-space projector normal (for best projector test). */ projectors[i].normal[0] = 0; projectors[i].normal[1] = 0; projectors[i].normal[2] = 1; @@ -208,7 +208,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd, coords = BKE_mesh_vert_coords_alloc(mesh, &numVerts); - /* convert coords to world space */ + /* Convert coords to world-space. */ for (i = 0, co = coords; i < numVerts; i++, co++) { mul_m4_v3(ob->obmat, *co); } diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 0b4c34d6155..e256ebcff56 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -18,6 +18,8 @@ # All rights reserved. # ***** END GPL LICENSE BLOCK ***** +add_subdirectory(geometry) + set(INC . composite @@ -155,148 +157,6 @@ set(SRC function/nodes/node_fn_value_to_string.cc function/node_function_util.cc - geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc - geometry/nodes/legacy/node_geo_attribute_clamp.cc - geometry/nodes/legacy/node_geo_attribute_color_ramp.cc - geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc - geometry/nodes/legacy/node_geo_attribute_compare.cc - geometry/nodes/legacy/node_geo_attribute_convert.cc - geometry/nodes/legacy/node_geo_attribute_curve_map.cc - geometry/nodes/legacy/node_geo_attribute_fill.cc - geometry/nodes/legacy/node_geo_attribute_map_range.cc - geometry/nodes/legacy/node_geo_attribute_math.cc - geometry/nodes/legacy/node_geo_attribute_mix.cc - geometry/nodes/legacy/node_geo_attribute_proximity.cc - geometry/nodes/legacy/node_geo_attribute_randomize.cc - geometry/nodes/legacy/node_geo_attribute_sample_texture.cc - geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc - geometry/nodes/legacy/node_geo_attribute_transfer.cc - geometry/nodes/legacy/node_geo_attribute_vector_math.cc - geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc - geometry/nodes/legacy/node_geo_curve_endpoints.cc - geometry/nodes/legacy/node_geo_curve_reverse.cc - geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc - geometry/nodes/legacy/node_geo_curve_set_handles.cc - geometry/nodes/legacy/node_geo_curve_spline_type.cc - geometry/nodes/legacy/node_geo_curve_subdivide.cc - geometry/nodes/legacy/node_geo_curve_to_points.cc - geometry/nodes/legacy/node_geo_delete_geometry.cc - geometry/nodes/legacy/node_geo_edge_split.cc - geometry/nodes/legacy/node_geo_material_assign.cc - geometry/nodes/legacy/node_geo_mesh_to_curve.cc - geometry/nodes/legacy/node_geo_point_distribute.cc - geometry/nodes/legacy/node_geo_point_instance.cc - geometry/nodes/legacy/node_geo_point_rotate.cc - geometry/nodes/legacy/node_geo_point_scale.cc - geometry/nodes/legacy/node_geo_point_separate.cc - geometry/nodes/legacy/node_geo_point_translate.cc - geometry/nodes/legacy/node_geo_points_to_volume.cc - geometry/nodes/legacy/node_geo_raycast.cc - geometry/nodes/legacy/node_geo_select_by_material.cc - geometry/nodes/legacy/node_geo_subdivision_surface.cc - geometry/nodes/legacy/node_geo_volume_to_mesh.cc - - geometry/nodes/node_geo_attribute_capture.cc - geometry/nodes/node_geo_attribute_remove.cc - geometry/nodes/node_geo_attribute_statistic.cc - geometry/nodes/node_geo_boolean.cc - geometry/nodes/node_geo_bounding_box.cc - geometry/nodes/node_geo_collection_info.cc - geometry/nodes/node_geo_common.cc - geometry/nodes/node_geo_convex_hull.cc - geometry/nodes/node_geo_curve_endpoint_selection.cc - geometry/nodes/node_geo_curve_fill.cc - geometry/nodes/node_geo_curve_fillet.cc - geometry/nodes/node_geo_curve_handle_type_selection.cc - geometry/nodes/node_geo_curve_length.cc - geometry/nodes/node_geo_curve_parameter.cc - geometry/nodes/node_geo_curve_primitive_bezier_segment.cc - geometry/nodes/node_geo_curve_primitive_circle.cc - geometry/nodes/node_geo_curve_primitive_line.cc - geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc - geometry/nodes/node_geo_curve_primitive_quadrilateral.cc - geometry/nodes/node_geo_curve_primitive_spiral.cc - geometry/nodes/node_geo_curve_primitive_star.cc - geometry/nodes/node_geo_curve_resample.cc - geometry/nodes/node_geo_curve_reverse.cc - geometry/nodes/node_geo_curve_sample.cc - geometry/nodes/node_geo_curve_set_handles.cc - geometry/nodes/node_geo_curve_spline_type.cc - geometry/nodes/node_geo_curve_subdivide.cc - geometry/nodes/node_geo_curve_to_mesh.cc - geometry/nodes/node_geo_curve_to_points.cc - geometry/nodes/node_geo_curve_trim.cc - geometry/nodes/node_geo_delete_geometry.cc - geometry/nodes/node_geo_distribute_points_on_faces.cc - geometry/nodes/node_geo_edge_split.cc - geometry/nodes/node_geo_image_texture.cc - geometry/nodes/node_geo_input_curve_handles.cc - geometry/nodes/node_geo_input_curve_tilt.cc - geometry/nodes/node_geo_input_id.cc - geometry/nodes/node_geo_input_index.cc - geometry/nodes/node_geo_input_material_index.cc - geometry/nodes/node_geo_input_material.cc - geometry/nodes/node_geo_input_normal.cc - geometry/nodes/node_geo_input_position.cc - geometry/nodes/node_geo_input_radius.cc - geometry/nodes/node_geo_input_shade_smooth.cc - geometry/nodes/node_geo_input_spline_cyclic.cc - geometry/nodes/node_geo_input_spline_length.cc - geometry/nodes/node_geo_input_spline_resolution.cc - geometry/nodes/node_geo_input_tangent.cc - geometry/nodes/node_geo_instance_on_points.cc - geometry/nodes/node_geo_instances_to_points.cc - geometry/nodes/node_geo_is_viewport.cc - geometry/nodes/node_geo_join_geometry.cc - geometry/nodes/node_geo_material_replace.cc - geometry/nodes/node_geo_material_selection.cc - geometry/nodes/node_geo_mesh_primitive_circle.cc - geometry/nodes/node_geo_mesh_primitive_cone.cc - geometry/nodes/node_geo_mesh_primitive_cube.cc - geometry/nodes/node_geo_mesh_primitive_cylinder.cc - geometry/nodes/node_geo_mesh_primitive_grid.cc - geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc - geometry/nodes/node_geo_mesh_primitive_line.cc - geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc - geometry/nodes/node_geo_mesh_subdivide.cc - geometry/nodes/node_geo_mesh_to_curve.cc - geometry/nodes/node_geo_mesh_to_points.cc - geometry/nodes/node_geo_object_info.cc - geometry/nodes/node_geo_points_to_vertices.cc - geometry/nodes/node_geo_points_to_volume.cc - geometry/nodes/node_geo_proximity.cc - geometry/nodes/node_geo_raycast.cc - geometry/nodes/node_geo_realize_instances.cc - geometry/nodes/node_geo_rotate_instances.cc - geometry/nodes/node_geo_scale_instances.cc - geometry/nodes/node_geo_separate_components.cc - geometry/nodes/node_geo_separate_geometry.cc - geometry/nodes/node_geo_set_curve_handles.cc - geometry/nodes/node_geo_set_curve_radius.cc - geometry/nodes/node_geo_set_curve_tilt.cc - geometry/nodes/node_geo_set_id.cc - geometry/nodes/node_geo_set_material_index.cc - geometry/nodes/node_geo_set_material.cc - geometry/nodes/node_geo_set_point_radius.cc - geometry/nodes/node_geo_set_position.cc - geometry/nodes/node_geo_set_shade_smooth.cc - geometry/nodes/node_geo_set_spline_cyclic.cc - geometry/nodes/node_geo_set_spline_resolution.cc - geometry/nodes/node_geo_string_join.cc - geometry/nodes/node_geo_string_to_curves.cc - geometry/nodes/node_geo_subdivision_surface.cc - geometry/nodes/node_geo_switch.cc - geometry/nodes/node_geo_transfer_attribute.cc - geometry/nodes/node_geo_transform.cc - geometry/nodes/node_geo_translate_instances.cc - geometry/nodes/node_geo_triangulate.cc - geometry/nodes/node_geo_viewer.cc - geometry/nodes/node_geo_volume_to_mesh.cc - - geometry/node_geometry_exec.cc - geometry/node_geometry_tree.cc - geometry/node_geometry_util.cc - shader/nodes/node_shader_add_shader.c shader/nodes/node_shader_ambient_occlusion.c shader/nodes/node_shader_attribute.c @@ -434,7 +294,6 @@ set(SRC composite/node_composite_util.hh function/node_function_util.hh shader/node_shader_util.h - geometry/node_geometry_util.hh texture/node_texture_util.h NOD_common.h @@ -463,8 +322,8 @@ set(SRC set(LIB bf_bmesh bf_functions - bf_geometry bf_intern_sky + bf_nodes_geometry ) if(WITH_BULLET) diff --git a/source/blender/nodes/NOD_common.h b/source/blender/nodes/NOD_common.h index 50ed992dcb6..fa979bb4799 100644 --- a/source/blender/nodes/NOD_common.h +++ b/source/blender/nodes/NOD_common.h @@ -45,6 +45,8 @@ struct bNodeSocket *node_group_output_find_socket(struct bNode *node, const char void node_group_input_update(struct bNodeTree *ntree, struct bNode *node); void node_group_output_update(struct bNodeTree *ntree, struct bNode *node); +void node_internal_links_create(struct bNodeTree *ntree, struct bNode *node); + #ifdef __cplusplus } #endif diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh index 6e1f21dbae0..700f32ee414 100644 --- a/source/blender/nodes/NOD_geometry_exec.hh +++ b/source/blender/nodes/NOD_geometry_exec.hh @@ -57,13 +57,8 @@ using fn::GPointer; using fn::GSpan; using fn::GVArray; using fn::GVArray_GSpan; -using fn::GVArray_Span; -using fn::GVArray_Typed; -using fn::GVArrayPtr; using fn::GVMutableArray; using fn::GVMutableArray_GSpan; -using fn::GVMutableArray_Typed; -using fn::GVMutableArrayPtr; using geometry_nodes_eval_log::NodeWarningType; /** @@ -316,21 +311,21 @@ class GeoNodeExecParams { * \note This will add an error message if the string socket is active and * the input attribute does not exist. */ - GVArrayPtr get_input_attribute(const StringRef name, - const GeometryComponent &component, - const AttributeDomain domain, - const CustomDataType type, - const void *default_value) const; + GVArray get_input_attribute(const StringRef name, + const GeometryComponent &component, + const AttributeDomain domain, + const CustomDataType type, + const void *default_value) const; template<typename T> - GVArray_Typed<T> get_input_attribute(const StringRef name, - const GeometryComponent &component, - const AttributeDomain domain, - const T &default_value) const + VArray<T> get_input_attribute(const StringRef name, + const GeometryComponent &component, + const AttributeDomain domain, + const T &default_value) const { const CustomDataType type = bke::cpp_type_to_custom_data_type(CPPType::get<T>()); - GVArrayPtr varray = this->get_input_attribute(name, component, domain, type, &default_value); - return GVArray_Typed<T>(std::move(varray)); + GVArray varray = this->get_input_attribute(name, component, domain, type, &default_value); + return varray.typed<T>(); } /** diff --git a/source/blender/nodes/NOD_type_conversions.hh b/source/blender/nodes/NOD_type_conversions.hh index ec4859f0657..c8b24fd1260 100644 --- a/source/blender/nodes/NOD_type_conversions.hh +++ b/source/blender/nodes/NOD_type_conversions.hh @@ -21,7 +21,6 @@ namespace blender::nodes { using fn::CPPType; -using fn::GVArray; struct ConversionFunctions { const fn::MultiFunction *multi_function; @@ -73,9 +72,9 @@ class DataTypeConversions { const void *from_value, void *to_value) const; - fn::GVArrayPtr try_convert(fn::GVArrayPtr varray, const CPPType &to_type) const; + fn::GVArray try_convert(fn::GVArray varray, const CPPType &to_type) const; - fn::GVMutableArrayPtr try_convert(fn::GVMutableArrayPtr varray, const CPPType &to_type) const; + fn::GVMutableArray try_convert(fn::GVMutableArray varray, const CPPType &to_type) const; }; const DataTypeConversions &get_implicit_type_conversions(); diff --git a/source/blender/nodes/composite/node_composite_util.cc b/source/blender/nodes/composite/node_composite_util.cc index 86aaec61bc3..21269b92e65 100644 --- a/source/blender/nodes/composite/node_composite_util.cc +++ b/source/blender/nodes/composite/node_composite_util.cc @@ -52,5 +52,4 @@ void cmp_node_type_base(bNodeType *ntype, int type, const char *name, short ncla ntype->poll = cmp_node_poll_default; ntype->updatefunc = cmp_node_update_default; ntype->insert_link = node_insert_link_default; - ntype->update_internal_links = node_update_internal_links_default; } diff --git a/source/blender/nodes/composite/nodes/node_composite_common.cc b/source/blender/nodes/composite/nodes/node_composite_common.cc index fecf6795ef7..6432a89ffa0 100644 --- a/source/blender/nodes/composite/nodes/node_composite_common.cc +++ b/source/blender/nodes/composite/nodes/node_composite_common.cc @@ -44,7 +44,6 @@ void register_node_type_cmp_group(void) ntype.poll = cmp_node_poll_default; ntype.poll_instance = node_group_poll_instance; ntype.insert_link = node_insert_link_default; - ntype.update_internal_links = node_update_internal_links_default; ntype.rna_ext.srna = RNA_struct_find("CompositorNodeGroup"); BLI_assert(ntype.rna_ext.srna != nullptr); RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype); @@ -66,7 +65,4 @@ void register_node_type_cmp_custom_group(bNodeType *ntype) if (ntype->insert_link == nullptr) { ntype->insert_link = node_insert_link_default; } - if (ntype->update_internal_links == nullptr) { - ntype->update_internal_links = node_update_internal_links_default; - } } diff --git a/source/blender/nodes/composite/nodes/node_composite_composite.cc b/source/blender/nodes/composite/nodes/node_composite_composite.cc index 4247e81e9b2..a1a49133a3a 100644 --- a/source/blender/nodes/composite/nodes/node_composite_composite.cc +++ b/source/blender/nodes/composite/nodes/node_composite_composite.cc @@ -43,8 +43,7 @@ void register_node_type_cmp_composite(void) cmp_node_type_base(&ntype, CMP_NODE_COMPOSITE, "Composite", NODE_CLASS_OUTPUT, NODE_PREVIEW); ntype.declare = blender::nodes::cmp_node_composite_declare; - /* Do not allow muting for this node. */ - node_type_internal_links(&ntype, nullptr); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_image.cc b/source/blender/nodes/composite/nodes/node_composite_image.cc index 79cb0bd0f8c..40d4d4563c9 100644 --- a/source/blender/nodes/composite/nodes/node_composite_image.cc +++ b/source/blender/nodes/composite/nodes/node_composite_image.cc @@ -372,7 +372,8 @@ static void cmp_node_image_verify_outputs(bNodeTree *ntree, bNode *node, bool rl for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock_next, sock_index++) { sock_next = sock->next; if (BLI_linklist_index(available_sockets.list, sock) >= 0) { - sock->flag &= ~(SOCK_UNAVAIL | SOCK_HIDDEN); + sock->flag &= ~SOCK_HIDDEN; + nodeSetSocketAvailability(ntree, sock, true); } else { bNodeLink *link; @@ -386,7 +387,7 @@ static void cmp_node_image_verify_outputs(bNodeTree *ntree, bNode *node, bool rl nodeRemoveSocket(ntree, node, sock); } else { - sock->flag |= SOCK_UNAVAIL; + nodeSetSocketAvailability(ntree, sock, false); } } } diff --git a/source/blender/nodes/composite/nodes/node_composite_scale.cc b/source/blender/nodes/composite/nodes/node_composite_scale.cc index 3972fc0d949..284d16b9b0d 100644 --- a/source/blender/nodes/composite/nodes/node_composite_scale.cc +++ b/source/blender/nodes/composite/nodes/node_composite_scale.cc @@ -32,7 +32,7 @@ static bNodeSocketTemplate cmp_node_scale_in[] = { {-1, ""}}; static bNodeSocketTemplate cmp_node_scale_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}}; -static void node_composite_update_scale(bNodeTree *UNUSED(ntree), bNode *node) +static void node_composite_update_scale(bNodeTree *ntree, bNode *node) { bNodeSocket *sock; bool use_xy_scale = ELEM(node->custom1, CMP_SCALE_RELATIVE, CMP_SCALE_ABSOLUTE); @@ -40,12 +40,7 @@ static void node_composite_update_scale(bNodeTree *UNUSED(ntree), bNode *node) /* Only show X/Y scale factor inputs for modes using them! */ for (sock = (bNodeSocket *)node->inputs.first; sock; sock = sock->next) { if (STR_ELEM(sock->name, "X", "Y")) { - if (use_xy_scale) { - sock->flag &= ~SOCK_UNAVAIL; - } - else { - sock->flag |= SOCK_UNAVAIL; - } + nodeSetSocketAvailability(ntree, sock, use_xy_scale); } } } diff --git a/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc b/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc index 68c5ecdf48e..c0403a041db 100644 --- a/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc +++ b/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc @@ -53,8 +53,7 @@ void register_node_type_cmp_splitviewer(void) node_type_init(&ntype, node_composit_init_splitviewer); node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage); - /* Do not allow muting for this node. */ - node_type_internal_links(&ntype, nullptr); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_viewer.cc b/source/blender/nodes/composite/nodes/node_composite_viewer.cc index 969e2409898..90f9882099b 100644 --- a/source/blender/nodes/composite/nodes/node_composite_viewer.cc +++ b/source/blender/nodes/composite/nodes/node_composite_viewer.cc @@ -59,7 +59,7 @@ void register_node_type_cmp_viewer(void) node_type_init(&ntype, node_composit_init_viewer); node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage); - node_type_internal_links(&ntype, nullptr); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/function/node_function_util.cc b/source/blender/nodes/function/node_function_util.cc index 8ff8b416310..a1493d51a11 100644 --- a/source/blender/nodes/function/node_function_util.cc +++ b/source/blender/nodes/function/node_function_util.cc @@ -33,6 +33,5 @@ void fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclas { node_type_base(ntype, type, name, nclass, flag); ntype->poll = fn_node_poll_default; - ntype->update_internal_links = node_update_internal_links_default; ntype->insert_link = node_insert_link_default; } diff --git a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc index b44e8d54ff1..ed03cc0025d 100644 --- a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc +++ b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc @@ -39,12 +39,12 @@ static void fn_node_boolean_math_layout(uiLayout *layout, bContext *UNUSED(C), P uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); } -static void node_boolean_math_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_boolean_math_update(bNodeTree *ntree, bNode *node) { bNodeSocket *sockB = (bNodeSocket *)BLI_findlink(&node->inputs, 1); - nodeSetSocketAvailability(sockB, - ELEM(node->custom1, NODE_BOOLEAN_MATH_AND, NODE_BOOLEAN_MATH_OR)); + nodeSetSocketAvailability( + ntree, sockB, ELEM(node->custom1, NODE_BOOLEAN_MATH_AND, NODE_BOOLEAN_MATH_OR)); } static void node_boolean_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen) diff --git a/source/blender/nodes/function/nodes/node_fn_float_compare.cc b/source/blender/nodes/function/nodes/node_fn_float_compare.cc index 2e1f2aaeeef..b31611a1df2 100644 --- a/source/blender/nodes/function/nodes/node_fn_float_compare.cc +++ b/source/blender/nodes/function/nodes/node_fn_float_compare.cc @@ -42,12 +42,14 @@ static void geo_node_float_compare_layout(uiLayout *layout, bContext *UNUSED(C), uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); } -static void node_float_compare_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_float_compare_update(bNodeTree *ntree, bNode *node) { bNodeSocket *sockEpsilon = (bNodeSocket *)BLI_findlink(&node->inputs, 2); nodeSetSocketAvailability( - sockEpsilon, ELEM(node->custom1, NODE_FLOAT_COMPARE_EQUAL, NODE_FLOAT_COMPARE_NOT_EQUAL)); + ntree, + sockEpsilon, + ELEM(node->custom1, NODE_FLOAT_COMPARE_EQUAL, NODE_FLOAT_COMPARE_NOT_EQUAL)); } static void node_float_compare_label(bNodeTree *UNUSED(ntree), diff --git a/source/blender/nodes/function/nodes/node_fn_random_value.cc b/source/blender/nodes/function/nodes/node_fn_random_value.cc index d48b9f3461a..9720a39b740 100644 --- a/source/blender/nodes/function/nodes/node_fn_random_value.cc +++ b/source/blender/nodes/function/nodes/node_fn_random_value.cc @@ -63,7 +63,7 @@ static void fn_node_random_value_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void fn_node_random_value_update(bNodeTree *UNUSED(ntree), bNode *node) +static void fn_node_random_value_update(bNodeTree *ntree, bNode *node) { const NodeRandomValue &storage = *(const NodeRandomValue *)node->storage; const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); @@ -81,18 +81,18 @@ static void fn_node_random_value_update(bNodeTree *UNUSED(ntree), bNode *node) bNodeSocket *sock_out_int = sock_out_float->next; bNodeSocket *sock_out_bool = sock_out_int->next; - nodeSetSocketAvailability(sock_min_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_max_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_min_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_max_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_min_int, data_type == CD_PROP_INT32); - nodeSetSocketAvailability(sock_max_int, data_type == CD_PROP_INT32); - nodeSetSocketAvailability(sock_probability, data_type == CD_PROP_BOOL); - - nodeSetSocketAvailability(sock_out_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_out_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_out_int, data_type == CD_PROP_INT32); - nodeSetSocketAvailability(sock_out_bool, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, sock_min_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_max_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_min_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_max_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_min_int, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, sock_max_int, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, sock_probability, data_type == CD_PROP_BOOL); + + nodeSetSocketAvailability(ntree, sock_out_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_out_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_out_int, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, sock_out_bool, data_type == CD_PROP_BOOL); } class RandomVectorFunction : public fn::MultiFunction { diff --git a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc index fc4c3d8221f..7dbc11fb161 100644 --- a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc +++ b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc @@ -36,18 +36,18 @@ static void fn_node_rotate_euler_declare(NodeDeclarationBuilder &b) b.add_output<decl::Vector>(N_("Rotation")); }; -static void fn_node_rotate_euler_update(bNodeTree *UNUSED(ntree), bNode *node) +static void fn_node_rotate_euler_update(bNodeTree *ntree, bNode *node) { bNodeSocket *rotate_by_socket = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 1)); bNodeSocket *axis_socket = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 2)); bNodeSocket *angle_socket = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 3)); - nodeSetSocketAvailability(rotate_by_socket, - ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_EULER)); - nodeSetSocketAvailability(axis_socket, - ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE)); - nodeSetSocketAvailability(angle_socket, - ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE)); + nodeSetSocketAvailability( + ntree, rotate_by_socket, ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_EULER)); + nodeSetSocketAvailability( + ntree, axis_socket, ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE)); + nodeSetSocketAvailability( + ntree, angle_socket, ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE)); } static void fn_node_rotate_euler_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt new file mode 100644 index 00000000000..61b5bbf6e7e --- /dev/null +++ b/source/blender/nodes/geometry/CMakeLists.txt @@ -0,0 +1,267 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENSE BLOCK ***** + +set(INC + . + ../ + ../intern + ../../editors/include + ../../blenkernel + ../../blenlib + ../../blentranslation + ../../bmesh + ../../depsgraph + ../../functions + ../../geometry + ../../gpu + ../../imbuf + ../../makesdna + ../../makesrna + ../../render + ../../windowmanager + ../../../../intern/guardedalloc +) + + +set(SRC + nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc + nodes/legacy/node_geo_legacy_attribute_clamp.cc + nodes/legacy/node_geo_legacy_attribute_color_ramp.cc + nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc + nodes/legacy/node_geo_legacy_attribute_compare.cc + nodes/legacy/node_geo_legacy_attribute_convert.cc + nodes/legacy/node_geo_legacy_attribute_curve_map.cc + nodes/legacy/node_geo_legacy_attribute_fill.cc + nodes/legacy/node_geo_legacy_attribute_map_range.cc + nodes/legacy/node_geo_legacy_attribute_math.cc + nodes/legacy/node_geo_legacy_attribute_mix.cc + nodes/legacy/node_geo_legacy_attribute_proximity.cc + nodes/legacy/node_geo_legacy_attribute_randomize.cc + nodes/legacy/node_geo_legacy_attribute_sample_texture.cc + nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc + nodes/legacy/node_geo_legacy_attribute_transfer.cc + nodes/legacy/node_geo_legacy_attribute_vector_math.cc + nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc + nodes/legacy/node_geo_legacy_curve_endpoints.cc + nodes/legacy/node_geo_legacy_curve_reverse.cc + nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc + nodes/legacy/node_geo_legacy_curve_set_handles.cc + nodes/legacy/node_geo_legacy_curve_spline_type.cc + nodes/legacy/node_geo_legacy_curve_subdivide.cc + nodes/legacy/node_geo_legacy_curve_to_points.cc + nodes/legacy/node_geo_legacy_delete_geometry.cc + nodes/legacy/node_geo_legacy_edge_split.cc + nodes/legacy/node_geo_legacy_material_assign.cc + nodes/legacy/node_geo_legacy_mesh_to_curve.cc + nodes/legacy/node_geo_legacy_point_distribute.cc + nodes/legacy/node_geo_legacy_point_instance.cc + nodes/legacy/node_geo_legacy_point_rotate.cc + nodes/legacy/node_geo_legacy_point_scale.cc + nodes/legacy/node_geo_legacy_point_separate.cc + nodes/legacy/node_geo_legacy_point_translate.cc + nodes/legacy/node_geo_legacy_points_to_volume.cc + nodes/legacy/node_geo_legacy_raycast.cc + nodes/legacy/node_geo_legacy_select_by_material.cc + nodes/legacy/node_geo_legacy_subdivision_surface.cc + nodes/legacy/node_geo_legacy_volume_to_mesh.cc + + nodes/node_geo_attribute_capture.cc + nodes/node_geo_attribute_remove.cc + nodes/node_geo_attribute_statistic.cc + nodes/node_geo_boolean.cc + nodes/node_geo_bounding_box.cc + nodes/node_geo_collection_info.cc + nodes/node_geo_common.cc + nodes/node_geo_convex_hull.cc + nodes/node_geo_curve_endpoint_selection.cc + nodes/node_geo_curve_fill.cc + nodes/node_geo_curve_fillet.cc + nodes/node_geo_curve_handle_type_selection.cc + nodes/node_geo_curve_length.cc + nodes/node_geo_curve_parameter.cc + nodes/node_geo_curve_primitive_bezier_segment.cc + nodes/node_geo_curve_primitive_circle.cc + nodes/node_geo_curve_primitive_line.cc + nodes/node_geo_curve_primitive_quadratic_bezier.cc + nodes/node_geo_curve_primitive_quadrilateral.cc + nodes/node_geo_curve_primitive_spiral.cc + nodes/node_geo_curve_primitive_star.cc + nodes/node_geo_curve_resample.cc + nodes/node_geo_curve_reverse.cc + nodes/node_geo_curve_sample.cc + nodes/node_geo_curve_set_handles.cc + nodes/node_geo_curve_spline_type.cc + nodes/node_geo_curve_subdivide.cc + nodes/node_geo_curve_to_mesh.cc + nodes/node_geo_curve_to_points.cc + nodes/node_geo_curve_trim.cc + nodes/node_geo_delete_geometry.cc + nodes/node_geo_distribute_points_on_faces.cc + nodes/node_geo_edge_split.cc + nodes/node_geo_image_texture.cc + nodes/node_geo_input_curve_handles.cc + nodes/node_geo_input_curve_tilt.cc + nodes/node_geo_input_id.cc + nodes/node_geo_input_index.cc + nodes/node_geo_input_material_index.cc + nodes/node_geo_input_material.cc + nodes/node_geo_input_normal.cc + nodes/node_geo_input_position.cc + nodes/node_geo_input_radius.cc + nodes/node_geo_input_shade_smooth.cc + nodes/node_geo_input_spline_cyclic.cc + nodes/node_geo_input_spline_length.cc + nodes/node_geo_input_spline_resolution.cc + nodes/node_geo_input_tangent.cc + nodes/node_geo_instance_on_points.cc + nodes/node_geo_instances_to_points.cc + nodes/node_geo_is_viewport.cc + nodes/node_geo_join_geometry.cc + nodes/node_geo_material_replace.cc + nodes/node_geo_material_selection.cc + nodes/node_geo_mesh_primitive_circle.cc + nodes/node_geo_mesh_primitive_cone.cc + nodes/node_geo_mesh_primitive_cube.cc + nodes/node_geo_mesh_primitive_cylinder.cc + nodes/node_geo_mesh_primitive_grid.cc + nodes/node_geo_mesh_primitive_ico_sphere.cc + nodes/node_geo_mesh_primitive_line.cc + nodes/node_geo_mesh_primitive_uv_sphere.cc + nodes/node_geo_mesh_subdivide.cc + nodes/node_geo_mesh_to_curve.cc + nodes/node_geo_mesh_to_points.cc + nodes/node_geo_object_info.cc + nodes/node_geo_points_to_vertices.cc + nodes/node_geo_points_to_volume.cc + nodes/node_geo_proximity.cc + nodes/node_geo_raycast.cc + nodes/node_geo_realize_instances.cc + nodes/node_geo_rotate_instances.cc + nodes/node_geo_scale_instances.cc + nodes/node_geo_separate_components.cc + nodes/node_geo_separate_geometry.cc + nodes/node_geo_set_curve_handles.cc + nodes/node_geo_set_curve_radius.cc + nodes/node_geo_set_curve_tilt.cc + nodes/node_geo_set_id.cc + nodes/node_geo_set_material_index.cc + nodes/node_geo_set_material.cc + nodes/node_geo_set_point_radius.cc + nodes/node_geo_set_position.cc + nodes/node_geo_set_shade_smooth.cc + nodes/node_geo_set_spline_cyclic.cc + nodes/node_geo_set_spline_resolution.cc + nodes/node_geo_string_join.cc + nodes/node_geo_string_to_curves.cc + nodes/node_geo_subdivision_surface.cc + nodes/node_geo_switch.cc + nodes/node_geo_transfer_attribute.cc + nodes/node_geo_transform.cc + nodes/node_geo_translate_instances.cc + nodes/node_geo_triangulate.cc + nodes/node_geo_viewer.cc + nodes/node_geo_volume_to_mesh.cc + + node_geometry_exec.cc + node_geometry_tree.cc + node_geometry_util.cc + + node_geometry_util.hh +) + +set(LIB + bf_bmesh + bf_functions + bf_geometry +) + +if(WITH_BULLET) + list(APPEND INC_SYS + ${BULLET_INCLUDE_DIRS} + "../../../../intern/rigidbody/" + ) + if(NOT WITH_SYSTEM_BULLET) + list(APPEND LIB + extern_bullet + ) + endif() + + list(APPEND LIB + ${BULLET_LIBRARIES} + ) + add_definitions(-DWITH_BULLET) +endif() + +if(WITH_PYTHON) + list(APPEND INC + ../../python + ) + list(APPEND INC_SYS + ${PYTHON_INCLUDE_DIRS} + ) + list(APPEND LIB + ${PYTHON_LINKFLAGS} + ${PYTHON_LIBRARIES} + ) + add_definitions(-DWITH_PYTHON) +endif() + +if(WITH_INTERNATIONAL) + add_definitions(-DWITH_INTERNATIONAL) +endif() + +if(WITH_TBB) + list(APPEND INC_SYS + ${TBB_INCLUDE_DIRS} + ) + add_definitions(-DWITH_TBB) + if(WIN32) + # TBB includes Windows.h which will define min/max macros + # that will collide with the stl versions. + add_definitions(-DNOMINMAX) + endif() +endif() + +if(WITH_IMAGE_OPENEXR) + add_definitions(-DWITH_OPENEXR) +endif() + +if(WITH_OPENSUBDIV) + add_definitions(-DWITH_OPENSUBDIV) +endif() + +if(WITH_GMP) + add_definitions(-DWITH_GMP) + + list(APPEND INC_SYS + ${GMP_INCLUDE_DIRS} + ) + + list(APPEND LIB + ${GMP_LIBRARIES} + ) +endif() + +if(WITH_OPENVDB) + list(APPEND INC_SYS + ${OPENVDB_INCLUDE_DIRS} + ) + add_definitions(-DWITH_OPENVDB ${OPENVDB_DEFINITIONS}) +endif() + +blender_add_lib(bf_nodes_geometry "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/nodes/geometry/node_geometry_util.cc b/source/blender/nodes/geometry/node_geometry_util.cc index 46e9d36c09c..5c1d507041c 100644 --- a/source/blender/nodes/geometry/node_geometry_util.cc +++ b/source/blender/nodes/geometry/node_geometry_util.cc @@ -35,7 +35,8 @@ using bke::GeometryInstanceGroup; * \param mode: Controls which socket of the group to make available. * \param name_is_available: If false, make all sockets with this name unavailable. */ -void update_attribute_input_socket_availabilities(bNode &node, +void update_attribute_input_socket_availabilities(bNodeTree &ntree, + bNode &node, const StringRef name, const GeometryNodeAttributeInputMode mode, const bool name_is_available) @@ -50,7 +51,7 @@ void update_attribute_input_socket_availabilities(bNode &node, (socket->type == SOCK_INT && mode_ == GEO_NODE_ATTRIBUTE_INPUT_INTEGER) || (socket->type == SOCK_VECTOR && mode_ == GEO_NODE_ATTRIBUTE_INPUT_VECTOR) || (socket->type == SOCK_RGBA && mode_ == GEO_NODE_ATTRIBUTE_INPUT_COLOR)); - nodeSetSocketAvailability(socket, socket_is_available); + nodeSetSocketAvailability(&ntree, socket, socket_is_available); } } } @@ -72,6 +73,5 @@ void geo_node_type_base(bNodeType *ntype, int type, const char *name, short ncla { node_type_base(ntype, type, name, nclass, flag); ntype->poll = geo_node_poll_default; - ntype->update_internal_links = node_update_internal_links_default; ntype->insert_link = node_insert_link_default; } diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh index ac346eb705b..79fe2ffc42b 100644 --- a/source/blender/nodes/geometry/node_geometry_util.hh +++ b/source/blender/nodes/geometry/node_geometry_util.hh @@ -43,7 +43,8 @@ bool geo_node_poll_default(struct bNodeType *ntype, const char **r_disabled_hint); namespace blender::nodes { -void update_attribute_input_socket_availabilities(bNode &node, +void update_attribute_input_socket_availabilities(bNodeTree &ntree, + bNode &node, const StringRef name, const GeometryNodeAttributeInputMode mode, const bool name_is_available = true); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc index b92d4704d63..dc7c251d034 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc @@ -65,14 +65,14 @@ static void geo_node_align_rotation_to_vector_init(bNodeTree *UNUSED(ntree), bNo node->storage = node_storage; } -static void geo_node_align_rotation_to_vector_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_align_rotation_to_vector_update(bNodeTree *ntree, bNode *node) { NodeGeometryAlignRotationToVector *node_storage = (NodeGeometryAlignRotationToVector *) node->storage; update_attribute_input_socket_availabilities( - *node, "Factor", (GeometryNodeAttributeInputMode)node_storage->input_type_factor); + *ntree, *node, "Factor", (GeometryNodeAttributeInputMode)node_storage->input_type_factor); update_attribute_input_socket_availabilities( - *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type_vector); + *ntree, *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type_vector); } static void align_rotations_auto_pivot(const VArray<float3> &vectors, @@ -179,9 +179,9 @@ static void align_rotations_on_component(GeometryComponent &component, return; } - GVArray_Typed<float> factors = params.get_input_attribute<float>( + VArray<float> factors = params.get_input_attribute<float>( "Factor", component, ATTR_DOMAIN_POINT, 1.0f); - GVArray_Typed<float3> vectors = params.get_input_attribute<float3>( + VArray<float3> vectors = params.get_input_attribute<float3>( "Vector", component, ATTR_DOMAIN_POINT, {0, 0, 1}); float3 local_main_axis{0, 0, 0}; diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_clamp.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc index 91ff114a480..a11a1bd3825 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_clamp.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc @@ -53,7 +53,7 @@ static void geo_node_attribute_clamp_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_attribute_clamp_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_attribute_clamp_update(bNodeTree *ntree, bNode *node) { bNodeSocket *sock_min_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 3); bNodeSocket *sock_max_vector = sock_min_vector->next; @@ -66,14 +66,14 @@ static void geo_node_attribute_clamp_update(bNodeTree *UNUSED(ntree), bNode *nod const NodeAttributeClamp &storage = *(const NodeAttributeClamp *)node->storage; const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); - nodeSetSocketAvailability(sock_min_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_max_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_min_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_max_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_min_int, data_type == CD_PROP_INT32); - nodeSetSocketAvailability(sock_max_int, data_type == CD_PROP_INT32); - nodeSetSocketAvailability(sock_min_color, data_type == CD_PROP_COLOR); - nodeSetSocketAvailability(sock_max_color, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, sock_min_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_max_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_min_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_max_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_min_int, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, sock_max_int, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, sock_min_color, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, sock_max_color, data_type == CD_PROP_COLOR); } template<typename T> T clamp_value(const T val, const T min, const T max); @@ -156,7 +156,7 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam const AttributeDomain domain = get_result_domain(component, attribute_name, result_name); const int operation = static_cast<int>(storage.operation); - GVArrayPtr attribute_input = component.attribute_try_get_for_read( + GVArray attribute_input = component.attribute_try_get_for_read( attribute_name, domain, data_type); OutputAttribute attribute_result = component.attribute_try_get_for_output_only( @@ -185,7 +185,7 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam } } MutableSpan<float3> results = attribute_result.as_span<float3>(); - clamp_attribute<float3>(attribute_input->typed<float3>(), results, min, max); + clamp_attribute<float3>(attribute_input.typed<float3>(), results, min, max); break; } case CD_PROP_FLOAT: { @@ -193,10 +193,10 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam const float max = params.get_input<float>("Max_001"); MutableSpan<float> results = attribute_result.as_span<float>(); if (operation == NODE_CLAMP_RANGE && min > max) { - clamp_attribute<float>(attribute_input->typed<float>(), results, max, min); + clamp_attribute<float>(attribute_input.typed<float>(), results, max, min); } else { - clamp_attribute<float>(attribute_input->typed<float>(), results, min, max); + clamp_attribute<float>(attribute_input.typed<float>(), results, min, max); } break; } @@ -205,10 +205,10 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam const int max = params.get_input<int>("Max_002"); MutableSpan<int> results = attribute_result.as_span<int>(); if (operation == NODE_CLAMP_RANGE && min > max) { - clamp_attribute<int>(attribute_input->typed<int>(), results, max, min); + clamp_attribute<int>(attribute_input.typed<int>(), results, max, min); } else { - clamp_attribute<int>(attribute_input->typed<int>(), results, min, max); + clamp_attribute<int>(attribute_input.typed<int>(), results, min, max); } break; } @@ -231,7 +231,7 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam } MutableSpan<ColorGeometry4f> results = attribute_result.as_span<ColorGeometry4f>(); clamp_attribute<ColorGeometry4f>( - attribute_input->typed<ColorGeometry4f>(), results, min, max); + attribute_input.typed<ColorGeometry4f>(), results, min, max); break; } default: { diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_color_ramp.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc index ab4b6aad545..061f5f3d7ee 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_color_ramp.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc @@ -85,7 +85,7 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon return; } - GVArray_Typed<float> attribute_in = component.attribute_get_for_read<float>( + VArray<float> attribute_in = component.attribute_get_for_read<float>( input_name, result_domain, 0.0f); MutableSpan<ColorGeometry4f> results = attribute_result.as_span(); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc index d4c23380b4e..a610356955b 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc @@ -57,15 +57,15 @@ static void geo_node_attribute_combine_xyz_init(bNodeTree *UNUSED(tree), bNode * node->storage = data; } -static void geo_node_attribute_combine_xyz_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_attribute_combine_xyz_update(bNodeTree *ntree, bNode *node) { NodeAttributeCombineXYZ *node_storage = (NodeAttributeCombineXYZ *)node->storage; update_attribute_input_socket_availabilities( - *node, "X", (GeometryNodeAttributeInputMode)node_storage->input_type_x); + *ntree, *node, "X", (GeometryNodeAttributeInputMode)node_storage->input_type_x); update_attribute_input_socket_availabilities( - *node, "Y", (GeometryNodeAttributeInputMode)node_storage->input_type_y); + *ntree, *node, "Y", (GeometryNodeAttributeInputMode)node_storage->input_type_y); update_attribute_input_socket_availabilities( - *node, "Z", (GeometryNodeAttributeInputMode)node_storage->input_type_z); + *ntree, *node, "Z", (GeometryNodeAttributeInputMode)node_storage->input_type_z); } static AttributeDomain get_result_domain(const GeometryComponent &component, @@ -95,11 +95,11 @@ static void combine_attributes(GeometryComponent &component, const GeoNodeExecPa if (!attribute_result) { return; } - GVArray_Typed<float> attribute_x = params.get_input_attribute<float>( + VArray<float> attribute_x = params.get_input_attribute<float>( "X", component, result_domain, 0.0f); - GVArray_Typed<float> attribute_y = params.get_input_attribute<float>( + VArray<float> attribute_y = params.get_input_attribute<float>( "Y", component, result_domain, 0.0f); - GVArray_Typed<float> attribute_z = params.get_input_attribute<float>( + VArray<float> attribute_z = params.get_input_attribute<float>( "Z", component, result_domain, 0.0f); for (const int i : IndexRange(attribute_result->size())) { diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_compare.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc index e4e43a7b724..a4ffe884999 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_compare.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc @@ -65,16 +65,16 @@ static bool operation_tests_equality(const NodeAttributeCompare &node_storage) return ELEM(node_storage.operation, NODE_FLOAT_COMPARE_EQUAL, NODE_FLOAT_COMPARE_NOT_EQUAL); } -static void geo_node_attribute_compare_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_attribute_compare_update(bNodeTree *ntree, bNode *node) { NodeAttributeCompare *node_storage = (NodeAttributeCompare *)node->storage; update_attribute_input_socket_availabilities( - *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a); + *ntree, *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a); update_attribute_input_socket_availabilities( - *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b); + *ntree, *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b); bNodeSocket *socket_threshold = (bNodeSocket *)BLI_findlink(&node->inputs, 9); - nodeSetSocketAvailability(socket_threshold, operation_tests_equality(*node_storage)); + nodeSetSocketAvailability(ntree, socket_threshold, operation_tests_equality(*node_storage)); } static void do_math_operation(const VArray<float> &input_a, @@ -257,9 +257,9 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx const CustomDataType input_data_type = get_data_type(component, params, *node_storage); - GVArrayPtr attribute_a = params.get_input_attribute( + GVArray attribute_a = params.get_input_attribute( "A", component, result_domain, input_data_type, nullptr); - GVArrayPtr attribute_b = params.get_input_attribute( + GVArray attribute_b = params.get_input_attribute( "B", component, result_domain, input_data_type, nullptr); if (!attribute_a || !attribute_b) { @@ -276,47 +276,47 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx if (operation == NODE_FLOAT_COMPARE_EQUAL) { if (input_data_type == CD_PROP_FLOAT) { do_equal_operation_float( - attribute_a->typed<float>(), attribute_b->typed<float>(), threshold, result_span); + attribute_a.typed<float>(), attribute_b.typed<float>(), threshold, result_span); } else if (input_data_type == CD_PROP_FLOAT3) { do_equal_operation_float3( - attribute_a->typed<float3>(), attribute_b->typed<float3>(), threshold, result_span); + attribute_a.typed<float3>(), attribute_b.typed<float3>(), threshold, result_span); } else if (input_data_type == CD_PROP_COLOR) { - do_equal_operation_color4f(attribute_a->typed<ColorGeometry4f>(), - attribute_b->typed<ColorGeometry4f>(), + do_equal_operation_color4f(attribute_a.typed<ColorGeometry4f>(), + attribute_b.typed<ColorGeometry4f>(), threshold, result_span); } else if (input_data_type == CD_PROP_BOOL) { do_equal_operation_bool( - attribute_a->typed<bool>(), attribute_b->typed<bool>(), threshold, result_span); + attribute_a.typed<bool>(), attribute_b.typed<bool>(), threshold, result_span); } } else if (operation == NODE_FLOAT_COMPARE_NOT_EQUAL) { if (input_data_type == CD_PROP_FLOAT) { do_not_equal_operation_float( - attribute_a->typed<float>(), attribute_b->typed<float>(), threshold, result_span); + attribute_a.typed<float>(), attribute_b.typed<float>(), threshold, result_span); } else if (input_data_type == CD_PROP_FLOAT3) { do_not_equal_operation_float3( - attribute_a->typed<float3>(), attribute_b->typed<float3>(), threshold, result_span); + attribute_a.typed<float3>(), attribute_b.typed<float3>(), threshold, result_span); } else if (input_data_type == CD_PROP_COLOR) { - do_not_equal_operation_color4f(attribute_a->typed<ColorGeometry4f>(), - attribute_b->typed<ColorGeometry4f>(), + do_not_equal_operation_color4f(attribute_a.typed<ColorGeometry4f>(), + attribute_b.typed<ColorGeometry4f>(), threshold, result_span); } else if (input_data_type == CD_PROP_BOOL) { do_not_equal_operation_bool( - attribute_a->typed<bool>(), attribute_b->typed<bool>(), threshold, result_span); + attribute_a.typed<bool>(), attribute_b.typed<bool>(), threshold, result_span); } } } else { do_math_operation( - attribute_a->typed<float>(), attribute_b->typed<float>(), operation, result_span); + attribute_a.typed<float>(), attribute_b.typed<float>(), operation, result_span); } attribute_result.save(); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_convert.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc index dc05fa2c125..13ba8d13618 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_convert.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc @@ -104,7 +104,7 @@ static void attribute_convert_calc(GeometryComponent &component, return; } - GVArrayPtr source_attribute = component.attribute_try_get_for_read( + GVArray source_attribute = component.attribute_try_get_for_read( source_name, result_domain, result_type); if (!source_attribute) { params.error_message_add(NodeWarningType::Error, @@ -118,7 +118,7 @@ static void attribute_convert_calc(GeometryComponent &component, return; } - GVArray_GSpan source_span{*source_attribute}; + GVArray_GSpan source_span{source_attribute}; GMutableSpan result_span = result_attribute.as_span(); BLI_assert(source_span.size() == result_span.size()); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_curve_map.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc index 669ac21436f..af56df0dc3f 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_curve_map.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc @@ -136,10 +136,10 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon switch (result_type) { case CD_PROP_FLOAT: { const CurveMapping *cumap = (CurveMapping *)node_storage.curve_vec; - GVArray_Typed<float> attribute_in = component.attribute_get_for_read<float>( + VArray<float> attribute_in = component.attribute_get_for_read<float>( input_name, result_domain, float(0.0f)); MutableSpan<float> results = attribute_result.as_span<float>(); - threading::parallel_for(IndexRange(attribute_in.size()), 512, [&](IndexRange range) { + threading::parallel_for(attribute_in.index_range(), 512, [&](IndexRange range) { for (const int i : range) { results[i] = BKE_curvemapping_evaluateF(cumap, 3, attribute_in[i]); } @@ -148,10 +148,10 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon } case CD_PROP_FLOAT3: { const CurveMapping *cumap = (CurveMapping *)node_storage.curve_vec; - GVArray_Typed<float3> attribute_in = component.attribute_get_for_read<float3>( + VArray<float3> attribute_in = component.attribute_get_for_read<float3>( input_name, result_domain, float3(0.0f)); MutableSpan<float3> results = attribute_result.as_span<float3>(); - threading::parallel_for(IndexRange(attribute_in.size()), 512, [&](IndexRange range) { + threading::parallel_for(attribute_in.index_range(), 512, [&](IndexRange range) { for (const int i : range) { BKE_curvemapping_evaluate3F(cumap, results[i], attribute_in[i]); } @@ -160,11 +160,10 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon } case CD_PROP_COLOR: { const CurveMapping *cumap = (CurveMapping *)node_storage.curve_rgb; - GVArray_Typed<ColorGeometry4f> attribute_in = - component.attribute_get_for_read<ColorGeometry4f>( - input_name, result_domain, ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f)); + VArray<ColorGeometry4f> attribute_in = component.attribute_get_for_read<ColorGeometry4f>( + input_name, result_domain, ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f)); MutableSpan<ColorGeometry4f> results = attribute_result.as_span<ColorGeometry4f>(); - threading::parallel_for(IndexRange(attribute_in.size()), 512, [&](IndexRange range) { + threading::parallel_for(attribute_in.index_range(), 512, [&](IndexRange range) { for (const int i : range) { BKE_curvemapping_evaluateRGBF(cumap, results[i], attribute_in[i]); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_fill.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc index 5cb49dd83d0..a1b537e9657 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_fill.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc @@ -47,7 +47,7 @@ static void geo_node_attribute_fill_init(bNodeTree *UNUSED(tree), bNode *node) node->custom2 = ATTR_DOMAIN_AUTO; } -static void geo_node_attribute_fill_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_attribute_fill_update(bNodeTree *ntree, bNode *node) { bNodeSocket *socket_value_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 2); bNodeSocket *socket_value_float = socket_value_vector->next; @@ -57,11 +57,11 @@ static void geo_node_attribute_fill_update(bNodeTree *UNUSED(ntree), bNode *node const CustomDataType data_type = static_cast<CustomDataType>(node->custom1); - nodeSetSocketAvailability(socket_value_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_value_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_value_color4f, data_type == CD_PROP_COLOR); - nodeSetSocketAvailability(socket_value_boolean, data_type == CD_PROP_BOOL); - nodeSetSocketAvailability(socket_value_int32, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, socket_value_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_value_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_value_color4f, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, socket_value_boolean, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, socket_value_int32, data_type == CD_PROP_INT32); } static AttributeDomain get_result_domain(const GeometryComponent &component, const StringRef name) diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_map_range.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc index 978c75187fe..2c70157d586 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_map_range.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc @@ -58,7 +58,7 @@ static void geo_node_attribute_map_range_init(bNodeTree *UNUSED(ntree), bNode *n node->storage = data; } -static void geo_node_attribute_map_range_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_attribute_map_range_update(bNodeTree *ntree, bNode *node) { NodeAttributeMapRange &node_storage = *(NodeAttributeMapRange *)node->storage; @@ -78,23 +78,26 @@ static void geo_node_attribute_map_range_update(bNodeTree *UNUSED(ntree), bNode const CustomDataType data_type = static_cast<CustomDataType>(node_storage.data_type); - nodeSetSocketAvailability(sock_clamp, + nodeSetSocketAvailability(ntree, + sock_clamp, node_storage.interpolation_type == NODE_MAP_RANGE_LINEAR || node_storage.interpolation_type == NODE_MAP_RANGE_STEPPED); - nodeSetSocketAvailability(sock_from_min_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_from_max_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_to_min_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_to_max_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_steps_float, + nodeSetSocketAvailability(ntree, sock_from_min_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_from_max_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_to_min_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_to_max_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, + sock_steps_float, data_type == CD_PROP_FLOAT && node_storage.interpolation_type == NODE_MAP_RANGE_STEPPED); - nodeSetSocketAvailability(sock_from_min_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_from_max_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_to_min_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_to_max_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_steps_vector, + nodeSetSocketAvailability(ntree, sock_from_min_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_from_max_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_to_min_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_to_max_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, + sock_steps_vector, data_type == CD_PROP_FLOAT3 && node_storage.interpolation_type == NODE_MAP_RANGE_STEPPED); } @@ -362,7 +365,7 @@ static void map_range_attribute(GeometryComponent &component, const GeoNodeExecP const AttributeDomain domain = get_result_domain(component, input_name, result_name); - GVArrayPtr attribute_input = component.attribute_try_get_for_read(input_name, domain, data_type); + GVArray attribute_input = component.attribute_try_get_for_read(input_name, domain, data_type); if (!attribute_input) { params.error_message_add(NodeWarningType::Error, @@ -381,12 +384,12 @@ static void map_range_attribute(GeometryComponent &component, const GeoNodeExecP switch (data_type) { case CD_PROP_FLOAT: { - map_range_float(attribute_input->typed<float>(), attribute_result.as_span<float>(), params); + map_range_float(attribute_input.typed<float>(), attribute_result.as_span<float>(), params); break; } case CD_PROP_FLOAT3: { map_range_float3( - attribute_input->typed<float3>(), attribute_result.as_span<float3>(), params); + attribute_input.typed<float3>(), attribute_result.as_span<float3>(), params); break; } default: diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_math.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc index 55d35f87cda..193db7355f9 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_math.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc @@ -141,19 +141,21 @@ static void geo_node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *lab BLI_strncpy(label, IFACE_(name), maxlen); } -static void geo_node_attribute_math_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_attribute_math_update(bNodeTree *ntree, bNode *node) { NodeAttributeMath &node_storage = *(NodeAttributeMath *)node->storage; NodeMathOperation operation = static_cast<NodeMathOperation>(node_storage.operation); update_attribute_input_socket_availabilities( - *node, "A", (GeometryNodeAttributeInputMode)node_storage.input_type_a); + *ntree, *node, "A", (GeometryNodeAttributeInputMode)node_storage.input_type_a); update_attribute_input_socket_availabilities( + *ntree, *node, "B", (GeometryNodeAttributeInputMode)node_storage.input_type_b, operation_use_input_b(operation)); update_attribute_input_socket_availabilities( + *ntree, *node, "C", (GeometryNodeAttributeInputMode)node_storage.input_type_c, @@ -250,7 +252,7 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP return; } - GVArray_Typed<float> attribute_a = params.get_input_attribute<float>( + VArray<float> attribute_a = params.get_input_attribute<float>( "A", component, result_domain, 0.0f); MutableSpan<float> result_span = attribute_result.as_span(); @@ -258,10 +260,10 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP /* Note that passing the data with `get_internal_span<float>()` works * because the attributes were accessed with #CD_PROP_FLOAT. */ if (operation_use_input_b(operation)) { - GVArray_Typed<float> attribute_b = params.get_input_attribute<float>( + VArray<float> attribute_b = params.get_input_attribute<float>( "B", component, result_domain, 0.0f); if (operation_use_input_c(operation)) { - GVArray_Typed<float> attribute_c = params.get_input_attribute<float>( + VArray<float> attribute_c = params.get_input_attribute<float>( "C", component, result_domain, 0.0f); do_math_operation(attribute_a, attribute_b, attribute_c, result_span, operation); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_mix.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc index b4205bc91b7..6c7f2313633 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_mix.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc @@ -70,15 +70,15 @@ static void geo_node_attribute_mix_init(bNodeTree *UNUSED(ntree), bNode *node) node->storage = data; } -static void geo_node_attribute_mix_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_attribute_mix_update(bNodeTree *ntree, bNode *node) { NodeAttributeMix *node_storage = (NodeAttributeMix *)node->storage; update_attribute_input_socket_availabilities( - *node, "Factor", (GeometryNodeAttributeInputMode)node_storage->input_type_factor); + *ntree, *node, "Factor", (GeometryNodeAttributeInputMode)node_storage->input_type_factor); update_attribute_input_socket_availabilities( - *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a); + *ntree, *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a); update_attribute_input_socket_availabilities( - *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b); + *ntree, *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b); } static void do_mix_operation_float(const int blend_mode, @@ -144,25 +144,28 @@ static void do_mix_operation(const CustomDataType result_type, GVMutableArray &attribute_result) { if (result_type == CD_PROP_FLOAT) { + VMutableArray<float> result = attribute_result.typed<float>(); do_mix_operation_float(blend_mode, attribute_factor, attribute_a.typed<float>(), attribute_b.typed<float>(), - attribute_result.typed<float>()); + result); } else if (result_type == CD_PROP_FLOAT3) { + VMutableArray<float3> result = attribute_result.typed<float3>(); do_mix_operation_float3(blend_mode, attribute_factor, attribute_a.typed<float3>(), attribute_b.typed<float3>(), - attribute_result.typed<float3>()); + result); } else if (result_type == CD_PROP_COLOR) { + VMutableArray<ColorGeometry4f> result = attribute_result.typed<ColorGeometry4f>(); do_mix_operation_color4f(blend_mode, attribute_factor, attribute_a.typed<ColorGeometry4f>(), attribute_b.typed<ColorGeometry4f>(), - attribute_result.typed<ColorGeometry4f>()); + result); } } @@ -203,19 +206,19 @@ static void attribute_mix_calc(GeometryComponent &component, const GeoNodeExecPa return; } - GVArray_Typed<float> attribute_factor = params.get_input_attribute<float>( + VArray<float> attribute_factor = params.get_input_attribute<float>( "Factor", component, result_domain, 0.5f); - GVArrayPtr attribute_a = params.get_input_attribute( + GVArray attribute_a = params.get_input_attribute( "A", component, result_domain, result_type, nullptr); - GVArrayPtr attribute_b = params.get_input_attribute( + GVArray attribute_b = params.get_input_attribute( "B", component, result_domain, result_type, nullptr); do_mix_operation(result_type, node_storage->blend_type, attribute_factor, - *attribute_a, - *attribute_b, - *attribute_result); + attribute_a, + attribute_b, + attribute_result.varray()); attribute_result.save(); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_proximity.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc index 9e3a7984c53..0122f9b7598 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_proximity.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc @@ -153,7 +153,7 @@ static void attribute_calc_proximity(GeometryComponent &component, if (!position_attribute || (!distance_attribute && !location_attribute)) { return; } - GVArray_Typed<float3> positions{*position_attribute.varray}; + VArray<float3> positions = position_attribute.varray.typed<float3>(); const NodeGeometryAttributeProximity &storage = *(const NodeGeometryAttributeProximity *)params.node().storage; diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_randomize.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc index 2901472d661..f8d9dcdaf87 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_randomize.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc @@ -57,7 +57,7 @@ static void geo_node_legacy_attribute_randomize_init(bNodeTree *UNUSED(tree), bN node->storage = data; } -static void geo_node_legacy_attribute_randomize_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_legacy_attribute_randomize_update(bNodeTree *ntree, bNode *node) { bNodeSocket *sock_min_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 2); bNodeSocket *sock_max_vector = sock_min_vector->next; @@ -68,12 +68,12 @@ static void geo_node_legacy_attribute_randomize_update(bNodeTree *UNUSED(ntree), const NodeAttributeRandomize &storage = *(const NodeAttributeRandomize *)node->storage; const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); - nodeSetSocketAvailability(sock_min_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_max_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_min_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_max_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_min_int, data_type == CD_PROP_INT32); - nodeSetSocketAvailability(sock_max_int, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, sock_min_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_max_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_min_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_max_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_min_int, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, sock_max_int, data_type == CD_PROP_INT32); } template<typename T> @@ -180,13 +180,13 @@ Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &compo const int domain_size = component.attribute_domain_size(domain); /* Hash the reserved name attribute "id" as a (hopefully) stable seed for each point. */ - GVArrayPtr hash_attribute = component.attribute_try_get_for_read("id", domain); + GVArray hash_attribute = component.attribute_try_get_for_read("id", domain); Array<uint32_t> hashes(domain_size); if (hash_attribute) { - BLI_assert(hashes.size() == hash_attribute->size()); - const CPPType &cpp_type = hash_attribute->type(); + BLI_assert(hashes.size() == hash_attribute.size()); + const CPPType &cpp_type = hash_attribute.type(); BLI_assert(cpp_type.is_hashable()); - GVArray_GSpan items{*hash_attribute}; + GVArray_GSpan items{hash_attribute}; threading::parallel_for(hashes.index_range(), 512, [&](IndexRange range) { for (const int i : range) { hashes[i] = cpp_type.hash(items[i]); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_sample_texture.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc index 19d6ced6eb6..9748ca3f2ad 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_sample_texture.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc @@ -82,7 +82,7 @@ static void execute_on_component(GeometryComponent &component, const GeoNodeExec return; } - GVArray_Typed<float3> mapping_attribute = component.attribute_get_for_read<float3>( + VArray<float3> mapping_attribute = component.attribute_get_for_read<float3>( mapping_name, result_domain, {0, 0, 0}); MutableSpan<ColorGeometry4f> colors = attribute_out.as_span(); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc index 809e75e73a3..bfc69780bf6 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc @@ -49,11 +49,11 @@ static void geo_node_attribute_separate_xyz_init(bNodeTree *UNUSED(tree), bNode node->storage = data; } -static void geo_node_attribute_separate_xyz_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_attribute_separate_xyz_update(bNodeTree *ntree, bNode *node) { NodeAttributeSeparateXYZ *node_storage = (NodeAttributeSeparateXYZ *)node->storage; update_attribute_input_socket_availabilities( - *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type); + *ntree, *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type); } static void extract_input(const int index, const Span<float3> &input, MutableSpan<float> result) @@ -106,9 +106,9 @@ static void separate_attribute(GeometryComponent &component, const GeoNodeExecPa const AttributeDomain result_domain = get_result_domain( component, params, result_name_x, result_name_y, result_name_z); - GVArray_Typed<float3> attribute_input = params.get_input_attribute<float3>( + VArray<float3> attribute_input = params.get_input_attribute<float3>( "Vector", component, result_domain, {0, 0, 0}); - VArray_Span<float3> input_span{*attribute_input}; + VArray_Span<float3> input_span{attribute_input}; OutputAttribute_Typed<float> attribute_result_x = component.attribute_try_get_for_output_only<float>(result_name_x, result_domain); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_transfer.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc index 3a9cd52661a..b8827f82efc 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_transfer.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc @@ -407,13 +407,13 @@ static void transfer_attribute_nearest(const GeometrySet &src_geometry, if (pointcloud_distances_sq[i] < mesh_distances_sq[i]) { /* Point-cloud point is closer. */ const int index = pointcloud_indices[i]; - pointcloud_src_attribute.varray->get(index, buffer); + pointcloud_src_attribute.varray.get(index, buffer); dst_attribute->set_by_relocate(i, buffer); } else { /* Mesh element is closer. */ const int index = mesh_indices[i]; - mesh_src_attribute.varray->get(index, buffer); + mesh_src_attribute.varray.get(index, buffer); dst_attribute->set_by_relocate(i, buffer); } } @@ -424,7 +424,7 @@ static void transfer_attribute_nearest(const GeometrySet &src_geometry, src_name, data_type); for (const int i : IndexRange(tot_samples)) { const int index = pointcloud_indices[i]; - src_attribute.varray->get(index, buffer); + src_attribute.varray.get(index, buffer); dst_attribute->set_by_relocate(i, buffer); } } @@ -434,7 +434,7 @@ static void transfer_attribute_nearest(const GeometrySet &src_geometry, data_type); for (const int i : IndexRange(tot_samples)) { const int index = mesh_indices[i]; - src_attribute.varray->get(index, buffer); + src_attribute.varray.get(index, buffer); dst_attribute->set_by_relocate(i, buffer); } } @@ -460,7 +460,7 @@ static void transfer_attribute(const GeoNodeExecParams ¶ms, const AttributeDomain dst_domain = (input_domain == ATTR_DOMAIN_AUTO) ? auto_domain : input_domain; - GVArray_Typed<float3> dst_positions = dst_component.attribute_get_for_read<float3>( + VArray<float3> dst_positions = dst_component.attribute_get_for_read<float3>( "position", dst_domain, {0, 0, 0}); switch (mapping) { diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_math.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc index 4c351846243..e7fdd0f2eef 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_math.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc @@ -166,19 +166,21 @@ static void geo_node_vector_math_label(bNodeTree *UNUSED(ntree), BLI_snprintf(label, maxlen, IFACE_("Vector %s"), IFACE_(name)); } -static void geo_node_attribute_vector_math_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_attribute_vector_math_update(bNodeTree *ntree, bNode *node) { const NodeAttributeVectorMath *node_storage = (NodeAttributeVectorMath *)node->storage; const NodeVectorMathOperation operation = (const NodeVectorMathOperation)node_storage->operation; update_attribute_input_socket_availabilities( - *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a); + *ntree, *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a); update_attribute_input_socket_availabilities( + *ntree, *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b, operation_use_input_b(operation)); update_attribute_input_socket_availabilities( + *ntree, *node, "C", (GeometryNodeAttributeInputMode)node_storage->input_type_c, @@ -187,7 +189,7 @@ static void geo_node_attribute_vector_math_update(bNodeTree *UNUSED(ntree), bNod static void do_math_operation_fl3_fl3_to_fl3(const VArray<float3> &input_a, const VArray<float3> &input_b, - VMutableArray<float3> &result, + const VMutableArray<float3> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); @@ -218,7 +220,7 @@ static void do_math_operation_fl3_fl3_to_fl3(const VArray<float3> &input_a, static void do_math_operation_fl3_fl3_fl3_to_fl3(const VArray<float3> &input_a, const VArray<float3> &input_b, const VArray<float3> &input_c, - VMutableArray<float3> &result, + const VMutableArray<float3> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); @@ -251,7 +253,7 @@ static void do_math_operation_fl3_fl3_fl3_to_fl3(const VArray<float3> &input_a, static void do_math_operation_fl3_fl3_fl_to_fl3(const VArray<float3> &input_a, const VArray<float3> &input_b, const VArray<float> &input_c, - VMutableArray<float3> &result, + const VMutableArray<float3> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); @@ -283,7 +285,7 @@ static void do_math_operation_fl3_fl3_fl_to_fl3(const VArray<float3> &input_a, static void do_math_operation_fl3_fl3_to_fl(const VArray<float3> &input_a, const VArray<float3> &input_b, - VMutableArray<float> &result, + const VMutableArray<float> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); @@ -313,7 +315,7 @@ static void do_math_operation_fl3_fl3_to_fl(const VArray<float3> &input_a, static void do_math_operation_fl3_fl_to_fl3(const VArray<float3> &input_a, const VArray<float> &input_b, - VMutableArray<float3> &result, + const VMutableArray<float3> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); @@ -342,7 +344,7 @@ static void do_math_operation_fl3_fl_to_fl3(const VArray<float3> &input_a, } static void do_math_operation_fl3_to_fl3(const VArray<float3> &input_a, - VMutableArray<float3> &result, + const VMutableArray<float3> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); @@ -369,7 +371,7 @@ static void do_math_operation_fl3_to_fl3(const VArray<float3> &input_a, } static void do_math_operation_fl3_to_fl(const VArray<float3> &input_a, - VMutableArray<float> &result, + const VMutableArray<float> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); @@ -437,13 +439,13 @@ static void attribute_vector_math_calc(GeometryComponent &component, const AttributeDomain result_domain = get_result_domain( component, params, operation, result_name); - GVArrayPtr attribute_a = params.get_input_attribute( + GVArray attribute_a = params.get_input_attribute( "A", component, result_domain, read_type_a, nullptr); if (!attribute_a) { return; } - GVArrayPtr attribute_b; - GVArrayPtr attribute_c; + GVArray attribute_b; + GVArray attribute_c; if (use_input_b) { attribute_b = params.get_input_attribute("B", component, result_domain, read_type_b, nullptr); if (!attribute_b) { @@ -476,26 +478,26 @@ static void attribute_vector_math_calc(GeometryComponent &component, case NODE_VECTOR_MATH_MODULO: case NODE_VECTOR_MATH_MINIMUM: case NODE_VECTOR_MATH_MAXIMUM: - do_math_operation_fl3_fl3_to_fl3(attribute_a->typed<float3>(), - attribute_b->typed<float3>(), - attribute_result->typed<float3>(), + do_math_operation_fl3_fl3_to_fl3(attribute_a.typed<float3>(), + attribute_b.typed<float3>(), + attribute_result.varray().typed<float3>(), operation); break; case NODE_VECTOR_MATH_DOT_PRODUCT: case NODE_VECTOR_MATH_DISTANCE: - do_math_operation_fl3_fl3_to_fl(attribute_a->typed<float3>(), - attribute_b->typed<float3>(), - attribute_result->typed<float>(), + do_math_operation_fl3_fl3_to_fl(attribute_a.typed<float3>(), + attribute_b.typed<float3>(), + attribute_result.varray().typed<float>(), operation); break; case NODE_VECTOR_MATH_LENGTH: do_math_operation_fl3_to_fl( - attribute_a->typed<float3>(), attribute_result->typed<float>(), operation); + attribute_a.typed<float3>(), attribute_result.varray().typed<float>(), operation); break; case NODE_VECTOR_MATH_SCALE: - do_math_operation_fl3_fl_to_fl3(attribute_a->typed<float3>(), - attribute_b->typed<float>(), - attribute_result->typed<float3>(), + do_math_operation_fl3_fl_to_fl3(attribute_a.typed<float3>(), + attribute_b.typed<float>(), + attribute_result.varray().typed<float3>(), operation); break; case NODE_VECTOR_MATH_NORMALIZE: @@ -507,22 +509,22 @@ static void attribute_vector_math_calc(GeometryComponent &component, case NODE_VECTOR_MATH_COSINE: case NODE_VECTOR_MATH_TANGENT: do_math_operation_fl3_to_fl3( - attribute_a->typed<float3>(), attribute_result->typed<float3>(), operation); + attribute_a.typed<float3>(), attribute_result.varray().typed<float3>(), operation); break; case NODE_VECTOR_MATH_WRAP: case NODE_VECTOR_MATH_FACEFORWARD: case NODE_VECTOR_MATH_MULTIPLY_ADD: - do_math_operation_fl3_fl3_fl3_to_fl3(attribute_a->typed<float3>(), - attribute_b->typed<float3>(), - attribute_c->typed<float3>(), - attribute_result->typed<float3>(), + do_math_operation_fl3_fl3_fl3_to_fl3(attribute_a.typed<float3>(), + attribute_b.typed<float3>(), + attribute_c.typed<float3>(), + attribute_result.varray().typed<float3>(), operation); break; case NODE_VECTOR_MATH_REFRACT: - do_math_operation_fl3_fl3_fl_to_fl3(attribute_a->typed<float3>(), - attribute_b->typed<float3>(), - attribute_c->typed<float>(), - attribute_result->typed<float3>(), + do_math_operation_fl3_fl3_fl_to_fl3(attribute_a.typed<float3>(), + attribute_b.typed<float3>(), + attribute_c.typed<float>(), + attribute_result.varray().typed<float3>(), operation); break; } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc index 9ab8ec25fb6..a6cd24ed72d 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc @@ -70,27 +70,30 @@ static void geo_node_attribute_vector_rotate_layout(uiLayout *layout, } } -static void geo_node_attribute_vector_rotate_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_attribute_vector_rotate_update(bNodeTree *ntree, bNode *node) { const NodeAttributeVectorRotate *node_storage = (NodeAttributeVectorRotate *)node->storage; const GeometryNodeAttributeVectorRotateMode mode = (const GeometryNodeAttributeVectorRotateMode) node_storage->mode; update_attribute_input_socket_availabilities( - *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type_vector); + *ntree, *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type_vector); update_attribute_input_socket_availabilities( - *node, "Center", (GeometryNodeAttributeInputMode)node_storage->input_type_center); + *ntree, *node, "Center", (GeometryNodeAttributeInputMode)node_storage->input_type_center); update_attribute_input_socket_availabilities( + *ntree, *node, "Axis", (GeometryNodeAttributeInputMode)node_storage->input_type_axis, (mode == GEO_NODE_VECTOR_ROTATE_TYPE_AXIS)); update_attribute_input_socket_availabilities( + *ntree, *node, "Angle", (GeometryNodeAttributeInputMode)node_storage->input_type_angle, (mode != GEO_NODE_VECTOR_ROTATE_TYPE_EULER_XYZ)); update_attribute_input_socket_availabilities( + *ntree, *node, "Rotation", (GeometryNodeAttributeInputMode)node_storage->input_type_rotation, @@ -220,12 +223,12 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon const AttributeDomain result_domain = get_result_domain(component, params, result_name); const bool invert = params.get_input<bool>("Invert"); - GVArrayPtr attribute_vector = params.get_input_attribute( + GVArray attribute_vector = params.get_input_attribute( "Vector", component, result_domain, CD_PROP_FLOAT3, nullptr); if (!attribute_vector) { return; } - GVArrayPtr attribute_center = params.get_input_attribute( + GVArray attribute_center = params.get_input_attribute( "Center", component, result_domain, CD_PROP_FLOAT3, nullptr); if (!attribute_center) { return; @@ -238,21 +241,21 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon } if (mode == GEO_NODE_VECTOR_ROTATE_TYPE_EULER_XYZ) { - GVArrayPtr attribute_rotation = params.get_input_attribute( + GVArray attribute_rotation = params.get_input_attribute( "Rotation", component, result_domain, CD_PROP_FLOAT3, nullptr); if (!attribute_rotation) { return; } - do_vector_rotate_euler(attribute_vector->typed<float3>(), - attribute_center->typed<float3>(), - attribute_rotation->typed<float3>(), + do_vector_rotate_euler(attribute_vector.typed<float3>(), + attribute_center.typed<float3>(), + attribute_rotation.typed<float3>(), attribute_result.as_span<float3>(), invert); attribute_result.save(); return; } - GVArrayPtr attribute_angle = params.get_input_attribute( + GVArray attribute_angle = params.get_input_attribute( "Angle", component, result_domain, CD_PROP_FLOAT, nullptr); if (!attribute_angle) { return; @@ -260,40 +263,40 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon switch (mode) { case GEO_NODE_VECTOR_ROTATE_TYPE_AXIS: { - GVArrayPtr attribute_axis = params.get_input_attribute( + GVArray attribute_axis = params.get_input_attribute( "Axis", component, result_domain, CD_PROP_FLOAT3, nullptr); if (!attribute_axis) { return; } - do_vector_rotate_around_axis(attribute_vector->typed<float3>(), - attribute_center->typed<float3>(), - attribute_axis->typed<float3>(), - attribute_angle->typed<float>(), + do_vector_rotate_around_axis(attribute_vector.typed<float3>(), + attribute_center.typed<float3>(), + attribute_axis.typed<float3>(), + attribute_angle.typed<float>(), attribute_result.as_span<float3>(), invert); } break; case GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_X: - do_vector_rotate_around_fixed_axis(attribute_vector->typed<float3>(), - attribute_center->typed<float3>(), + do_vector_rotate_around_fixed_axis(attribute_vector.typed<float3>(), + attribute_center.typed<float3>(), float3(1.0f, 0.0f, 0.0f), - attribute_angle->typed<float>(), + attribute_angle.typed<float>(), attribute_result.as_span<float3>(), invert); break; case GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_Y: - do_vector_rotate_around_fixed_axis(attribute_vector->typed<float3>(), - attribute_center->typed<float3>(), + do_vector_rotate_around_fixed_axis(attribute_vector.typed<float3>(), + attribute_center.typed<float3>(), float3(0.0f, 1.0f, 0.0f), - attribute_angle->typed<float>(), + attribute_angle.typed<float>(), attribute_result.as_span<float3>(), invert); break; case GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_Z: - do_vector_rotate_around_fixed_axis(attribute_vector->typed<float3>(), - attribute_center->typed<float3>(), + do_vector_rotate_around_fixed_axis(attribute_vector.typed<float3>(), + attribute_center.typed<float3>(), float3(0.0f, 0.0f, 1.0f), - attribute_angle->typed<float>(), + attribute_angle.typed<float>(), attribute_result.as_span<float3>(), invert); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_endpoints.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc index 8b81008ff34..67c8200a9c2 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_endpoints.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc @@ -61,7 +61,7 @@ static void copy_spline_domain_attributes(const CurveComponent &curve_component, if (meta_data.domain != ATTR_DOMAIN_CURVE) { return true; } - GVArrayPtr spline_attribute = curve_component.attribute_get_for_read( + GVArray spline_attribute = curve_component.attribute_get_for_read( attribute_id, ATTR_DOMAIN_CURVE, meta_data.data_type); OutputAttribute result_attribute = points.attribute_try_get_for_output_only( @@ -70,7 +70,7 @@ static void copy_spline_domain_attributes(const CurveComponent &curve_component, /* Only copy the attributes of splines in the offsets. */ for (const int i : offsets.index_range()) { - spline_attribute->get(offsets[i], result[i]); + spline_attribute.get(offsets[i], result[i]); } result_attribute.save(); @@ -130,7 +130,7 @@ static void copy_endpoint_attributes(Span<SplinePtr> splines, BLI_assert(spline.attributes.get_for_read(attribute_id)); GSpan spline_span = *spline.attributes.get_for_read(attribute_id); - blender::fn::GVArray_For_GSpan(spline_span).get(0, point_span[i]); + spline_span.type().copy_assign(spline_span[0], point_span[i]); } for (const auto item : end_data.point_attributes.items()) { @@ -139,7 +139,7 @@ static void copy_endpoint_attributes(Span<SplinePtr> splines, BLI_assert(spline.attributes.get_for_read(attribute_id)); GSpan spline_span = *spline.attributes.get_for_read(attribute_id); - blender::fn::GVArray_For_GSpan(spline_span).get(spline.size() - 1, point_span[i]); + spline_span.type().copy_assign(spline_span[spline.size() - 1], point_span[i]); } } }); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc index ba76fafe3e6..bc4612e2b8b 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_reverse.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc @@ -44,7 +44,7 @@ static void geo_node_curve_reverse_exec(GeoNodeExecParams params) MutableSpan<SplinePtr> splines = curve.splines(); const std::string selection_name = params.extract_input<std::string>("Selection"); - GVArray_Typed<bool> selection = curve_component.attribute_get_for_read( + VArray<bool> selection = curve_component.attribute_get_for_read( selection_name, ATTR_DOMAIN_CURVE, true); threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) { diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc index 40d827ae141..40d827ae141 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc index 4bac9cb976e..b92db315d94 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_set_handles.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc @@ -84,7 +84,7 @@ static void geo_node_curve_set_handles_exec(GeoNodeExecParams params) MutableSpan<SplinePtr> splines = curve.splines(); const std::string selection_name = params.extract_input<std::string>("Selection"); - GVArray_Typed<bool> selection = curve_component.attribute_get_for_read( + VArray<bool> selection = curve_component.attribute_get_for_read( selection_name, ATTR_DOMAIN_POINT, true); const BezierSpline::HandleType new_handle_type = handle_type_from_input_type(type); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc index df53c96e6ca..36d4519cac3 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_spline_type.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc @@ -255,7 +255,7 @@ static void geo_node_legacy_curve_spline_type_exec(GeoNodeExecParams params) const CurveEval &curve = *curve_component->get_for_read(); const std::string selection_name = params.extract_input<std::string>("Selection"); - GVArray_Typed<bool> selection = curve_component->attribute_get_for_read( + VArray<bool> selection = curve_component->attribute_get_for_read( selection_name, ATTR_DOMAIN_CURVE, true); std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>(); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc index f9b0a9d128e..603547a8e69 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc @@ -25,10 +25,6 @@ #include "node_geometry_util.hh" -using blender::fn::GVArray_For_GSpan; -using blender::fn::GVArray_For_Span; -using blender::fn::GVArray_Typed; - namespace blender::nodes { static void geo_node_curve_subdivide_declare(NodeDeclarationBuilder &b) @@ -55,12 +51,12 @@ static void geo_node_curve_subdivide_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_curve_subdivide_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_curve_subdivide_update(bNodeTree *ntree, bNode *node) { NodeGeometryPointTranslate &node_storage = *(NodeGeometryPointTranslate *)node->storage; update_attribute_input_socket_availabilities( - *node, "Cuts", (GeometryNodeAttributeInputMode)node_storage.input_type); + *ntree, *node, "Cuts", (GeometryNodeAttributeInputMode)node_storage.input_type); } static Array<int> get_subdivided_offsets(const Spline &spline, @@ -363,14 +359,13 @@ static void geo_node_subdivide_exec(GeoNodeExecParams params) } const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>(); - GVArray_Typed<int> cuts = params.get_input_attribute<int>( - "Cuts", component, ATTR_DOMAIN_POINT, 0); - if (cuts->is_single() && cuts->get_internal_single() < 1) { + VArray<int> cuts = params.get_input_attribute<int>("Cuts", component, ATTR_DOMAIN_POINT, 0); + if (cuts.is_single() && cuts.get_internal_single() < 1) { params.set_output("Geometry", geometry_set); return; } - std::unique_ptr<CurveEval> output_curve = subdivide_curve(*component.get_for_read(), *cuts); + std::unique_ptr<CurveEval> output_curve = subdivide_curve(*component.get_for_read(), cuts); params.set_output("Geometry", GeometrySet::create_with_curve(output_curve.release())); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc index c171d485a6a..ab51258cc69 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_to_points.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc @@ -50,7 +50,7 @@ static void geo_node_curve_to_points_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_curve_to_points_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_curve_to_points_update(bNodeTree *ntree, bNode *node) { NodeGeometryCurveToPoints &node_storage = *(NodeGeometryCurveToPoints *)node->storage; const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode; @@ -58,8 +58,8 @@ static void geo_node_curve_to_points_update(bNodeTree *UNUSED(ntree), bNode *nod bNodeSocket *count_socket = ((bNodeSocket *)node->inputs.first)->next; bNodeSocket *length_socket = count_socket->next; - nodeSetSocketAvailability(count_socket, mode == GEO_NODE_CURVE_RESAMPLE_COUNT); - nodeSetSocketAvailability(length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH); + nodeSetSocketAvailability(ntree, count_socket, mode == GEO_NODE_CURVE_RESAMPLE_COUNT); + nodeSetSocketAvailability(ntree, length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH); } /** @@ -121,7 +121,7 @@ static GMutableSpan create_attribute_and_retrieve_span(PointCloudComponent &poin points.attribute_try_create(attribute_id, ATTR_DOMAIN_POINT, data_type, AttributeInitDefault()); WriteAttributeLookup attribute = points.attribute_try_get_for_write(attribute_id); BLI_assert(attribute); - return attribute.varray->get_internal_span(); + return attribute.varray.get_internal_span(); } template<typename T> @@ -177,8 +177,8 @@ static void copy_evaluated_point_attributes(Span<SplinePtr> splines, const int size = offsets[i + 1] - offsets[i]; data.positions.slice(offset, size).copy_from(spline.evaluated_positions()); - spline.interpolate_to_evaluated(spline.radii())->materialize(data.radii.slice(offset, size)); - spline.interpolate_to_evaluated(spline.tilts())->materialize(data.tilts.slice(offset, size)); + spline.interpolate_to_evaluated(spline.radii()).materialize(data.radii.slice(offset, size)); + spline.interpolate_to_evaluated(spline.tilts()).materialize(data.tilts.slice(offset, size)); for (const Map<AttributeIDRef, GMutableSpan>::Item item : data.point_attributes.items()) { const AttributeIDRef attribute_id = item.key; @@ -188,7 +188,7 @@ static void copy_evaluated_point_attributes(Span<SplinePtr> splines, GSpan spline_span = *spline.attributes.get_for_read(attribute_id); spline.interpolate_to_evaluated(spline_span) - ->materialize(point_span.slice(offset, size).data()); + .materialize(point_span.slice(offset, size).data()); } data.tangents.slice(offset, size).copy_from(spline.evaluated_tangents()); @@ -230,7 +230,7 @@ static void copy_uniform_sample_point_attributes(Span<SplinePtr> splines, BLI_assert(spline.attributes.get_for_read(attribute_id)); GSpan spline_span = *spline.attributes.get_for_read(attribute_id); - spline.sample_with_index_factors(*spline.interpolate_to_evaluated(spline_span), + spline.sample_with_index_factors(spline.interpolate_to_evaluated(spline_span), uniform_samples, point_span.slice(offset, size)); } @@ -263,20 +263,20 @@ static void copy_spline_domain_attributes(const CurveComponent &curve_component, if (meta_data.domain != ATTR_DOMAIN_CURVE) { return true; } - GVArrayPtr spline_attribute = curve_component.attribute_get_for_read( + GVArray spline_attribute = curve_component.attribute_get_for_read( attribute_id, ATTR_DOMAIN_CURVE, meta_data.data_type); - const CPPType &type = spline_attribute->type(); + const CPPType &type = spline_attribute.type(); OutputAttribute result_attribute = points.attribute_try_get_for_output_only( attribute_id, ATTR_DOMAIN_POINT, meta_data.data_type); GMutableSpan result = result_attribute.as_span(); - for (const int i : IndexRange(spline_attribute->size())) { + for (const int i : spline_attribute.index_range()) { const int offset = offsets[i]; const int size = offsets[i + 1] - offsets[i]; if (size != 0) { BUFFER_FOR_CPP_TYPE_VALUE(type, buffer); - spline_attribute->get(i, buffer); + spline_attribute.get(i, buffer); type.fill_assign_n(buffer, result[offset], size); } } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc index 1d76a0532a1..8d7c05ea533 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_delete_geometry.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc @@ -29,19 +29,19 @@ using blender::bke::CustomDataAttributes; /* Code from the mask modifier in MOD_mask.cc. */ -extern void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh, - Mesh &dst_mesh, - blender::Span<int> vertex_map); -extern void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, - Mesh &dst_mesh, - blender::Span<int> vertex_map, - blender::Span<int> edge_map); -extern void copy_masked_polys_to_new_mesh(const Mesh &src_mesh, - Mesh &dst_mesh, - blender::Span<int> vertex_map, - blender::Span<int> edge_map, - blender::Span<int> masked_poly_indices, - blender::Span<int> new_loop_starts); +void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + blender::Span<int> vertex_map); +void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + blender::Span<int> vertex_map, + blender::Span<int> edge_map); +void copy_masked_polys_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + blender::Span<int> vertex_map, + blender::Span<int> edge_map, + blender::Span<int> masked_poly_indices, + blender::Span<int> new_loop_starts); namespace blender::nodes { @@ -137,7 +137,7 @@ static std::unique_ptr<CurveEval> curve_delete(const CurveEval &input_curve, Vector<int64_t> copied_splines; if (input_curve.attributes.get_for_read(name)) { - GVArray_Typed<bool> selection = input_curve.attributes.get_for_read<bool>(name, false); + VArray<bool> selection = input_curve.attributes.get_for_read<bool>(name, false); for (const int i : input_splines.index_range()) { if (selection[i] == invert) { output_curve->add_spline(input_splines[i]->copy()); @@ -151,7 +151,7 @@ static std::unique_ptr<CurveEval> curve_delete(const CurveEval &input_curve, for (const int i : input_splines.index_range()) { const Spline &spline = *input_splines[i]; - GVArray_Typed<bool> selection = spline.attributes.get_for_read<bool>(name, false); + VArray<bool> selection = spline.attributes.get_for_read<bool>(name, false); indices_to_copy.clear(); for (const int i_point : IndexRange(spline.size())) { @@ -202,7 +202,7 @@ static void delete_point_cloud_selection(const PointCloudComponent &in_component const StringRef selection_name, const bool invert) { - const GVArray_Typed<bool> selection_attribute = in_component.attribute_get_for_read<bool>( + const VArray<bool> selection_attribute = in_component.attribute_get_for_read<bool>( selection_name, ATTR_DOMAIN_POINT, false); VArray_Span<bool> selection{selection_attribute}; @@ -590,7 +590,7 @@ static void delete_mesh_selection(MeshComponent &component, const AttributeDomain selection_domain = get_mesh_selection_domain(component, selection_name); /* This already checks if the attribute exists, and displays a warning in that case. */ - GVArray_Typed<bool> selection = component.attribute_get_for_read<bool>( + VArray<bool> selection = component.attribute_get_for_read<bool>( selection_name, selection_domain, false); /* Check if there is anything to delete. */ diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc index 8f2bf05d2b4..8f2bf05d2b4 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_edge_split.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_material_assign.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc index 333a17aa4e9..58374679a95 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_material_assign.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc @@ -72,7 +72,7 @@ static void geo_node_legacy_material_assign_exec(GeoNodeExecParams params) MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>(); Mesh *mesh = mesh_component.get_for_write(); if (mesh != nullptr) { - GVArray_Typed<bool> face_mask = mesh_component.attribute_get_for_read<bool>( + VArray<bool> face_mask = mesh_component.attribute_get_for_read<bool>( mask_name, ATTR_DOMAIN_FACE, true); assign_material_to_faces(*mesh, face_mask, material); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc index 9167096fd3d..321de24a3dc 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_mesh_to_curve.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc @@ -44,7 +44,7 @@ static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params) params.error_message_add(NodeWarningType::Error, TIP_("No attribute with name \"") + selection_name + "\""); } - GVArray_Typed<bool> selection = component.attribute_get_for_read<bool>( + VArray<bool> selection = component.attribute_get_for_read<bool>( selection_name, ATTR_DOMAIN_EDGE, true); Vector<int64_t> selected_edge_indices; diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc index 210757f986d..4e13a490d89 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_distribute.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc @@ -61,11 +61,12 @@ static void geo_node_point_distribute_layout(uiLayout *layout, uiItemR(layout, ptr, "distribute_method", 0, "", ICON_NONE); } -static void node_point_distribute_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_point_distribute_update(bNodeTree *ntree, bNode *node) { bNodeSocket *sock_min_dist = (bNodeSocket *)BLI_findlink(&node->inputs, 1); - nodeSetSocketAvailability(sock_min_dist, ELEM(node->custom1, GEO_NODE_POINT_DISTRIBUTE_POISSON)); + nodeSetSocketAvailability( + ntree, sock_min_dist, ELEM(node->custom1, GEO_NODE_POINT_DISTRIBUTE_POISSON)); } /** @@ -106,9 +107,9 @@ static void sample_mesh_surface(const Mesh &mesh, float looptri_density_factor = 1.0f; if (density_factors != nullptr) { - const float v0_density_factor = std::max(0.0f, density_factors->get(v0_loop)); - const float v1_density_factor = std::max(0.0f, density_factors->get(v1_loop)); - const float v2_density_factor = std::max(0.0f, density_factors->get(v2_loop)); + const float v0_density_factor = std::max(0.0f, (*density_factors)[v0_loop]); + const float v1_density_factor = std::max(0.0f, (*density_factors)[v1_loop]); + const float v2_density_factor = std::max(0.0f, (*density_factors)[v2_loop]); looptri_density_factor = (v0_density_factor + v1_density_factor + v2_density_factor) / 3.0f; } const float area = area_tri_v3(v0_pos, v1_pos, v2_pos); @@ -315,7 +316,7 @@ BLI_NOINLINE static void interpolate_existing_attributes( } const AttributeDomain source_domain = attribute_info->domain; - GVArrayPtr source_attribute = source_component.attribute_get_for_read( + GVArray source_attribute = source_component.attribute_get_for_read( attribute_id, source_domain, output_data_type, nullptr); if (!source_attribute) { i_instance += set_group.transforms.size(); @@ -329,7 +330,7 @@ BLI_NOINLINE static void interpolate_existing_attributes( GMutableSpan instance_span = out_span.slice(offset, bary_coords.size()); interpolate_attribute( - mesh, bary_coords, looptri_indices, source_domain, *source_attribute, instance_span); + mesh, bary_coords, looptri_indices, source_domain, source_attribute, instance_span); i_instance++; } @@ -337,7 +338,7 @@ BLI_NOINLINE static void interpolate_existing_attributes( attribute_math::convert_to_static_type(output_data_type, [&](auto dummy) { using T = decltype(dummy); - GVArray_Span<T> source_span{*source_attribute}; + VArray_Span source_span{source_attribute.typed<T>()}; }); } @@ -445,7 +446,7 @@ static void distribute_points_random(Span<GeometryInstanceGroup> set_groups, for (const GeometryInstanceGroup &set_group : set_groups) { const GeometrySet &set = set_group.geometry_set; const MeshComponent &component = *set.get_component_for_read<MeshComponent>(); - GVArray_Typed<float> density_factors = component.attribute_get_for_read<float>( + VArray<float> density_factors = component.attribute_get_for_read<float>( density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f); const Mesh &mesh = *component.get_for_read(); for (const float4x4 &transform : set_group.transforms) { @@ -455,7 +456,7 @@ static void distribute_points_random(Span<GeometryInstanceGroup> set_groups, sample_mesh_surface(mesh, transform, density, - &*density_factors, + &density_factors, seed, positions, bary_coords, @@ -514,7 +515,7 @@ static void distribute_points_poisson_disk(Span<GeometryInstanceGroup> set_group const GeometrySet &set = set_group.geometry_set; const MeshComponent &component = *set.get_component_for_read<MeshComponent>(); const Mesh &mesh = *component.get_for_read(); - const GVArray_Typed<float> density_factors = component.attribute_get_for_read<float>( + const VArray<float> density_factors = component.attribute_get_for_read<float>( density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f); for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) { diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc index ffb2a0dd7ac..713971941ea 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc @@ -53,7 +53,7 @@ static void geo_node_point_instance_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_point_instance_update(bNodeTree *UNUSED(tree), bNode *node) +static void geo_node_point_instance_update(bNodeTree *ntree, bNode *node) { bNodeSocket *object_socket = (bNodeSocket *)BLI_findlink(&node->inputs, 1); bNodeSocket *collection_socket = object_socket->next; @@ -65,12 +65,15 @@ static void geo_node_point_instance_update(bNodeTree *UNUSED(tree), bNode *node) const bool use_whole_collection = (node_storage->flag & GEO_NODE_POINT_INSTANCE_WHOLE_COLLECTION) != 0; - nodeSetSocketAvailability(object_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_OBJECT); - nodeSetSocketAvailability(collection_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION); - nodeSetSocketAvailability(instance_geometry_socket, - type == GEO_NODE_POINT_INSTANCE_TYPE_GEOMETRY); + nodeSetSocketAvailability(ntree, object_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_OBJECT); nodeSetSocketAvailability( - seed_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION && !use_whole_collection); + ntree, collection_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION); + nodeSetSocketAvailability( + ntree, instance_geometry_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_GEOMETRY); + nodeSetSocketAvailability(ntree, + seed_socket, + type == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION && + !use_whole_collection); } static Vector<InstanceReference> get_instance_references__object(GeoNodeExecParams ¶ms) @@ -171,13 +174,12 @@ static void add_instances_from_component(InstancesComponent &instances, const int domain_size = src_geometry.attribute_domain_size(domain); - GVArray_Typed<float3> positions = src_geometry.attribute_get_for_read<float3>( + VArray<float3> positions = src_geometry.attribute_get_for_read<float3>( "position", domain, {0, 0, 0}); - GVArray_Typed<float3> rotations = src_geometry.attribute_get_for_read<float3>( + VArray<float3> rotations = src_geometry.attribute_get_for_read<float3>( "rotation", domain, {0, 0, 0}); - GVArray_Typed<float3> scales = src_geometry.attribute_get_for_read<float3>( - "scale", domain, {1, 1, 1}); - GVArray_Typed<int> id_attribute = src_geometry.attribute_get_for_read<int>("id", domain, -1); + VArray<float3> scales = src_geometry.attribute_get_for_read<float3>("scale", domain, {1, 1, 1}); + VArray<int> id_attribute = src_geometry.attribute_get_for_read<int>("id", domain, -1); /* The initial size of the component might be non-zero if there are two component types. */ const int start_len = instances.instances_amount(); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_rotate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc index 54d36dab98d..ab1d68bfe4f 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_rotate.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc @@ -71,20 +71,23 @@ static void geo_node_point_rotate_init(bNodeTree *UNUSED(ntree), bNode *node) node->storage = node_storage; } -static void geo_node_point_rotate_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_point_rotate_update(bNodeTree *ntree, bNode *node) { NodeGeometryRotatePoints *node_storage = (NodeGeometryRotatePoints *)node->storage; update_attribute_input_socket_availabilities( + *ntree, *node, "Axis", (GeometryNodeAttributeInputMode)node_storage->input_type_axis, node_storage->type == GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE); update_attribute_input_socket_availabilities( + *ntree, *node, "Angle", (GeometryNodeAttributeInputMode)node_storage->input_type_angle, node_storage->type == GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE); update_attribute_input_socket_availabilities( + *ntree, *node, "Rotation", (GeometryNodeAttributeInputMode)node_storage->input_type_rotation, @@ -169,9 +172,9 @@ static void point_rotate_on_component(GeometryComponent &component, const int domain_size = rotations.size(); if (storage.type == GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE) { - GVArray_Typed<float3> axis = params.get_input_attribute<float3>( + VArray<float3> axis = params.get_input_attribute<float3>( "Axis", component, ATTR_DOMAIN_POINT, {0, 0, 1}); - GVArray_Typed<float> angles = params.get_input_attribute<float>( + VArray<float> angles = params.get_input_attribute<float>( "Angle", component, ATTR_DOMAIN_POINT, 0); if (storage.space == GEO_NODE_POINT_ROTATE_SPACE_OBJECT) { @@ -182,7 +185,7 @@ static void point_rotate_on_component(GeometryComponent &component, } } else { - GVArray_Typed<float3> eulers = params.get_input_attribute<float3>( + VArray<float3> eulers = params.get_input_attribute<float3>( "Rotation", component, ATTR_DOMAIN_POINT, {0, 0, 0}); if (storage.space == GEO_NODE_POINT_ROTATE_SPACE_OBJECT) { diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_scale.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc index 934442ee8a3..8d6345ce6b1 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_scale.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc @@ -50,12 +50,12 @@ static void geo_node_point_scale_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_point_scale_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_point_scale_update(bNodeTree *ntree, bNode *node) { NodeGeometryPointScale &node_storage = *(NodeGeometryPointScale *)node->storage; update_attribute_input_socket_availabilities( - *node, "Factor", (GeometryNodeAttributeInputMode)node_storage.input_type); + *ntree, *node, "Factor", (GeometryNodeAttributeInputMode)node_storage.input_type); } static void execute_on_component(GeoNodeExecParams params, GeometryComponent &component) @@ -78,7 +78,7 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co const CustomDataType data_type = (input_type == GEO_NODE_ATTRIBUTE_INPUT_FLOAT) ? CD_PROP_FLOAT : CD_PROP_FLOAT3; - GVArrayPtr attribute = params.get_input_attribute( + GVArray attribute = params.get_input_attribute( "Factor", component, ATTR_DOMAIN_POINT, data_type, nullptr); if (!attribute) { return; @@ -86,13 +86,13 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co MutableSpan<float3> scale_span = scale_attribute.as_span(); if (data_type == CD_PROP_FLOAT) { - GVArray_Typed<float> factors{*attribute}; + VArray<float> factors = attribute.typed<float>(); for (const int i : scale_span.index_range()) { scale_span[i] = scale_span[i] * factors[i]; } } else if (data_type == CD_PROP_FLOAT3) { - GVArray_Typed<float3> factors{*attribute}; + VArray<float3> factors = attribute.typed<float3>(); for (const int i : scale_span.index_range()) { scale_span[i] = scale_span[i] * factors[i]; } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_separate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc index accdaf78439..3539fe2de64 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_separate.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc @@ -55,7 +55,7 @@ void copy_point_attributes_based_on_mask(const GeometryComponent &in_component, { for (const AttributeIDRef &attribute_id : in_component.attribute_ids()) { ReadAttributeLookup attribute = in_component.attribute_try_get_for_read(attribute_id); - const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray->type()); + const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); /* Only copy point attributes. Theoretically this could interpolate attributes on other * domains to the point domain, but that would conflict with attributes that are built-in @@ -69,7 +69,7 @@ void copy_point_attributes_based_on_mask(const GeometryComponent &in_component, attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); - GVArray_Span<T> span{*attribute.varray}; + VArray_Span span{attribute.varray.typed<T>()}; MutableSpan<T> out_span = result_attribute.as_span<T>(); copy_data_based_on_mask(span, masks, invert, out_span); }); @@ -103,7 +103,7 @@ static void separate_points_from_component(const GeometryComponent &in_component return; } - const GVArray_Typed<bool> mask_attribute = in_component.attribute_get_for_read<bool>( + const VArray<bool> mask_attribute = in_component.attribute_get_for_read<bool>( mask_name, ATTR_DOMAIN_POINT, false); VArray_Span<bool> masks{mask_attribute}; diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_translate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc index 34f7641995f..3b2959beb86 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_translate.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc @@ -43,10 +43,10 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co if (!position_attribute) { return; } - GVArray_Typed<float3> attribute = params.get_input_attribute<float3>( + VArray<float3> attribute = params.get_input_attribute<float3>( "Translation", component, ATTR_DOMAIN_POINT, {0, 0, 0}); - for (const int i : IndexRange(attribute.size())) { + for (const int i : attribute.index_range()) { position_attribute->set(i, position_attribute->get(i) + attribute[i]); } @@ -81,12 +81,12 @@ static void geo_node_point_translate_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_point_translate_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_point_translate_update(bNodeTree *ntree, bNode *node) { NodeGeometryPointTranslate &node_storage = *(NodeGeometryPointTranslate *)node->storage; update_attribute_input_socket_availabilities( - *node, "Translation", (GeometryNodeAttributeInputMode)node_storage.input_type); + *ntree, *node, "Translation", (GeometryNodeAttributeInputMode)node_storage.input_type); } } // namespace blender::nodes diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc index cf7f466c2a6..d465a9ab1a8 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_points_to_volume.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc @@ -65,19 +65,22 @@ static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node STRNCPY(radius_attribute_socket_value->value, "radius"); } -static void geo_node_points_to_volume_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_points_to_volume_update(bNodeTree *ntree, bNode *node) { NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)node->storage; bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size"); bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount"); - nodeSetSocketAvailability(voxel_amount_socket, + nodeSetSocketAvailability(ntree, + voxel_amount_socket, data->resolution_mode == GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT); - nodeSetSocketAvailability( - voxel_size_socket, data->resolution_mode == GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE); + nodeSetSocketAvailability(ntree, + voxel_size_socket, + data->resolution_mode == + GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE); update_attribute_input_socket_availabilities( - *node, "Radius", (GeometryNodeAttributeInputMode)data->input_type_radius); + *ntree, *node, "Radius", (GeometryNodeAttributeInputMode)data->input_type_radius); } #ifdef WITH_OPENVDB @@ -172,12 +175,12 @@ static void gather_point_data_from_component(const GeoNodeExecParams ¶ms, Vector<float3> &r_positions, Vector<float> &r_radii) { - GVArray_Typed<float3> positions = component.attribute_get_for_read<float3>( + VArray<float3> positions = component.attribute_get_for_read<float3>( "position", ATTR_DOMAIN_POINT, {0, 0, 0}); - GVArray_Typed<float> radii = params.get_input_attribute<float>( + VArray<float> radii = params.get_input_attribute<float>( "Radius", component, ATTR_DOMAIN_POINT, 0.0f); - for (const int i : IndexRange(positions.size())) { + for (const int i : positions.index_range()) { r_positions.append(positions[i]); r_radii.append(radii[i]); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc index e6a81fc9627..5aa683ca232 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_raycast.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc @@ -65,15 +65,19 @@ static void geo_node_raycast_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_raycast_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_raycast_update(bNodeTree *ntree, bNode *node) { NodeGeometryRaycast *node_storage = (NodeGeometryRaycast *)node->storage; update_attribute_input_socket_availabilities( + *ntree, *node, "Ray Direction", (GeometryNodeAttributeInputMode)node_storage->input_type_ray_direction); update_attribute_input_socket_availabilities( - *node, "Ray Length", (GeometryNodeAttributeInputMode)node_storage->input_type_ray_length); + *ntree, + *node, + "Ray Length", + (GeometryNodeAttributeInputMode)node_storage->input_type_ray_length); } static void raycast_to_mesh(const Mesh &mesh, @@ -197,11 +201,11 @@ static void raycast_from_points(const GeoNodeExecParams ¶ms, (GeometryNodeRaycastMapMode)storage.mapping); const AttributeDomain result_domain = ATTR_DOMAIN_POINT; - GVArray_Typed<float3> ray_origins = dst_component.attribute_get_for_read<float3>( + VArray<float3> ray_origins = dst_component.attribute_get_for_read<float3>( "position", result_domain, {0, 0, 0}); - GVArray_Typed<float3> ray_directions = params.get_input_attribute<float3>( + VArray<float3> ray_directions = params.get_input_attribute<float3>( "Ray Direction", dst_component, result_domain, {0, 0, 0}); - GVArray_Typed<float> ray_lengths = params.get_input_attribute<float>( + VArray<float> ray_lengths = params.get_input_attribute<float>( "Ray Length", dst_component, result_domain, 0); OutputAttribute_Typed<bool> hit_attribute = @@ -218,10 +222,10 @@ static void raycast_from_points(const GeoNodeExecParams ¶ms, Array<int> hit_indices; Array<float3> hit_positions_internal; if (!hit_attribute_names.is_empty()) { - hit_indices.reinitialize(ray_origins->size()); + hit_indices.reinitialize(ray_origins.size()); if (!hit_position_attribute) { - hit_positions_internal.reinitialize(ray_origins->size()); + hit_positions_internal.reinitialize(ray_origins.size()); } } const MutableSpan<bool> is_hit = hit_attribute ? hit_attribute.as_span() : MutableSpan<bool>(); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_select_by_material.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc index a8d6f33a5fd..a8d6f33a5fd 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_select_by_material.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc index 295cd05fd01..295cd05fd01 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_subdivision_surface.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc index 39af5bf1fd2..6a52b943967 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_volume_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc @@ -68,15 +68,17 @@ static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node) node->storage = data; } -static void geo_node_volume_to_mesh_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_volume_to_mesh_update(bNodeTree *ntree, bNode *node) { NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)node->storage; bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size"); bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount"); - nodeSetSocketAvailability(voxel_amount_socket, + nodeSetSocketAvailability(ntree, + voxel_amount_socket, data->resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT); - nodeSetSocketAvailability(voxel_size_socket, + nodeSetSocketAvailability(ntree, + voxel_size_socket, data->resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc index 5cc8f1476f8..1cb26646d5a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc @@ -60,7 +60,7 @@ static void geo_node_attribute_capture_init(bNodeTree *UNUSED(tree), bNode *node node->storage = data; } -static void geo_node_attribute_capture_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_attribute_capture_update(bNodeTree *ntree, bNode *node) { const NodeGeometryAttributeCapture &storage = *(const NodeGeometryAttributeCapture *) node->storage; @@ -73,11 +73,11 @@ static void geo_node_attribute_capture_update(bNodeTree *UNUSED(ntree), bNode *n bNodeSocket *socket_value_boolean = socket_value_color4f->next; bNodeSocket *socket_value_int32 = socket_value_boolean->next; - nodeSetSocketAvailability(socket_value_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_value_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_value_color4f, data_type == CD_PROP_COLOR); - nodeSetSocketAvailability(socket_value_boolean, data_type == CD_PROP_BOOL); - nodeSetSocketAvailability(socket_value_int32, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, socket_value_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_value_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_value_color4f, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, socket_value_boolean, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, socket_value_int32, data_type == CD_PROP_INT32); bNodeSocket *out_socket_value_geometry = (bNodeSocket *)node->outputs.first; bNodeSocket *out_socket_value_vector = out_socket_value_geometry->next; @@ -86,11 +86,11 @@ static void geo_node_attribute_capture_update(bNodeTree *UNUSED(ntree), bNode *n bNodeSocket *out_socket_value_boolean = out_socket_value_color4f->next; bNodeSocket *out_socket_value_int32 = out_socket_value_boolean->next; - nodeSetSocketAvailability(out_socket_value_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(out_socket_value_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(out_socket_value_color4f, data_type == CD_PROP_COLOR); - nodeSetSocketAvailability(out_socket_value_boolean, data_type == CD_PROP_BOOL); - nodeSetSocketAvailability(out_socket_value_int32, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, out_socket_value_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, out_socket_value_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, out_socket_value_color4f, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, out_socket_value_boolean, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, out_socket_value_int32, data_type == CD_PROP_INT32); } static void try_capture_field_on_geometry(GeometryComponent &component, @@ -147,16 +147,27 @@ static void geo_node_attribute_capture_exec(GeoNodeExecParams params) WeakAnonymousAttributeID anonymous_id{"Attribute"}; const CPPType &type = field.cpp_type(); - static const Array<GeometryComponentType> types = { - GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}; - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { - for (const GeometryComponentType type : types) { - if (geometry_set.has(type)) { - GeometryComponent &component = geometry_set.get_component_for_write(type); - try_capture_field_on_geometry(component, anonymous_id.get(), domain, field); - } + /* Run on the instances component separately to only affect the top level of instances. */ + if (domain == ATTR_DOMAIN_INSTANCE) { + if (geometry_set.has_instances()) { + GeometryComponent &component = geometry_set.get_component_for_write( + GEO_COMPONENT_TYPE_INSTANCES); + try_capture_field_on_geometry(component, anonymous_id.get(), domain, field); } - }); + } + else { + static const Array<GeometryComponentType> types = { + GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}; + + geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + for (const GeometryComponentType type : types) { + if (geometry_set.has(type)) { + GeometryComponent &component = geometry_set.get_component_for_write(type); + try_capture_field_on_geometry(component, anonymous_id.get(), domain, field); + } + } + }); + } GField output_field{std::make_shared<bke::AnonymousAttributeFieldInput>( std::move(anonymous_id), type, params.attribute_producer_name())}; diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc index 155bd8c8c28..d9513332078 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc @@ -65,7 +65,7 @@ static void geo_node_attribute_statistic_init(bNodeTree *UNUSED(tree), bNode *no node->custom2 = ATTR_DOMAIN_POINT; } -static void geo_node_attribute_statistic_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_attribute_statistic_update(bNodeTree *ntree, bNode *node) { bNodeSocket *socket_geo = (bNodeSocket *)node->inputs.first; bNodeSocket *socket_float_attr = socket_geo->next; @@ -91,25 +91,25 @@ static void geo_node_attribute_statistic_update(bNodeTree *UNUSED(ntree), bNode const CustomDataType data_type = static_cast<CustomDataType>(node->custom1); - nodeSetSocketAvailability(socket_float_attr, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_float_mean, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_float_median, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_float_sum, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_float_min, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_float_max, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_float_range, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_float_std, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_float_variance, data_type == CD_PROP_FLOAT); - - nodeSetSocketAvailability(socket_float3_attr, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_vector_mean, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_vector_median, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_vector_sum, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_vector_min, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_vector_max, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_vector_range, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_vector_std, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_vector_variance, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_float_attr, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_float_mean, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_float_median, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_float_sum, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_float_min, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_float_max, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_float_range, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_float_std, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_float_variance, data_type == CD_PROP_FLOAT); + + nodeSetSocketAvailability(ntree, socket_float3_attr, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_vector_mean, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_vector_median, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_vector_sum, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_vector_min, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_vector_max, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_vector_range, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_vector_std, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_vector_variance, data_type == CD_PROP_FLOAT3); } template<typename T> static T compute_sum(const Span<T> data) diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc index 516f07b7ad3..dba051fe13d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc @@ -41,7 +41,7 @@ static void geo_node_boolean_layout(uiLayout *layout, bContext *UNUSED(C), Point uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); } -static void geo_node_boolean_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_boolean_update(bNodeTree *ntree, bNode *node) { GeometryNodeBooleanOperation operation = (GeometryNodeBooleanOperation)node->custom1; @@ -51,13 +51,13 @@ static void geo_node_boolean_update(bNodeTree *UNUSED(ntree), bNode *node) switch (operation) { case GEO_NODE_BOOLEAN_INTERSECT: case GEO_NODE_BOOLEAN_UNION: - nodeSetSocketAvailability(geometry_1_socket, false); - nodeSetSocketAvailability(geometry_2_socket, true); + nodeSetSocketAvailability(ntree, geometry_1_socket, false); + nodeSetSocketAvailability(ntree, geometry_2_socket, true); node_sock_label(geometry_2_socket, N_("Mesh")); break; case GEO_NODE_BOOLEAN_DIFFERENCE: - nodeSetSocketAvailability(geometry_1_socket, true); - nodeSetSocketAvailability(geometry_2_socket, true); + nodeSetSocketAvailability(ntree, geometry_1_socket, true); + nodeSetSocketAvailability(ntree, geometry_2_socket, true); node_sock_label(geometry_2_socket, N_("Mesh 2")); break; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc index f068e621596..503711fedfe 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc @@ -38,7 +38,7 @@ static void geo_node_collection_info_declare(NodeDeclarationBuilder &b) b.add_input<decl::Bool>(N_("Reset Children")) .description( N_("Reset the transforms of every child instance in the output. Only used when Separate " - "Children is enabled")); + "Children is enabled")); b.add_output<decl::Geometry>(N_("Geometry")); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_common.cc b/source/blender/nodes/geometry/nodes/node_geo_common.cc index e2bb7e9f939..9ebbdd349de 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_common.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_common.cc @@ -31,7 +31,6 @@ void register_node_type_geo_group(void) ntype.poll = geo_node_poll_default; ntype.poll_instance = node_group_poll_instance; ntype.insert_link = node_insert_link_default; - ntype.update_internal_links = node_update_internal_links_default; ntype.rna_ext.srna = RNA_struct_find("GeometryNodeGroup"); BLI_assert(ntype.rna_ext.srna != nullptr); RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype); @@ -53,7 +52,4 @@ void register_node_type_geo_custom_group(bNodeType *ntype) if (ntype->insert_link == nullptr) { ntype->insert_link = node_insert_link_default; } - if (ntype->update_internal_links == nullptr) { - ntype->update_internal_links = node_update_internal_links_default; - } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc index 3cf682e161c..221fb421ab4 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc @@ -169,10 +169,10 @@ static Mesh *compute_hull(const GeometrySet &geometry_set) span_count++; const PointCloudComponent *component = geometry_set.get_component_for_read<PointCloudComponent>(); - GVArray_Typed<float3> varray = component->attribute_get_for_read<float3>( + VArray<float3> varray = component->attribute_get_for_read<float3>( "position", ATTR_DOMAIN_POINT, {0, 0, 0}); - total_size += varray->size(); - positions_span = varray->get_internal_span(); + total_size += varray.size(); + positions_span = varray.get_internal_span(); } if (geometry_set.has_curve()) { @@ -200,18 +200,18 @@ static Mesh *compute_hull(const GeometrySet &geometry_set) if (geometry_set.has_mesh()) { const MeshComponent *component = geometry_set.get_component_for_read<MeshComponent>(); - GVArray_Typed<float3> varray = component->attribute_get_for_read<float3>( + VArray<float3> varray = component->attribute_get_for_read<float3>( "position", ATTR_DOMAIN_POINT, {0, 0, 0}); - varray->materialize(positions.as_mutable_span().slice(offset, varray.size())); + varray.materialize(positions.as_mutable_span().slice(offset, varray.size())); offset += varray.size(); } if (geometry_set.has_pointcloud()) { const PointCloudComponent *component = geometry_set.get_component_for_read<PointCloudComponent>(); - GVArray_Typed<float3> varray = component->attribute_get_for_read<float3>( + VArray<float3> varray = component->attribute_get_for_read<float3>( "position", ATTR_DOMAIN_POINT, {0, 0, 0}); - varray->materialize(positions.as_mutable_span().slice(offset, varray.size())); + varray.materialize(positions.as_mutable_span().slice(offset, varray.size())); offset += varray.size(); } @@ -235,16 +235,16 @@ static void read_positions(const GeometryComponent &component, Span<float4x4> transforms, Vector<float3> *r_coords) { - GVArray_Typed<float3> positions = component.attribute_get_for_read<float3>( + VArray<float3> positions = component.attribute_get_for_read<float3>( "position", ATTR_DOMAIN_POINT, {0, 0, 0}); /* NOTE: could use convex hull operation here to * cut out some vertices, before accumulating, * but can also be done by the user beforehand. */ - r_coords->reserve(r_coords->size() + positions.size() * transforms.size()); + r_coords->reserve(r_coords->size() + positions->size() * transforms.size()); for (const float4x4 &transform : transforms) { - for (const int i : positions.index_range()) { + for (const int i : positions->index_range()) { const float3 position = positions[i]; const float3 transformed_position = transform * position; r_coords->append(transformed_position); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc index 42d88cdb1e7..c41b76412e9 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc @@ -64,9 +64,9 @@ class EndpointFieldInput final : public fn::FieldInput { category_ = Category::Generated; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask UNUSED(mask), - ResourceScope &scope) const final + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask UNUSED(mask), + ResourceScope &UNUSED(scope)) const final { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { @@ -111,9 +111,9 @@ class EndpointFieldInput final : public fn::FieldInput { } current_point += spline->size(); } - return &scope.construct<fn::GVArray_For_ArrayContainer<Array<bool>>>(std::move(selection)); + return VArray<bool>::ForContainer(std::move(selection)); } - return nullptr; + return {}; }; uint64_t hash() const override diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc index 27d7d22b106..a320f35c539 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc @@ -59,10 +59,10 @@ struct FilletParam { GeometryNodeCurveFilletMode mode; /* Number of points to be added. */ - const VArray<int> *counts; + VArray<int> counts; /* Radii for fillet arc at all vertices. */ - const VArray<float> *radii; + VArray<float> radii; /* Whether or not fillets are allowed to overlap. */ bool limit_radius; @@ -76,14 +76,14 @@ struct FilletData { Array<int> counts; }; -static void geo_node_curve_fillet_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_curve_fillet_update(bNodeTree *ntree, bNode *node) { NodeGeometryCurveFillet &node_storage = *(NodeGeometryCurveFillet *)node->storage; const GeometryNodeCurveFilletMode mode = (GeometryNodeCurveFilletMode)node_storage.mode; bNodeSocket *poly_socket = ((bNodeSocket *)node->inputs.first)->next; - nodeSetSocketAvailability(poly_socket, mode == GEO_NODE_CURVE_FILLET_POLY); + nodeSetSocketAvailability(ntree, poly_socket, mode == GEO_NODE_CURVE_FILLET_POLY); } /* Function to get the center of a fillet. */ @@ -160,7 +160,7 @@ static Array<int> calculate_counts(const FilletParam &fillet_param, Array<int> counts(size, 1); if (fillet_param.mode == GEO_NODE_CURVE_FILLET_POLY) { for (const int i : IndexRange(size)) { - counts[i] = (*fillet_param.counts)[spline_offset + i]; + counts[i] = fillet_param.counts[spline_offset + i]; } } if (!cyclic) { @@ -178,12 +178,12 @@ static Array<float> calculate_radii(const FilletParam &fillet_param, Array<float> radii(size, 0.0f); if (fillet_param.limit_radius) { for (const int i : IndexRange(size)) { - radii[i] = std::max((*fillet_param.radii)[spline_offset + i], 0.0f); + radii[i] = std::max(fillet_param.radii[spline_offset + i], 0.0f); } } else { for (const int i : IndexRange(size)) { - radii[i] = (*fillet_param.radii)[spline_offset + i]; + radii[i] = fillet_param.radii[spline_offset + i]; } } @@ -590,13 +590,13 @@ static void calculate_curve_fillet(GeometrySet &geometry_set, field_evaluator.evaluate(); - fillet_param.radii = &field_evaluator.get_evaluated<float>(0); - if (fillet_param.radii->is_single() && fillet_param.radii->get_internal_single() < 0.0f) { + fillet_param.radii = field_evaluator.get_evaluated<float>(0); + if (fillet_param.radii.is_single() && fillet_param.radii.get_internal_single() < 0.0f) { return; } if (mode == GEO_NODE_CURVE_FILLET_POLY) { - fillet_param.counts = &field_evaluator.get_evaluated<int>(1); + fillet_param.counts = field_evaluator.get_evaluated<int>(1); } fillet_param.limit_radius = limit_radius; diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc index 165f5da5f71..5fb17270301 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc @@ -96,9 +96,9 @@ class HandleTypeFieldInput final : public fn::FieldInput { category_ = Category::Generated; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &scope) const final + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &UNUSED(scope)) const final { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { @@ -106,22 +106,22 @@ class HandleTypeFieldInput final : public fn::FieldInput { const GeometryComponent &component = geometry_context->geometry_component(); const AttributeDomain domain = geometry_context->domain(); if (component.type() != GEO_COMPONENT_TYPE_CURVE) { - return nullptr; + return {}; } const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); const CurveEval *curve = curve_component.get_for_read(); if (curve == nullptr) { - return nullptr; + return {}; } if (domain == ATTR_DOMAIN_POINT) { Array<bool> selection(mask.min_array_size()); select_by_handle_type(*curve, type_, mode_, selection); - return &scope.construct<fn::GVArray_For_ArrayContainer<Array<bool>>>(std::move(selection)); + return VArray<bool>::ForContainer(std::move(selection)); } } - return nullptr; + return {}; }; uint64_t hash() const override @@ -158,11 +158,8 @@ void register_node_type_geo_curve_handle_type_selection() { static bNodeType ntype; - geo_node_type_base(&ntype, - GEO_NODE_CURVE_HANDLE_TYPE_SELECTION, - "Handle Type Selection", - NODE_CLASS_GEOMETRY, - 0); + geo_node_type_base( + &ntype, GEO_NODE_CURVE_HANDLE_TYPE_SELECTION, "Handle Type Selection", NODE_CLASS_INPUT, 0); ntype.declare = blender::nodes::geo_node_curve_handle_type_selection_declare; ntype.geometry_node_execute = blender::nodes::geo_node_curve_handle_type_selection_exec; node_type_init(&ntype, blender::nodes::geo_node_curve_handle_type_selection_init); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc index ee7a78ccf71..63518b38090 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc @@ -129,10 +129,9 @@ static Array<float> curve_length_point_domain(const CurveEval &curve) return lengths; } -static const GVArray *construct_curve_parameter_gvarray(const CurveEval &curve, - const IndexMask mask, - const AttributeDomain domain, - ResourceScope &scope) +static VArray<float> construct_curve_parameter_varray(const CurveEval &curve, + const IndexMask mask, + const AttributeDomain domain) { if (domain == ATTR_DOMAIN_POINT) { Span<SplinePtr> splines = curve.splines(); @@ -147,7 +146,7 @@ static const GVArray *construct_curve_parameter_gvarray(const CurveEval &curve, values[offsets[i_spline] + i] *= spline_length_inv; } } - return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float>>>(std::move(values)); + return VArray<float>::ForContainer(std::move(values)); } if (domain == ATTR_DOMAIN_CURVE) { @@ -156,32 +155,31 @@ static const GVArray *construct_curve_parameter_gvarray(const CurveEval &curve, for (const int i : mask) { values[i] *= total_length_inv; } - return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float>>>(std::move(values)); + return VArray<float>::ForContainer(std::move(values)); } - return nullptr; + return {}; } -static const GVArray *construct_curve_length_gvarray(const CurveEval &curve, - const IndexMask mask, - const AttributeDomain domain, - ResourceScope &scope) +static VArray<float> construct_curve_length_varray(const CurveEval &curve, + const IndexMask mask, + const AttributeDomain domain) { if (domain == ATTR_DOMAIN_POINT) { Array<float> lengths = curve_length_point_domain(curve); - return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float>>>(std::move(lengths)); + return VArray<float>::ForContainer(std::move(lengths)); } if (domain == ATTR_DOMAIN_CURVE) { if (curve.splines().size() == 1) { Array<float> lengths(1, 0.0f); - return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float>>>(std::move(lengths)); + return VArray<float>::ForContainer(std::move(lengths)); } Array<float> lengths = curve_length_spline_domain(curve, mask); - return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float>>>(std::move(lengths)); + return VArray<float>::ForContainer(std::move(lengths)); } - return nullptr; + return {}; } class CurveParameterFieldInput final : public fn::FieldInput { @@ -191,9 +189,9 @@ class CurveParameterFieldInput final : public fn::FieldInput { category_ = Category::Generated; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &scope) const final + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &UNUSED(scope)) const final { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { @@ -205,11 +203,11 @@ class CurveParameterFieldInput final : public fn::FieldInput { const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); const CurveEval *curve = curve_component.get_for_read(); if (curve) { - return construct_curve_parameter_gvarray(*curve, mask, domain, scope); + return construct_curve_parameter_varray(*curve, mask, domain); } } } - return nullptr; + return {}; } uint64_t hash() const override @@ -231,9 +229,9 @@ class CurveLengthFieldInput final : public fn::FieldInput { category_ = Category::Generated; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &scope) const final + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &UNUSED(scope)) const final { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { @@ -244,11 +242,11 @@ class CurveLengthFieldInput final : public fn::FieldInput { const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); const CurveEval *curve = curve_component.get_for_read(); if (curve) { - return construct_curve_length_gvarray(*curve, mask, domain, scope); + return construct_curve_length_varray(*curve, mask, domain); } } } - return nullptr; + return {}; } uint64_t hash() const override diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc index ffede480c75..5d8beb9c9d8 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc @@ -73,7 +73,7 @@ static void geo_node_curve_primitive_circle_init(bNodeTree *UNUSED(tree), bNode node->storage = data; } -static void geo_node_curve_primitive_circle_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_curve_primitive_circle_update(bNodeTree *ntree, bNode *node) { const NodeGeometryCurvePrimitiveCircle *node_storage = (NodeGeometryCurvePrimitiveCircle *) node->storage; @@ -87,11 +87,16 @@ static void geo_node_curve_primitive_circle_update(bNodeTree *UNUSED(ntree), bNo bNodeSocket *center_socket = ((bNodeSocket *)node->outputs.first)->next; - nodeSetSocketAvailability(start_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS); - nodeSetSocketAvailability(middle_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS); - nodeSetSocketAvailability(end_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS); - nodeSetSocketAvailability(center_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS); - nodeSetSocketAvailability(radius_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS); + nodeSetSocketAvailability( + ntree, start_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS); + nodeSetSocketAvailability( + ntree, middle_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS); + nodeSetSocketAvailability( + ntree, end_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS); + nodeSetSocketAvailability( + ntree, center_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS); + nodeSetSocketAvailability( + ntree, radius_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS); } static bool colinear_f3_f3_f3(const float3 p1, const float3 p2, const float3 p3) diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc index 37a5989d3f1..238fc77e1cc 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc @@ -59,7 +59,7 @@ static void geo_node_curve_primitive_line_init(bNodeTree *UNUSED(tree), bNode *n node->storage = data; } -static void geo_node_curve_primitive_line_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_curve_primitive_line_update(bNodeTree *ntree, bNode *node) { const NodeGeometryCurvePrimitiveLine *node_storage = (NodeGeometryCurvePrimitiveLine *) node->storage; @@ -70,10 +70,11 @@ static void geo_node_curve_primitive_line_update(bNodeTree *UNUSED(ntree), bNode bNodeSocket *direction_socket = p2_socket->next; bNodeSocket *length_socket = direction_socket->next; - nodeSetSocketAvailability(p2_socket, mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS); - nodeSetSocketAvailability(direction_socket, - mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION); - nodeSetSocketAvailability(length_socket, mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION); + nodeSetSocketAvailability(ntree, p2_socket, mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS); + nodeSetSocketAvailability( + ntree, direction_socket, mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION); + nodeSetSocketAvailability( + ntree, length_socket, mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION); } static std::unique_ptr<CurveEval> create_point_line_curve(const float3 start, const float3 end) diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc index e00a502bf32..114ae441d99 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc @@ -92,7 +92,7 @@ static void geo_node_curve_primitive_quadrilateral_init(bNodeTree *UNUSED(tree), node->storage = data; } -static void geo_node_curve_primitive_quadrilateral_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_curve_primitive_quadrilateral_update(bNodeTree *ntree, bNode *node) { NodeGeometryCurvePrimitiveQuad &node_storage = *(NodeGeometryCurvePrimitiveQuad *)node->storage; GeometryNodeCurvePrimitiveQuadMode mode = static_cast<GeometryNodeCurvePrimitiveQuadMode>( @@ -111,34 +111,34 @@ static void geo_node_curve_primitive_quadrilateral_update(bNodeTree *UNUSED(ntre bNodeSocket *p4 = p3->next; LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { - nodeSetSocketAvailability(sock, false); + nodeSetSocketAvailability(ntree, sock, false); } if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE) { - nodeSetSocketAvailability(width, true); - nodeSetSocketAvailability(height, true); + nodeSetSocketAvailability(ntree, width, true); + nodeSetSocketAvailability(ntree, height, true); } else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_PARALLELOGRAM) { - nodeSetSocketAvailability(width, true); - nodeSetSocketAvailability(height, true); - nodeSetSocketAvailability(offset, true); + nodeSetSocketAvailability(ntree, width, true); + nodeSetSocketAvailability(ntree, height, true); + nodeSetSocketAvailability(ntree, offset, true); } else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID) { - nodeSetSocketAvailability(bottom, true); - nodeSetSocketAvailability(top, true); - nodeSetSocketAvailability(offset, true); - nodeSetSocketAvailability(height, true); + nodeSetSocketAvailability(ntree, bottom, true); + nodeSetSocketAvailability(ntree, top, true); + nodeSetSocketAvailability(ntree, offset, true); + nodeSetSocketAvailability(ntree, height, true); } else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_KITE) { - nodeSetSocketAvailability(width, true); - nodeSetSocketAvailability(bottom_height, true); - nodeSetSocketAvailability(top_height, true); + nodeSetSocketAvailability(ntree, width, true); + nodeSetSocketAvailability(ntree, bottom_height, true); + nodeSetSocketAvailability(ntree, top_height, true); } else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_POINTS) { - nodeSetSocketAvailability(p1, true); - nodeSetSocketAvailability(p2, true); - nodeSetSocketAvailability(p3, true); - nodeSetSocketAvailability(p4, true); + nodeSetSocketAvailability(ntree, p1, true); + nodeSetSocketAvailability(ntree, p2, true); + nodeSetSocketAvailability(ntree, p3, true); + nodeSetSocketAvailability(ntree, p4, true); } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc index 2a872fd82cb..1384165e520 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc @@ -35,13 +35,11 @@ static void geo_node_curve_primitive_spiral_declare(NodeDeclarationBuilder &b) b.add_input<decl::Float>(N_("Start Radius")) .default_value(1.0f) .subtype(PROP_DISTANCE) - .description( - N_("Horizontal Distance from the Z axis at the start of the spiral")); + .description(N_("Horizontal Distance from the Z axis at the start of the spiral")); b.add_input<decl::Float>(N_("End Radius")) .default_value(2.0f) .subtype(PROP_DISTANCE) - .description( - N_("Horizontal Distance from the Z axis at the end of the spiral")); + .description(N_("Horizontal Distance from the Z axis at the end of the spiral")); b.add_input<decl::Float>(N_("Height")) .default_value(2.0f) .subtype(PROP_DISTANCE) diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc index 7f682b198b3..9004681c246 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc @@ -42,6 +42,9 @@ static void geo_node_curve_primitive_star_declare(NodeDeclarationBuilder &b) .subtype(PROP_ANGLE) .description(N_("The counterclockwise rotation of the inner set of points")); b.add_output<decl::Geometry>(N_("Curve")); + b.add_output<decl::Bool>(N_("Outer Points")) + .field_source() + .description(N_("An attribute field with a selection of the outer points")); } static std::unique_ptr<CurveEval> create_star_curve(const float inner_radius, @@ -66,9 +69,22 @@ static std::unique_ptr<CurveEval> create_star_curve(const float inner_radius, spline->attributes.reallocate(spline->size()); curve->add_spline(std::move(spline)); curve->attributes.reallocate(curve->splines().size()); + return curve; } +static void create_selection_output(CurveComponent &component, + StrongAnonymousAttributeID &r_attribute) +{ + OutputAttribute_Typed<bool> attribute = component.attribute_try_get_for_output_only<bool>( + r_attribute.get(), ATTR_DOMAIN_POINT); + MutableSpan<bool> selection = attribute.as_span(); + for (int i : selection.index_range()) { + selection[i] = i % 2 == 0; + } + attribute.save(); +} + static void geo_node_curve_primitive_star_exec(GeoNodeExecParams params) { std::unique_ptr<CurveEval> curve = create_star_curve( @@ -76,9 +92,17 @@ static void geo_node_curve_primitive_star_exec(GeoNodeExecParams params) std::max(params.extract_input<float>("Outer Radius"), 0.0f), params.extract_input<float>("Twist"), std::max(params.extract_input<int>("Points"), 3)); - params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); -} + GeometrySet output = GeometrySet::create_with_curve(curve.release()); + if (params.output_is_required("Outer Points")) { + StrongAnonymousAttributeID attribute_output("Outer Points"); + create_selection_output(output.get_component_for_write<CurveComponent>(), attribute_output); + params.set_output("Outer Points", + AnonymousAttributeFieldInput::Create<bool>( + std::move(attribute_output), params.attribute_producer_name())); + } + params.set_output("Curve", std::move(output)); +} } // namespace blender::nodes void register_node_type_geo_curve_primitive_star() diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc index fb2021c307b..f72978bae50 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc @@ -26,22 +26,18 @@ #include "node_geometry_util.hh" -using blender::fn::GVArray_For_GSpan; -using blender::fn::GVArray_For_Span; -using blender::fn::GVArray_Typed; - namespace blender::nodes { static void geo_node_curve_resample_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); + b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value(); b.add_input<decl::Int>(N_("Count")).default_value(10).min(1).max(100000).supports_field(); b.add_input<decl::Float>(N_("Length")) .default_value(0.1f) .min(0.001f) .supports_field() .subtype(PROP_DISTANCE); - b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field(); b.add_output<decl::Geometry>(N_("Curve")); } @@ -59,16 +55,16 @@ static void geo_node_curve_resample_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_curve_resample_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_curve_resample_update(bNodeTree *ntree, bNode *node) { NodeGeometryCurveResample &node_storage = *(NodeGeometryCurveResample *)node->storage; const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode; - bNodeSocket *count_socket = ((bNodeSocket *)node->inputs.first)->next; + bNodeSocket *count_socket = ((bNodeSocket *)node->inputs.first)->next->next; bNodeSocket *length_socket = count_socket->next; - nodeSetSocketAvailability(count_socket, mode == GEO_NODE_CURVE_RESAMPLE_COUNT); - nodeSetSocketAvailability(length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH); + nodeSetSocketAvailability(ntree, count_socket, mode == GEO_NODE_CURVE_RESAMPLE_COUNT); + nodeSetSocketAvailability(ntree, length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH); } struct SampleModeParam { @@ -124,7 +120,7 @@ static SplinePtr resample_spline(const Spline &src, const int count) std::optional<GMutableSpan> output_attribute = dst->attributes.get_for_write( attribute_id); if (output_attribute) { - src.sample_with_index_factors(*src.interpolate_to_evaluated(*input_attribute), + src.sample_with_index_factors(src.interpolate_to_evaluated(*input_attribute), uniform_samples, *output_attribute); return true; @@ -147,8 +143,8 @@ static SplinePtr resample_spline_evaluated(const Spline &src) dst->positions().copy_from(src.evaluated_positions()); dst->positions().copy_from(src.evaluated_positions()); - src.interpolate_to_evaluated(src.radii())->materialize(dst->radii()); - src.interpolate_to_evaluated(src.tilts())->materialize(dst->tilts()); + src.interpolate_to_evaluated(src.radii()).materialize(dst->radii()); + src.interpolate_to_evaluated(src.tilts()).materialize(dst->tilts()); src.attributes.foreach_attribute( [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { @@ -156,7 +152,7 @@ static SplinePtr resample_spline_evaluated(const Spline &src) if (dst->attributes.create(attribute_id, meta_data.data_type)) { std::optional<GMutableSpan> dst_attribute = dst->attributes.get_for_write(attribute_id); if (dst_attribute) { - src.interpolate_to_evaluated(*src_attribute)->materialize(dst_attribute->data()); + src.interpolate_to_evaluated(*src_attribute).materialize(dst_attribute->data()); return true; } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc index 31b38c0dce7..8f42aacab43 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc @@ -51,7 +51,7 @@ static void geo_node_curve_sample_type_init(bNodeTree *UNUSED(tree), bNode *node node->storage = data; } -static void geo_node_curve_sample_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_curve_sample_update(bNodeTree *ntree, bNode *node) { const NodeGeometryCurveSample &node_storage = *(NodeGeometryCurveSample *)node->storage; const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode; @@ -59,8 +59,8 @@ static void geo_node_curve_sample_update(bNodeTree *UNUSED(ntree), bNode *node) bNodeSocket *factor = ((bNodeSocket *)node->inputs.first)->next; bNodeSocket *length = factor->next; - nodeSetSocketAvailability(factor, mode == GEO_NODE_CURVE_SAMPLE_FACTOR); - nodeSetSocketAvailability(length, mode == GEO_NODE_CURVE_SAMPLE_LENGTH); + nodeSetSocketAvailability(ntree, factor, mode == GEO_NODE_CURVE_SAMPLE_FACTOR); + nodeSetSocketAvailability(ntree, length, mode == GEO_NODE_CURVE_SAMPLE_LENGTH); } template<typename T> static T sample_with_lookup(const Spline::LookupResult lookup, Span<T> data) diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc index b52de822c22..7c4c17e69e0 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc @@ -25,10 +25,6 @@ #include "node_geometry_util.hh" -using blender::fn::GVArray_For_GSpan; -using blender::fn::GVArray_For_Span; -using blender::fn::GVArray_Typed; - namespace blender::nodes { static void geo_node_curve_subdivide_declare(NodeDeclarationBuilder &b) diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc index 38d7fb99e87..b9f129a5f75 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc @@ -53,7 +53,7 @@ static void geo_node_curve_to_points_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_curve_to_points_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_curve_to_points_update(bNodeTree *ntree, bNode *node) { NodeGeometryCurveToPoints &node_storage = *(NodeGeometryCurveToPoints *)node->storage; const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode; @@ -61,8 +61,8 @@ static void geo_node_curve_to_points_update(bNodeTree *UNUSED(ntree), bNode *nod bNodeSocket *count_socket = ((bNodeSocket *)node->inputs.first)->next; bNodeSocket *length_socket = count_socket->next; - nodeSetSocketAvailability(count_socket, mode == GEO_NODE_CURVE_RESAMPLE_COUNT); - nodeSetSocketAvailability(length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH); + nodeSetSocketAvailability(ntree, count_socket, mode == GEO_NODE_CURVE_RESAMPLE_COUNT); + nodeSetSocketAvailability(ntree, length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH); } static Array<int> calculate_spline_point_offsets(GeoNodeExecParams ¶ms, @@ -113,7 +113,7 @@ static GMutableSpan ensure_point_attribute(PointCloudComponent &points, points.attribute_try_create(attribute_id, ATTR_DOMAIN_POINT, data_type, AttributeInitDefault()); WriteAttributeLookup attribute = points.attribute_try_get_for_write(attribute_id); BLI_assert(attribute); - return attribute.varray->get_internal_span(); + return attribute.varray.get_internal_span(); } template<typename T> @@ -194,7 +194,7 @@ static void copy_evaluated_point_attributes(const Span<SplinePtr> splines, const int size = offsets[i + 1] - offsets[i]; data.positions.slice(offset, size).copy_from(spline.evaluated_positions()); - spline.interpolate_to_evaluated(spline.radii())->materialize(data.radii.slice(offset, size)); + spline.interpolate_to_evaluated(spline.radii()).materialize(data.radii.slice(offset, size)); for (const Map<AttributeIDRef, GMutableSpan>::Item item : data.point_attributes.items()) { const AttributeIDRef attribute_id = item.key; @@ -203,7 +203,7 @@ static void copy_evaluated_point_attributes(const Span<SplinePtr> splines, BLI_assert(spline.attributes.get_for_read(attribute_id)); GSpan spline_span = *spline.attributes.get_for_read(attribute_id); - spline.interpolate_to_evaluated(spline_span)->materialize(dst.slice(offset, size).data()); + spline.interpolate_to_evaluated(spline_span).materialize(dst.slice(offset, size).data()); } if (!data.tangents.is_empty()) { @@ -233,7 +233,7 @@ static void copy_uniform_sample_point_attributes(const Span<SplinePtr> splines, spline.sample_with_index_factors<float3>( spline.evaluated_positions(), uniform_samples, data.positions.slice(offset, size)); - spline.sample_with_index_factors<float>(*spline.interpolate_to_evaluated(spline.radii()), + spline.sample_with_index_factors<float>(spline.interpolate_to_evaluated(spline.radii()), uniform_samples, data.radii.slice(offset, size)); @@ -244,7 +244,7 @@ static void copy_uniform_sample_point_attributes(const Span<SplinePtr> splines, BLI_assert(spline.attributes.get_for_read(attribute_id)); GSpan spline_span = *spline.attributes.get_for_read(attribute_id); - spline.sample_with_index_factors(*spline.interpolate_to_evaluated(spline_span), + spline.sample_with_index_factors(spline.interpolate_to_evaluated(spline_span), uniform_samples, dst.slice(offset, size)); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc index 4e1a2910c7c..b281876d314 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc @@ -62,7 +62,7 @@ static void geo_node_curve_trim_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_curve_trim_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_curve_trim_update(bNodeTree *ntree, bNode *node) { const NodeGeometryCurveTrim &node_storage = *(NodeGeometryCurveTrim *)node->storage; const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode; @@ -72,10 +72,10 @@ static void geo_node_curve_trim_update(bNodeTree *UNUSED(ntree), bNode *node) bNodeSocket *start_len = end_fac->next; bNodeSocket *end_len = start_len->next; - nodeSetSocketAvailability(start_fac, mode == GEO_NODE_CURVE_SAMPLE_FACTOR); - nodeSetSocketAvailability(end_fac, mode == GEO_NODE_CURVE_SAMPLE_FACTOR); - nodeSetSocketAvailability(start_len, mode == GEO_NODE_CURVE_SAMPLE_LENGTH); - nodeSetSocketAvailability(end_len, mode == GEO_NODE_CURVE_SAMPLE_LENGTH); + nodeSetSocketAvailability(ntree, start_fac, mode == GEO_NODE_CURVE_SAMPLE_FACTOR); + nodeSetSocketAvailability(ntree, end_fac, mode == GEO_NODE_CURVE_SAMPLE_FACTOR); + nodeSetSocketAvailability(ntree, start_len, mode == GEO_NODE_CURVE_SAMPLE_LENGTH); + nodeSetSocketAvailability(ntree, end_len, mode == GEO_NODE_CURVE_SAMPLE_LENGTH); } struct TrimLocation { @@ -216,9 +216,9 @@ static PolySpline trim_nurbs_spline(const Spline &spline, attribute_math::convert_to_static_type(src->type(), [&](auto dummy) { using T = decltype(dummy); - GVArray_Typed<T> eval_data = spline.interpolate_to_evaluated<T>(src->typed<T>()); + VArray<T> eval_data = spline.interpolate_to_evaluated<T>(src->typed<T>()); linear_trim_to_output_data<T>( - start, end, eval_data->get_internal_span(), dst->typed<T>()); + start, end, eval_data.get_internal_span(), dst->typed<T>()); }); return true; }, @@ -227,13 +227,13 @@ static PolySpline trim_nurbs_spline(const Spline &spline, linear_trim_to_output_data<float3>( start, end, spline.evaluated_positions(), new_spline.positions()); - GVArray_Typed<float> evaluated_radii = spline.interpolate_to_evaluated(spline.radii()); + VArray<float> evaluated_radii = spline.interpolate_to_evaluated(spline.radii()); linear_trim_to_output_data<float>( - start, end, evaluated_radii->get_internal_span(), new_spline.radii()); + start, end, evaluated_radii.get_internal_span(), new_spline.radii()); - GVArray_Typed<float> evaluated_tilts = spline.interpolate_to_evaluated(spline.tilts()); + VArray<float> evaluated_tilts = spline.interpolate_to_evaluated(spline.tilts()); linear_trim_to_output_data<float>( - start, end, evaluated_tilts->get_internal_span(), new_spline.tilts()); + start, end, evaluated_tilts.get_internal_span(), new_spline.tilts()); return new_spline; } @@ -427,8 +427,8 @@ static PolySpline to_single_point_nurbs(const Spline &spline, const Spline::Look std::optional<GMutableSpan> dst = new_spline.attributes.get_for_write(attribute_id); attribute_math::convert_to_static_type(src->type(), [&](auto dummy) { using T = decltype(dummy); - GVArray_Typed<T> eval_data = spline.interpolate_to_evaluated<T>(src->typed<T>()); - to_single_point_data<T>(trim, eval_data->get_internal_span(), dst->typed<T>()); + VArray<T> eval_data = spline.interpolate_to_evaluated<T>(src->typed<T>()); + to_single_point_data<T>(trim, eval_data.get_internal_span(), dst->typed<T>()); }); return true; }, @@ -436,11 +436,11 @@ static PolySpline to_single_point_nurbs(const Spline &spline, const Spline::Look to_single_point_data<float3>(trim, spline.evaluated_positions(), new_spline.positions()); - GVArray_Typed<float> evaluated_radii = spline.interpolate_to_evaluated(spline.radii()); - to_single_point_data<float>(trim, evaluated_radii->get_internal_span(), new_spline.radii()); + VArray<float> evaluated_radii = spline.interpolate_to_evaluated(spline.radii()); + to_single_point_data<float>(trim, evaluated_radii.get_internal_span(), new_spline.radii()); - GVArray_Typed<float> evaluated_tilts = spline.interpolate_to_evaluated(spline.tilts()); - to_single_point_data<float>(trim, evaluated_tilts->get_internal_span(), new_spline.tilts()); + VArray<float> evaluated_tilts = spline.interpolate_to_evaluated(spline.tilts()); + to_single_point_data<float>(trim, evaluated_tilts.get_internal_span(), new_spline.tilts()); return new_spline; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc index e0a3faaefb0..bbc7c337508 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc @@ -32,19 +32,19 @@ using blender::bke::CustomDataAttributes; /* Code from the mask modifier in MOD_mask.cc. */ -extern void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh, - Mesh &dst_mesh, - blender::Span<int> vertex_map); -extern void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, - Mesh &dst_mesh, - blender::Span<int> vertex_map, - blender::Span<int> edge_map); -extern void copy_masked_polys_to_new_mesh(const Mesh &src_mesh, - Mesh &dst_mesh, - blender::Span<int> vertex_map, - blender::Span<int> edge_map, - blender::Span<int> masked_poly_indices, - blender::Span<int> new_loop_starts); +void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + blender::Span<int> vertex_map); +void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + blender::Span<int> vertex_map, + blender::Span<int> edge_map); +void copy_masked_polys_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + blender::Span<int> vertex_map, + blender::Span<int> edge_map, + blender::Span<int> masked_poly_indices, + blender::Span<int> new_loop_starts); namespace blender::nodes { @@ -138,7 +138,7 @@ static void copy_attributes(const Map<AttributeIDRef, AttributeKind> &attributes if (!domains.contains(attribute.domain)) { continue; } - const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray->type()); + const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only( attribute_id, attribute.domain, data_type); @@ -149,7 +149,7 @@ static void copy_attributes(const Map<AttributeIDRef, AttributeKind> &attributes attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); - GVArray_Span<T> span{*attribute.varray}; + VArray_Span<T> span{attribute.varray.typed<T>()}; MutableSpan<T> out_span = result_attribute.as_span<T>(); out_span.copy_from(span); }); @@ -178,7 +178,7 @@ static void copy_attributes_based_on_mask(const Map<AttributeIDRef, AttributeKin if (domain != attribute.domain) { continue; } - const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray->type()); + const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only( attribute_id, attribute.domain, data_type); @@ -189,7 +189,7 @@ static void copy_attributes_based_on_mask(const Map<AttributeIDRef, AttributeKin attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); - GVArray_Span<T> span{*attribute.varray}; + VArray_Span<T> span{attribute.varray.typed<T>()}; MutableSpan<T> out_span = result_attribute.as_span<T>(); copy_data(span, out_span, mask); }); diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc index fa439b04da0..b2c76b76590 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc @@ -67,19 +67,21 @@ static void geo_node_point_distribute_points_on_faces_layout(uiLayout *layout, uiItemR(layout, ptr, "distribute_method", 0, "", ICON_NONE); } -static void node_point_distribute_points_on_faces_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_point_distribute_points_on_faces_update(bNodeTree *ntree, bNode *node) { bNodeSocket *sock_distance_min = (bNodeSocket *)BLI_findlink(&node->inputs, 2); bNodeSocket *sock_density_max = (bNodeSocket *)sock_distance_min->next; bNodeSocket *sock_density = sock_density_max->next; bNodeSocket *sock_density_factor = sock_density->next; - nodeSetSocketAvailability(sock_distance_min, + nodeSetSocketAvailability(ntree, + sock_distance_min, node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON); - nodeSetSocketAvailability(sock_density_max, - node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON); - nodeSetSocketAvailability(sock_density, - node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_RANDOM); - nodeSetSocketAvailability(sock_density_factor, + nodeSetSocketAvailability( + ntree, sock_density_max, node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON); + nodeSetSocketAvailability( + ntree, sock_density, node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_RANDOM); + nodeSetSocketAvailability(ntree, + sock_density_factor, node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON); } @@ -295,6 +297,12 @@ BLI_NOINLINE static void propagate_existing_attributes( for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) { const AttributeIDRef attribute_id = entry.key; const CustomDataType output_data_type = entry.value.data_type; + + ReadAttributeLookup source_attribute = mesh_component.attribute_try_get_for_read(attribute_id); + if (!source_attribute) { + continue; + } + /* The output domain is always #ATTR_DOMAIN_POINT, since we are creating a point cloud. */ OutputAttribute attribute_out = point_component.attribute_try_get_for_output_only( attribute_id, ATTR_DOMAIN_POINT, output_data_type); @@ -303,23 +311,12 @@ BLI_NOINLINE static void propagate_existing_attributes( } GMutableSpan out_span = attribute_out.as_span(); - - std::optional<AttributeMetaData> attribute_info = point_component.attribute_get_meta_data( - attribute_id); - if (!attribute_info) { - continue; - } - - const AttributeDomain source_domain = attribute_info->domain; - GVArrayPtr source_attribute = mesh_component.attribute_get_for_read( - attribute_id, source_domain, output_data_type, nullptr); - if (!source_attribute) { - continue; - } - - interpolate_attribute( - mesh, bary_coords, looptri_indices, source_domain, *source_attribute, out_span); - + interpolate_attribute(mesh, + bary_coords, + looptri_indices, + source_attribute.domain, + source_attribute.varray, + out_span); attribute_out.save(); } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc b/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc index e1c72fbd438..7bbe0716f78 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc @@ -82,7 +82,7 @@ class ImageFieldsFunction : public fn::MultiFunction { image_buffer_ = BKE_image_acquire_ibuf(&image_, &image_user_, &image_lock_); if (image_buffer_ == nullptr) { - throw std::runtime_error("cannot aquire image buffer"); + throw std::runtime_error("cannot acquire image buffer"); } if (image_buffer_->rect_float == nullptr) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc index 92b89313d23..6c95ad73bf7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc @@ -31,19 +31,18 @@ static void geo_node_input_normal_declare(NodeDeclarationBuilder &b) b.add_output<decl::Vector>(N_("Normal")).field_source(); } -static GVArrayPtr mesh_face_normals(const Mesh &mesh, - const Span<MVert> verts, - const Span<MPoly> polys, - const Span<MLoop> loops, - const IndexMask mask) +static VArray<float3> mesh_face_normals(const Mesh &mesh, + const Span<MVert> verts, + const Span<MPoly> polys, + const Span<MLoop> loops, + const IndexMask mask) { /* Use existing normals to avoid unnecessarily recalculating them, if possible. */ if (!(mesh.runtime.cd_dirty_poly & CD_MASK_NORMAL) && 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, polys.size())); + return VArray<float3>::ForSpan({(const float3 *)data, polys.size()}); } auto normal_fn = [verts, polys, loops](const int i) -> float3 { @@ -53,24 +52,21 @@ static GVArrayPtr mesh_face_normals(const Mesh &mesh, return normal; }; - return std::make_unique< - fn::GVArray_For_EmbeddedVArray<float3, VArray_For_Func<float3, decltype(normal_fn)>>>( - mask.min_array_size(), mask.min_array_size(), normal_fn); + return VArray<float3>::ForFunc(mask.min_array_size(), normal_fn); } -static GVArrayPtr mesh_vertex_normals(const Mesh &mesh, - const Span<MVert> verts, - const Span<MPoly> polys, - const Span<MLoop> loops, - const IndexMask mask) +static VArray<float3> mesh_vertex_normals(const Mesh &mesh, + const Span<MVert> verts, + const Span<MPoly> polys, + const Span<MLoop> loops, + const IndexMask mask) { /* Use existing normals to avoid unnecessarily recalculating them, if possible. */ if (!(mesh.runtime.cd_dirty_vert & CD_MASK_NORMAL) && CustomData_has_layer(&mesh.vdata, 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.totvert)); + return VArray<float3>::ForSpan({(const float3 *)data, mesh.totvert}); } /* If the normals are dirty, they must be recalculated for the output of this node's field @@ -91,14 +87,14 @@ static GVArrayPtr mesh_vertex_normals(const Mesh &mesh, nullptr, (float(*)[3])normals.data()); - return std::make_unique<fn::GVArray_For_ArrayContainer<Array<float3>>>(std::move(normals)); + return VArray<float3>::ForContainer(std::move(normals)); } -static const GVArray *construct_mesh_normals_gvarray(const MeshComponent &mesh_component, +static VArray<float3> construct_mesh_normals_gvarray(const MeshComponent &mesh_component, const Mesh &mesh, const IndexMask mask, const AttributeDomain domain, - ResourceScope &scope) + ResourceScope &UNUSED(scope)) { Span<MVert> verts{mesh.mvert, mesh.totvert}; Span<MEdge> edges{mesh.medge, mesh.totedge}; @@ -107,18 +103,18 @@ static const GVArray *construct_mesh_normals_gvarray(const MeshComponent &mesh_c switch (domain) { case ATTR_DOMAIN_FACE: { - return scope.add_value(mesh_face_normals(mesh, verts, polys, loops, mask)).get(); + return mesh_face_normals(mesh, verts, polys, loops, mask); } case ATTR_DOMAIN_POINT: { - return scope.add_value(mesh_vertex_normals(mesh, verts, polys, loops, mask)).get(); + return mesh_vertex_normals(mesh, verts, polys, loops, mask); } case ATTR_DOMAIN_EDGE: { /* In this case, start with vertex normals and convert to the edge domain, since the * conversion from edges to vertices is very simple. Use the full mask since the edges * might use the vertex normal from any index. */ - GVArrayPtr vert_normals = mesh_vertex_normals( + GVArray vert_normals = mesh_vertex_normals( mesh, verts, polys, loops, IndexRange(verts.size())); - Span<float3> vert_normals_span = vert_normals->get_internal_span().typed<float3>(); + Span<float3> vert_normals_span = vert_normals.get_internal_span().typed<float3>(); Array<float3> edge_normals(mask.min_array_size()); /* Use "manual" domain interpolation instead of the GeometryComponent API to avoid @@ -130,23 +126,21 @@ static const GVArray *construct_mesh_normals_gvarray(const MeshComponent &mesh_c .normalized(); } - return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float3>>>( - std::move(edge_normals)); + return VArray<float3>::ForContainer(std::move(edge_normals)); } case ATTR_DOMAIN_CORNER: { /* The normals on corners are just the mesh's face normals, so start with the face normal * array and copy the face normal for each of its corners. */ - GVArrayPtr face_normals = mesh_face_normals( + VArray<float3> face_normals = mesh_face_normals( mesh, verts, polys, loops, IndexRange(polys.size())); /* In this case using the mesh component's generic domain interpolation is fine, the data * will still be normalized, since the face normal is just copied to every corner. */ - GVArrayPtr loop_normals = mesh_component.attribute_try_adapt_domain( + return mesh_component.attribute_try_adapt_domain<float3>( std::move(face_normals), ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER); - return scope.add_value(std::move(loop_normals)).get(); } default: - return nullptr; + return {}; } } @@ -204,9 +198,9 @@ static Array<float3> curve_normal_point_domain(const CurveEval &curve) return normals; } -static const GVArray *construct_curve_normal_gvarray(const CurveComponent &component, +static VArray<float3> construct_curve_normal_gvarray(const CurveComponent &component, const AttributeDomain domain, - ResourceScope &scope) + ResourceScope &UNUSED(scope)) { const CurveEval *curve = component.get_for_read(); if (curve == nullptr) { @@ -220,20 +214,18 @@ static const GVArray *construct_curve_normal_gvarray(const CurveComponent &compo * This is only possible when there is only one poly spline. */ if (splines.size() == 1 && splines.first()->type() == Spline::Type::Poly) { const PolySpline &spline = static_cast<PolySpline &>(*splines.first()); - return &scope.construct<fn::GVArray_For_Span<float3>>(spline.evaluated_normals()); + return VArray<float3>::ForSpan(spline.evaluated_normals()); } Array<float3> normals = curve_normal_point_domain(*curve); - return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float3>>>(std::move(normals)); + return VArray<float3>::ForContainer(std::move(normals)); } if (domain == ATTR_DOMAIN_CURVE) { Array<float3> point_normals = curve_normal_point_domain(*curve); - GVArrayPtr gvarray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<float3>>>( - std::move(point_normals)); - GVArrayPtr spline_normals = component.attribute_try_adapt_domain( - std::move(gvarray), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE); - return scope.add_value(std::move(spline_normals)).get(); + VArray<float3> varray = VArray<float3>::ForContainer(std::move(point_normals)); + return component.attribute_try_adapt_domain<float3>( + std::move(varray), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE); } return nullptr; @@ -246,9 +238,9 @@ class NormalFieldInput final : public fn::FieldInput { category_ = Category::Generated; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &scope) const final + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &scope) const final { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { @@ -260,7 +252,7 @@ class NormalFieldInput final : public fn::FieldInput { const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); const Mesh *mesh = mesh_component.get_for_read(); if (mesh == nullptr) { - return nullptr; + return {}; } return construct_mesh_normals_gvarray(mesh_component, *mesh, mask, domain, scope); @@ -270,7 +262,7 @@ class NormalFieldInput final : public fn::FieldInput { return construct_curve_normal_gvarray(curve_component, domain, scope); } } - return nullptr; + return {}; } uint64_t hash() const override diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc index 895efa6f0ed..a976e0b193f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc @@ -25,31 +25,25 @@ static void geo_node_input_spline_length_declare(NodeDeclarationBuilder &b) b.add_output<decl::Float>(N_("Length")).field_source(); } -static const GVArray *construct_spline_length_gvarray(const CurveComponent &component, - const AttributeDomain domain, - ResourceScope &scope) +static VArray<float> construct_spline_length_gvarray(const CurveComponent &component, + const AttributeDomain domain, + ResourceScope &UNUSED(scope)) { const CurveEval *curve = component.get_for_read(); if (curve == nullptr) { - return nullptr; + return {}; } Span<SplinePtr> splines = curve->splines(); auto length_fn = [splines](int i) { return splines[i]->length(); }; if (domain == ATTR_DOMAIN_CURVE) { - return &scope.construct< - fn::GVArray_For_EmbeddedVArray<float, VArray_For_Func<float, decltype(length_fn)>>>( - splines.size(), splines.size(), length_fn); + return VArray<float>::ForFunc(splines.size(), length_fn); } if (domain == ATTR_DOMAIN_POINT) { - GVArrayPtr length = std::make_unique< - fn::GVArray_For_EmbeddedVArray<float, VArray_For_Func<float, decltype(length_fn)>>>( - splines.size(), splines.size(), length_fn); - return scope - .add_value(component.attribute_try_adapt_domain( - std::move(length), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT)) - .get(); + VArray<float> length = VArray<float>::ForFunc(splines.size(), length_fn); + return component.attribute_try_adapt_domain<float>( + std::move(length), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT); } return nullptr; @@ -62,9 +56,9 @@ class SplineLengthFieldInput final : public fn::FieldInput { category_ = Category::Generated; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask UNUSED(mask), - ResourceScope &scope) const final + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask UNUSED(mask), + ResourceScope &scope) const final { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { @@ -76,7 +70,7 @@ class SplineLengthFieldInput final : public fn::FieldInput { return construct_spline_length_gvarray(curve_component, domain, scope); } } - return nullptr; + return {}; } uint64_t hash() const override diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc index 6b1736fe2ac..49885f29d44 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc @@ -84,9 +84,9 @@ static Array<float3> curve_tangent_point_domain(const CurveEval &curve) return tangents; } -static const GVArray *construct_curve_tangent_gvarray(const CurveComponent &component, +static VArray<float3> construct_curve_tangent_gvarray(const CurveComponent &component, const AttributeDomain domain, - ResourceScope &scope) + ResourceScope &UNUSED(scope)) { const CurveEval *curve = component.get_for_read(); if (curve == nullptr) { @@ -100,20 +100,19 @@ static const GVArray *construct_curve_tangent_gvarray(const CurveComponent &comp * This is only possible when there is only one poly spline. */ if (splines.size() == 1 && splines.first()->type() == Spline::Type::Poly) { const PolySpline &spline = static_cast<PolySpline &>(*splines.first()); - return &scope.construct<fn::GVArray_For_Span<float3>>(spline.evaluated_tangents()); + return VArray<float3>::ForSpan(spline.evaluated_tangents()); } Array<float3> tangents = curve_tangent_point_domain(*curve); - return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float3>>>(std::move(tangents)); + return VArray<float3>::ForContainer(std::move(tangents)); } if (domain == ATTR_DOMAIN_CURVE) { Array<float3> point_tangents = curve_tangent_point_domain(*curve); - GVArrayPtr gvarray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<float3>>>( - std::move(point_tangents)); - GVArrayPtr spline_tangents = component.attribute_try_adapt_domain( - std::move(gvarray), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE); - return scope.add_value(std::move(spline_tangents)).get(); + return component.attribute_try_adapt_domain<float3>( + VArray<float3>::ForContainer(std::move(point_tangents)), + ATTR_DOMAIN_POINT, + ATTR_DOMAIN_CURVE); } return nullptr; @@ -126,9 +125,9 @@ class TangentFieldInput final : public fn::FieldInput { category_ = Category::Generated; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask UNUSED(mask), - ResourceScope &scope) const final + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask UNUSED(mask), + ResourceScope &scope) const final { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { @@ -141,7 +140,7 @@ class TangentFieldInput final : public fn::FieldInput { return construct_curve_tangent_gvarray(curve_component, domain, scope); } } - return nullptr; + return {}; } uint64_t hash() const override diff --git a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc index aff29d973d4..2a68030aba7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc @@ -80,10 +80,10 @@ static void add_instances_from_component(InstancesComponent &dst_component, select_len); FieldEvaluator field_evaluator{field_context, domain_size}; - const VArray<bool> *pick_instance = nullptr; - const VArray<int> *indices = nullptr; - const VArray<float3> *rotations = nullptr; - const VArray<float3> *scales = nullptr; + VArray<bool> pick_instance; + VArray<int> indices; + VArray<float3> rotations; + VArray<float3> scales; /* The evaluator could use the component's stable IDs as a destination directly, but only the * selected indices should be copied. */ field_evaluator.add(params.get_input<Field<bool>>("Pick Instance"), &pick_instance); @@ -92,7 +92,7 @@ static void add_instances_from_component(InstancesComponent &dst_component, field_evaluator.add(params.get_input<Field<float3>>("Scale"), &scales); field_evaluator.evaluate(); - GVArray_Typed<float3> positions = src_component.attribute_get_for_read<float3>( + VArray<float3> positions = src_component.attribute_get_for_read<float3>( "position", domain, {0, 0, 0}); const InstancesComponent *src_instances = instance.get_component_for_read<InstancesComponent>(); @@ -101,7 +101,7 @@ static void add_instances_from_component(InstancesComponent &dst_component, Array<int> handle_mapping; /* Only fill #handle_mapping when it may be used below. */ if (src_instances != nullptr && - (!pick_instance->is_single() || pick_instance->get_internal_single())) { + (!pick_instance.is_single() || pick_instance.get_internal_single())) { Span<InstanceReference> src_references = src_instances->references(); handle_mapping.reinitialize(src_references.size()); for (const int src_instance_handle : src_references.index_range()) { @@ -121,17 +121,16 @@ static void add_instances_from_component(InstancesComponent &dst_component, /* Compute base transform for every instances. */ float4x4 &dst_transform = dst_transforms[range_i]; - dst_transform = float4x4::from_loc_eul_scale( - positions[i], rotations->get(i), scales->get(i)); + dst_transform = float4x4::from_loc_eul_scale(positions[i], rotations[i], scales[i]); /* Reference that will be used by this new instance. */ int dst_handle = empty_reference_handle; - const bool use_individual_instance = pick_instance->get(i); + const bool use_individual_instance = pick_instance[i]; if (use_individual_instance) { if (src_instances != nullptr) { const int src_instances_amount = src_instances->instances_amount(); - const int original_index = indices->get(i); + const int original_index = indices[i]; /* Use #mod_i instead of `%` to get the desirable wrap around behavior where -1 * refers to the last element. */ const int index = mod_i(original_index, std::max(src_instances_amount, 1)); @@ -155,10 +154,10 @@ static void add_instances_from_component(InstancesComponent &dst_component, } }); - GVArrayPtr id_attribute = src_component.attribute_try_get_for_read( - "id", ATTR_DOMAIN_POINT, CD_PROP_INT32); - if (id_attribute) { - GVArray_Typed<int> ids{*id_attribute}; + VArray<int> ids = src_component + .attribute_try_get_for_read("id", ATTR_DOMAIN_POINT, CD_PROP_INT32) + .typed<int>(); + if (ids) { VArray_Span<int> ids_span{ids}; MutableSpan<int> dst_ids = dst_component.instance_ids_ensure(); for (const int64_t i : selection.index_range()) { @@ -166,8 +165,8 @@ static void add_instances_from_component(InstancesComponent &dst_component, } } - if (pick_instance->is_single()) { - if (pick_instance->get_internal_single()) { + if (pick_instance.is_single()) { + if (pick_instance.get_internal_single()) { if (instance.has_realized_data()) { params.error_message_add( NodeWarningType::Info, diff --git a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc index c3955426e69..f8c146833ba 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc @@ -51,9 +51,8 @@ static void convert_instances_to_points(GeometrySet &geometry_set, { const InstancesComponent &instances = *geometry_set.get_component_for_read<InstancesComponent>(); - const AttributeDomain attribute_domain = ATTR_DOMAIN_POINT; - GeometryComponentFieldContext field_context{instances, attribute_domain}; - const int domain_size = instances.attribute_domain_size(attribute_domain); + GeometryComponentFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE}; + const int domain_size = instances.attribute_domain_size(ATTR_DOMAIN_INSTANCE); fn::FieldEvaluator selection_evaluator{field_context, domain_size}; selection_evaluator.add(std::move(selection_field)); diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc index 9d363bd1af4..fcdf7c2da01 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc @@ -27,8 +27,6 @@ #include "node_geometry_util.hh" -using blender::fn::GVArray_For_GSpan; - namespace blender::nodes { static void geo_node_join_geometry_declare(NodeDeclarationBuilder &b) @@ -190,10 +188,10 @@ static void fill_new_attribute(Span<const GeometryComponent *> src_components, if (domain_size == 0) { continue; } - GVArrayPtr read_attribute = component->attribute_get_for_read( + GVArray read_attribute = component->attribute_get_for_read( attribute_id, domain, data_type, nullptr); - GVArray_GSpan src_span{*read_attribute}; + GVArray_GSpan src_span{read_attribute}; const void *src_buffer = src_span.data(); void *dst_buffer = dst_span[offset]; cpp_type->copy_assign_n(src_buffer, dst_buffer, domain_size); @@ -319,8 +317,7 @@ static void ensure_control_point_attribute(const AttributeIDRef &attribute_id, spline->size() * type.size(), type.alignment(), __func__); const DataTypeConversions &conversions = blender::nodes::get_implicit_type_conversions(); - conversions.try_convert(std::make_unique<GVArray_For_GSpan>(*attribute), type) - ->materialize(converted_buffer); + conversions.try_convert(GVArray::ForSpan(*attribute), type).materialize(converted_buffer); spline->attributes.remove(attribute_id); spline->attributes.create_by_move(attribute_id, data_type, converted_buffer); @@ -333,14 +330,14 @@ static void ensure_control_point_attribute(const AttributeIDRef &attribute_id, /* In this case the attribute did not exist, but there is a spline domain attribute * we can retrieve a value from, as a spline to point domain conversion. So fill the * new attribute with the value for this spline. */ - GVArrayPtr current_curve_attribute = current_curve->attributes.get_for_read( + GVArray current_curve_attribute = current_curve->attributes.get_for_read( attribute_id, data_type, nullptr); BLI_assert(spline->attributes.get_for_read(attribute_id)); std::optional<GMutableSpan> new_attribute = spline->attributes.get_for_write(attribute_id); BUFFER_FOR_CPP_TYPE_VALUE(type, buffer); - current_curve_attribute->get(spline_index_in_component, buffer); + current_curve_attribute.get(spline_index_in_component, buffer); type.fill_assign_n(buffer, new_attribute->data(), new_attribute->size()); } } @@ -397,8 +394,8 @@ static void ensure_spline_attribute(const AttributeIDRef &attribute_id, if (size == 0) { continue; } - GVArrayPtr read_attribute = curve.attributes.get_for_read(attribute_id, data_type, nullptr); - GVArray_GSpan src_span{*read_attribute}; + GVArray read_attribute = curve.attributes.get_for_read(attribute_id, data_type, nullptr); + GVArray_GSpan src_span{read_attribute}; const void *src_buffer = src_span.data(); type.copy_assign_n(src_buffer, result_attribute[offset], size); diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc index 06c770820ee..12ffa21762e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc @@ -64,36 +64,33 @@ class MaterialSelectionFieldInput final : public fn::FieldInput { category_ = Category::Generated; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &scope) const final + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &UNUSED(scope)) const final { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { const GeometryComponent &component = geometry_context->geometry_component(); const AttributeDomain domain = geometry_context->domain(); if (component.type() != GEO_COMPONENT_TYPE_MESH) { - return nullptr; + return {}; } const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); const Mesh *mesh = mesh_component.get_for_read(); if (mesh == nullptr) { - return nullptr; + return {}; } if (domain == ATTR_DOMAIN_FACE) { Array<bool> selection(mask.min_array_size()); select_mesh_by_material(*mesh, material_, mask, selection); - return &scope.construct<fn::GVArray_For_ArrayContainer<Array<bool>>>(std::move(selection)); + return VArray<bool>::ForContainer(std::move(selection)); } Array<bool> selection(mesh->totpoly); select_mesh_by_material(*mesh, material_, IndexMask(mesh->totpoly), selection); - GVArrayPtr face_selection = std::make_unique<fn::GVArray_For_ArrayContainer<Array<bool>>>( - std::move(selection)); - GVArrayPtr final_selection = mesh_component.attribute_try_adapt_domain( - std::move(face_selection), ATTR_DOMAIN_FACE, domain); - return scope.add_value(std::move(final_selection)).get(); + return mesh_component.attribute_try_adapt_domain<bool>( + VArray<bool>::ForContainer(std::move(selection)), ATTR_DOMAIN_FACE, domain); } return nullptr; diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc index 01378431ca6..fc93f6e72b5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc @@ -76,7 +76,7 @@ static void geo_node_mesh_primitive_cone_init(bNodeTree *UNUSED(ntree), bNode *n node->storage = node_storage; } -static void geo_node_mesh_primitive_cone_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_mesh_primitive_cone_update(bNodeTree *ntree, bNode *node) { bNodeSocket *vertices_socket = (bNodeSocket *)node->inputs.first; bNodeSocket *rings_socket = vertices_socket->next; @@ -86,7 +86,7 @@ static void geo_node_mesh_primitive_cone_update(bNodeTree *UNUSED(ntree), bNode const GeometryNodeMeshCircleFillType fill_type = static_cast<const GeometryNodeMeshCircleFillType>(storage.fill_type); const bool has_fill = fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE; - nodeSetSocketAvailability(fill_subdiv_socket, has_fill); + nodeSetSocketAvailability(ntree, fill_subdiv_socket, has_fill); } static void geo_node_mesh_primitive_cone_layout(uiLayout *layout, diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc index 51ecff72e68..a2ac46190b3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc @@ -56,8 +56,8 @@ static void geo_node_mesh_primitive_cylinder_declare(NodeDeclarationBuilder &b) .description(N_("The height of the cylinder")); b.add_output<decl::Geometry>(N_("Mesh")); b.add_output<decl::Bool>(N_("Top")).field_source(); - b.add_output<decl::Bool>(N_("Bottom")).field_source(); b.add_output<decl::Bool>(N_("Side")).field_source(); + b.add_output<decl::Bool>(N_("Bottom")).field_source(); } static void geo_node_mesh_primitive_cylinder_layout(uiLayout *layout, @@ -79,7 +79,7 @@ static void geo_node_mesh_primitive_cylinder_init(bNodeTree *UNUSED(ntree), bNod node->storage = node_storage; } -static void geo_node_mesh_primitive_cylinder_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_mesh_primitive_cylinder_update(bNodeTree *ntree, bNode *node) { bNodeSocket *vertices_socket = (bNodeSocket *)node->inputs.first; bNodeSocket *rings_socket = vertices_socket->next; @@ -89,7 +89,7 @@ static void geo_node_mesh_primitive_cylinder_update(bNodeTree *UNUSED(ntree), bN const GeometryNodeMeshCircleFillType fill_type = static_cast<const GeometryNodeMeshCircleFillType>(storage.fill_type); const bool has_fill = fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE; - nodeSetSocketAvailability(fill_subdiv_socket, has_fill); + nodeSetSocketAvailability(ntree, fill_subdiv_socket, has_fill); } static void geo_node_mesh_primitive_cylinder_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc index df4efb2427c..1a92be1c05d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc @@ -74,7 +74,7 @@ static void geo_node_mesh_primitive_line_init(bNodeTree *UNUSED(ntree), bNode *n node->storage = node_storage; } -static void geo_node_mesh_primitive_line_update(bNodeTree *UNUSED(tree), bNode *node) +static void geo_node_mesh_primitive_line_update(bNodeTree *ntree, bNode *node) { bNodeSocket *count_socket = (bNodeSocket *)node->inputs.first; bNodeSocket *resolution_socket = count_socket->next; @@ -90,10 +90,12 @@ static void geo_node_mesh_primitive_line_update(bNodeTree *UNUSED(tree), bNode * (mode == GEO_NODE_MESH_LINE_MODE_END_POINTS) ? N_("End Location") : N_("Offset")); - nodeSetSocketAvailability(resolution_socket, + nodeSetSocketAvailability(ntree, + resolution_socket, mode == GEO_NODE_MESH_LINE_MODE_END_POINTS && count_mode == GEO_NODE_MESH_LINE_COUNT_RESOLUTION); - nodeSetSocketAvailability(count_socket, + nodeSetSocketAvailability(ntree, + count_socket, mode == GEO_NODE_MESH_LINE_MODE_OFFSET || count_mode == GEO_NODE_MESH_LINE_COUNT_TOTAL); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc index 92911e89f59..a37e3e34777 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc @@ -113,14 +113,14 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set, for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) { const AttributeIDRef attribute_id = entry.key; const CustomDataType data_type = entry.value.data_type; - GVArrayPtr src = mesh_component->attribute_get_for_read(attribute_id, domain, data_type); + GVArray src = mesh_component->attribute_get_for_read(attribute_id, domain, data_type); OutputAttribute dst = point_component.attribute_try_get_for_output_only( attribute_id, ATTR_DOMAIN_POINT, data_type); if (dst && src) { attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); - GVArray_Typed<T> src_typed{*src}; - copy_attribute_to_points(*src_typed, selection, dst.as_span().typed<T>()); + VArray<T> src_typed = src.typed<T>(); + copy_attribute_to_points(src_typed, selection, dst.as_span().typed<T>()); }); dst.save(); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc index 3ba32c4b674..bb8e5f7e29b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc @@ -27,9 +27,8 @@ static void geo_node_object_info_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Object>(N_("Object")).hide_label(); b.add_input<decl::Bool>(N_("As Instance")) - .description( - N_("Output the entire object as single instance. " - "This allows instancing non-geometry object types")); + .description(N_("Output the entire object as single instance. " + "This allows instancing non-geometry object types")); b.add_output<decl::Vector>(N_("Location")); b.add_output<decl::Vector>(N_("Rotation")); b.add_output<decl::Vector>(N_("Scale")); @@ -48,53 +47,64 @@ static void geo_node_object_info_exec(GeoNodeExecParams params) const bool transform_space_relative = (node_storage->transform_space == GEO_NODE_TRANSFORM_SPACE_RELATIVE); - Object *object = params.get_input<Object *>("Object"); + auto default_transform = [&]() { + params.set_output("Location", float3(0)); + params.set_output("Rotation", float3(0)); + params.set_output("Scale", float3(0)); + }; + auto default_geometry = [&]() { params.set_output("Geometry", GeometrySet()); }; - float3 location = {0, 0, 0}; - float3 rotation = {0, 0, 0}; - float3 scale = {0, 0, 0}; - GeometrySet geometry_set; + Object *object = params.get_input<Object *>("Object"); const Object *self_object = params.self_object(); + if (object == nullptr) { + default_transform(); + default_geometry(); + return; + } - if (object != nullptr) { - const float4x4 transform = float4x4(self_object->imat) * float4x4(object->obmat); + const float4x4 &object_matrix = object->obmat; + const float4x4 transform = float4x4(self_object->imat) * object_matrix; - float quaternion[4]; - if (transform_space_relative) { - mat4_decompose(location, quaternion, scale, transform.values); - } - else { - mat4_decompose(location, quaternion, scale, object->obmat); + if (transform_space_relative) { + params.set_output("Location", transform.translation()); + params.set_output("Rotation", transform.to_euler()); + params.set_output("Scale", transform.scale()); + } + else { + params.set_output("Location", object_matrix.translation()); + params.set_output("Rotation", object_matrix.to_euler()); + params.set_output("Scale", object_matrix.scale()); + } + + if (params.output_is_required("Geometry")) { + if (object == self_object) { + params.error_message_add(NodeWarningType::Error, + TIP_("Geometry cannot be retrieved from the modifier object")); + default_geometry(); + return; } - quat_to_eul(rotation, quaternion); - - if (object != self_object) { - if (params.get_input<bool>("As Instance")) { - InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>(); - const int handle = instances.add_reference(*object); - if (transform_space_relative) { - instances.add_instance(handle, transform); - } - else { - float unit_transform[4][4]; - unit_m4(unit_transform); - instances.add_instance(handle, unit_transform); - } + + GeometrySet geometry_set; + if (params.get_input<bool>("As Instance")) { + InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>(); + const int handle = instances.add_reference(*object); + if (transform_space_relative) { + instances.add_instance(handle, transform); } else { - geometry_set = bke::object_get_evaluated_geometry_set(*object); - if (transform_space_relative) { - transform_geometry_set(geometry_set, transform, *params.depsgraph()); - } + instances.add_instance(handle, float4x4::identity()); + } + } + else { + geometry_set = bke::object_get_evaluated_geometry_set(*object); + if (transform_space_relative) { + transform_geometry_set(geometry_set, transform, *params.depsgraph()); } } - } - params.set_output("Location", location); - params.set_output("Rotation", rotation); - params.set_output("Scale", scale); - params.set_output("Geometry", geometry_set); + params.set_output("Geometry", geometry_set); + } } static void geo_node_object_info_node_init(bNodeTree *UNUSED(tree), bNode *node) diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc index 3e0096824d3..5a6a3b25a45 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc @@ -74,15 +74,15 @@ static void geometry_set_points_to_vertices(GeometrySet &geometry_set, for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) { const AttributeIDRef attribute_id = entry.key; const CustomDataType data_type = entry.value.data_type; - GVArrayPtr src = point_component->attribute_get_for_read( + GVArray src = point_component->attribute_get_for_read( attribute_id, ATTR_DOMAIN_POINT, data_type); OutputAttribute dst = mesh_component.attribute_try_get_for_output_only( attribute_id, ATTR_DOMAIN_POINT, data_type); if (dst && src) { attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); - GVArray_Typed<T> src_typed{*src}; - VArray_Span<T> src_typed_span{*src_typed}; + VArray<T> src_typed = src.typed<T>(); + VArray_Span<T> src_typed_span{src_typed}; copy_attribute_to_vertices(src_typed_span, selection, dst.as_span().typed<T>()); }); dst.save(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc index 18d674a38a4..31c16cb95e0 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc @@ -61,16 +61,19 @@ static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node node->storage = data; } -static void geo_node_points_to_volume_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_points_to_volume_update(bNodeTree *ntree, bNode *node) { NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)node->storage; bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size"); bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount"); - nodeSetSocketAvailability(voxel_amount_socket, + nodeSetSocketAvailability(ntree, + voxel_amount_socket, data->resolution_mode == GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT); - nodeSetSocketAvailability( - voxel_size_socket, data->resolution_mode == GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE); + nodeSetSocketAvailability(ntree, + voxel_size_socket, + data->resolution_mode == + GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE); } #ifdef WITH_OPENVDB @@ -165,7 +168,7 @@ static void gather_point_data_from_component(GeoNodeExecParams ¶ms, Vector<float3> &r_positions, Vector<float> &r_radii) { - GVArray_Typed<float3> positions = component.attribute_get_for_read<float3>( + VArray<float3> positions = component.attribute_get_for_read<float3>( "position", ATTR_DOMAIN_POINT, {0, 0, 0}); Field<float> radius_field = params.get_input<Field<float>>("Radius"); @@ -173,7 +176,7 @@ static void gather_point_data_from_component(GeoNodeExecParams ¶ms, const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT); r_positions.resize(r_positions.size() + domain_size); - positions->materialize(r_positions.as_mutable_span().take_back(domain_size)); + positions.materialize(r_positions.as_mutable_span().take_back(domain_size)); r_radii.resize(r_radii.size() + domain_size); fn::FieldEvaluator evaluator{field_context, domain_size}; diff --git a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc index 34946b1115c..d422bf5a00a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc @@ -78,7 +78,7 @@ static void geo_node_raycast_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_raycast_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_raycast_update(bNodeTree *ntree, bNode *node) { const NodeGeometryRaycast &data = *(const NodeGeometryRaycast *)node->storage; const CustomDataType data_type = static_cast<CustomDataType>(data.data_type); @@ -89,11 +89,11 @@ static void geo_node_raycast_update(bNodeTree *UNUSED(ntree), bNode *node) bNodeSocket *socket_boolean = socket_color4f->next; bNodeSocket *socket_int32 = socket_boolean->next; - nodeSetSocketAvailability(socket_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_color4f, data_type == CD_PROP_COLOR); - nodeSetSocketAvailability(socket_boolean, data_type == CD_PROP_BOOL); - nodeSetSocketAvailability(socket_int32, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, socket_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_color4f, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, socket_boolean, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, socket_int32, data_type == CD_PROP_INT32); bNodeSocket *out_socket_vector = (bNodeSocket *)BLI_findlink(&node->outputs, 4); bNodeSocket *out_socket_float = out_socket_vector->next; @@ -101,11 +101,11 @@ static void geo_node_raycast_update(bNodeTree *UNUSED(ntree), bNode *node) bNodeSocket *out_socket_boolean = out_socket_color4f->next; bNodeSocket *out_socket_int32 = out_socket_boolean->next; - nodeSetSocketAvailability(out_socket_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(out_socket_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(out_socket_color4f, data_type == CD_PROP_COLOR); - nodeSetSocketAvailability(out_socket_boolean, data_type == CD_PROP_BOOL); - nodeSetSocketAvailability(out_socket_int32, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, out_socket_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, out_socket_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, out_socket_color4f, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, out_socket_boolean, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, out_socket_int32, data_type == CD_PROP_INT32); } static eAttributeMapMode get_map_mode(GeometryNodeRaycastMapMode map_mode) diff --git a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc index abf44b1aaf8..c53eaa2ded9 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc @@ -32,7 +32,7 @@ static void geo_node_rotate_instances_declare(NodeDeclarationBuilder &b) static void rotate_instances(GeoNodeExecParams ¶ms, InstancesComponent &instances_component) { - GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_POINT}; + GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE}; const int domain_size = instances_component.instances_amount(); fn::FieldEvaluator selection_evaluator{field_context, domain_size}; diff --git a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc index ea2b458410e..fa2501515a9 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc @@ -35,7 +35,7 @@ static void geo_node_scale_instances_declare(NodeDeclarationBuilder &b) static void scale_instances(GeoNodeExecParams ¶ms, InstancesComponent &instances_component) { - GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_POINT}; + GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE}; fn::FieldEvaluator selection_evaluator{field_context, instances_component.instances_amount()}; selection_evaluator.add(params.extract_input<Field<bool>>("Selection")); diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc index b64aa266330..30b445da58c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc @@ -28,6 +28,7 @@ static void geo_node_set_curve_handles_declare(NodeDeclarationBuilder &b) b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); b.add_input<decl::Vector>(N_("Position")).implicit_field(); + b.add_input<decl::Vector>(N_("Offset")).default_value(float3(0.0f, 0.0f, 0.0f)).supports_field(); b.add_output<decl::Geometry>(N_("Curve")); } @@ -50,7 +51,8 @@ static void geo_node_set_curve_handles_init(bNodeTree *UNUSED(tree), bNode *node static void set_position_in_component(const GeometryNodeCurveHandleMode mode, GeometryComponent &component, const Field<bool> &selection_field, - const Field<float3> &position_field) + const Field<float3> &position_field, + const Field<float3> &offset_field) { GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT}; const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT); @@ -111,11 +113,22 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode, } } - OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output_only<float3>( - side, ATTR_DOMAIN_POINT); fn::FieldEvaluator position_evaluator{field_context, &selection}; - position_evaluator.add_with_destination(position_field, positions.varray()); + position_evaluator.add(position_field); + position_evaluator.add(offset_field); position_evaluator.evaluate(); + + const VArray<float3> &positions_input = position_evaluator.get_evaluated<float3>(0); + const VArray<float3> &offsets_input = position_evaluator.get_evaluated<float3>(1); + + OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output<float3>( + side, ATTR_DOMAIN_POINT, {0, 0, 0}); + MutableSpan<float3> position_mutable = positions.as_span(); + + for (int i : selection) { + position_mutable[i] = positions_input[i] + offsets_input[i]; + } + positions.save(); } @@ -128,6 +141,7 @@ static void geo_node_set_curve_handles_exec(GeoNodeExecParams params) GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); Field<float3> position_field = params.extract_input<Field<float3>>("Position"); + Field<float3> offset_field = params.extract_input<Field<float3>>("Offset"); bool has_bezier = false; geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { @@ -137,7 +151,8 @@ static void geo_node_set_curve_handles_exec(GeoNodeExecParams params) set_position_in_component(mode, geometry_set.get_component_for_write<CurveComponent>(), selection_field, - position_field); + position_field, + offset_field); } }); if (!has_bezier) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc index 4e564386a28..5fe9fb1b3d4 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc @@ -34,8 +34,11 @@ static void set_position_in_component(GeometryComponent &component, const Field<float3> &position_field, const Field<float3> &offset_field) { - GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT}; - const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT); + AttributeDomain domain = component.type() == GEO_COMPONENT_TYPE_INSTANCES ? + ATTR_DOMAIN_INSTANCE : + ATTR_DOMAIN_POINT; + GeometryComponentFieldContext field_context{component, domain}; + const int domain_size = component.attribute_domain_size(domain); if (domain_size == 0) { return; } @@ -57,7 +60,7 @@ static void set_position_in_component(GeometryComponent &component, const VArray<float3> &offsets_input = position_evaluator.get_evaluated<float3>(1); OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output<float3>( - "position", ATTR_DOMAIN_POINT, {0, 0, 0}); + "position", domain, {0, 0, 0}); MutableSpan<float3> position_mutable = positions.as_span(); for (int i : selection) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc index 95e94a22d81..9e3ff10a3c5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc @@ -91,17 +91,19 @@ static void geo_node_string_to_curves_init(bNodeTree *UNUSED(ntree), bNode *node node->id = (ID *)BKE_vfont_builtin_get(); } -static void geo_node_string_to_curves_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_string_to_curves_update(bNodeTree *ntree, bNode *node) { const NodeGeometryStringToCurves *storage = (const NodeGeometryStringToCurves *)node->storage; const GeometryNodeStringToCurvesOverflowMode overflow = (GeometryNodeStringToCurvesOverflowMode) storage->overflow; bNodeSocket *socket_remainder = ((bNodeSocket *)node->outputs.first)->next; - nodeSetSocketAvailability(socket_remainder, overflow == GEO_NODE_STRING_TO_CURVES_MODE_TRUNCATE); + nodeSetSocketAvailability( + ntree, socket_remainder, overflow == GEO_NODE_STRING_TO_CURVES_MODE_TRUNCATE); bNodeSocket *height_socket = (bNodeSocket *)node->inputs.last; bNodeSocket *width_socket = height_socket->prev; - nodeSetSocketAvailability(height_socket, overflow != GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW); + nodeSetSocketAvailability( + ntree, height_socket, overflow != GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW); node_sock_label(width_socket, overflow == GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW ? N_("Max Width") : N_("Text Box Width")); diff --git a/source/blender/nodes/geometry/nodes/node_geo_switch.cc b/source/blender/nodes/geometry/nodes/node_geo_switch.cc index 7e07a552650..8d6f53ae375 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_switch.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_switch.cc @@ -95,7 +95,7 @@ static void geo_node_switch_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_switch_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_switch_update(bNodeTree *ntree, bNode *node) { NodeSwitch *node_storage = (NodeSwitch *)node->storage; int index = 0; @@ -110,20 +110,20 @@ static void geo_node_switch_update(bNodeTree *UNUSED(ntree), bNode *node) SOCK_RGBA, SOCK_STRING); - nodeSetSocketAvailability(field_switch, fields_type); - nodeSetSocketAvailability(non_field_switch, !fields_type); + nodeSetSocketAvailability(ntree, field_switch, fields_type); + nodeSetSocketAvailability(ntree, non_field_switch, !fields_type); LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &node->inputs, index) { if (index <= 1) { continue; } - nodeSetSocketAvailability(socket, - socket->type == (eNodeSocketDatatype)node_storage->input_type); + nodeSetSocketAvailability( + ntree, socket, socket->type == (eNodeSocketDatatype)node_storage->input_type); } LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) { - nodeSetSocketAvailability(socket, - socket->type == (eNodeSocketDatatype)node_storage->input_type); + nodeSetSocketAvailability( + ntree, socket, socket->type == (eNodeSocketDatatype)node_storage->input_type); } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc index a889678537f..74b4c5d30c0 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc @@ -41,8 +41,10 @@ namespace blender::nodes { static void geo_node_transfer_attribute_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Target")) - .only_realized_data() - .supported_type({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD}); + .supported_type({GEO_COMPONENT_TYPE_MESH, + GEO_COMPONENT_TYPE_POINT_CLOUD, + GEO_COMPONENT_TYPE_CURVE, + GEO_COMPONENT_TYPE_INSTANCES}); b.add_input<decl::Vector>(N_("Attribute")).hide_value().supports_field(); b.add_input<decl::Float>(N_("Attribute"), "Attribute_001").hide_value().supports_field(); @@ -85,7 +87,7 @@ static void geo_node_transfer_attribute_init(bNodeTree *UNUSED(tree), bNode *nod node->storage = data; } -static void geo_node_transfer_attribute_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_transfer_attribute_update(bNodeTree *ntree, bNode *node) { const NodeGeometryTransferAttribute &data = *(const NodeGeometryTransferAttribute *) node->storage; @@ -102,14 +104,14 @@ static void geo_node_transfer_attribute_update(bNodeTree *UNUSED(ntree), bNode * bNodeSocket *socket_positions = socket_int32->next; bNodeSocket *socket_indices = socket_positions->next; - nodeSetSocketAvailability(socket_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_color4f, data_type == CD_PROP_COLOR); - nodeSetSocketAvailability(socket_boolean, data_type == CD_PROP_BOOL); - nodeSetSocketAvailability(socket_int32, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, socket_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_color4f, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, socket_boolean, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, socket_int32, data_type == CD_PROP_INT32); - nodeSetSocketAvailability(socket_positions, mapping != GEO_NODE_ATTRIBUTE_TRANSFER_INDEX); - nodeSetSocketAvailability(socket_indices, mapping == GEO_NODE_ATTRIBUTE_TRANSFER_INDEX); + nodeSetSocketAvailability(ntree, socket_positions, mapping != GEO_NODE_ATTRIBUTE_TRANSFER_INDEX); + nodeSetSocketAvailability(ntree, socket_indices, mapping == GEO_NODE_ATTRIBUTE_TRANSFER_INDEX); bNodeSocket *out_socket_vector = (bNodeSocket *)node->outputs.first; bNodeSocket *out_socket_float = out_socket_vector->next; @@ -117,11 +119,11 @@ static void geo_node_transfer_attribute_update(bNodeTree *UNUSED(ntree), bNode * bNodeSocket *out_socket_boolean = out_socket_color4f->next; bNodeSocket *out_socket_int32 = out_socket_boolean->next; - nodeSetSocketAvailability(out_socket_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(out_socket_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(out_socket_color4f, data_type == CD_PROP_COLOR); - nodeSetSocketAvailability(out_socket_boolean, data_type == CD_PROP_BOOL); - nodeSetSocketAvailability(out_socket_int32, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, out_socket_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, out_socket_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, out_socket_color4f, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, out_socket_boolean, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, out_socket_int32, data_type == CD_PROP_INT32); } static void get_closest_in_bvhtree(BVHTreeFromMesh &tree_data, @@ -305,7 +307,7 @@ void copy_with_indices(const VArray<T> &src, template<typename T> void copy_with_indices_clamped(const VArray<T> &src, const IndexMask mask, - const Span<int> indices, + const VArray<int> &indices, const MutableSpan<T> dst) { if (src.is_empty()) { @@ -540,10 +542,10 @@ class NearestTransferFunction : public fn::MultiFunction { attribute_math::convert_to_static_type(dst.type(), [&](auto dummy) { using T = decltype(dummy); if (use_mesh_ && use_points_) { - GVArray_Typed<T> src_mesh{*mesh_data_}; - GVArray_Typed<T> src_point{*point_data_}; - copy_with_indices_and_comparison(*src_mesh, - *src_point, + VArray<T> src_mesh = mesh_data_->typed<T>(); + VArray<T> src_point = point_data_->typed<T>(); + copy_with_indices_and_comparison(src_mesh, + src_point, mesh_distances, point_distances, mask, @@ -552,12 +554,12 @@ class NearestTransferFunction : public fn::MultiFunction { dst.typed<T>()); } else if (use_points_) { - GVArray_Typed<T> src_point{*point_data_}; - copy_with_indices(*src_point, mask, point_indices, dst.typed<T>()); + VArray<T> src_point = point_data_->typed<T>(); + copy_with_indices(src_point, mask, point_indices, dst.typed<T>()); } else if (use_mesh_) { - GVArray_Typed<T> src_mesh{*mesh_data_}; - copy_with_indices(*src_mesh, mask, mesh_indices, dst.typed<T>()); + VArray<T> src_mesh = mesh_data_->typed<T>(); + copy_with_indices(src_mesh, mask, mesh_indices, dst.typed<T>()); } }); } @@ -587,20 +589,15 @@ class NearestTransferFunction : public fn::MultiFunction { } }; -static const GeometryComponent *find_best_match_component(const GeometrySet &geometry, - const GeometryComponentType type, - const AttributeDomain domain) +static const GeometryComponent *find_target_component(const GeometrySet &geometry, + const AttributeDomain domain) { - /* Prefer transferring from the same component type, if it exists. */ - if (component_is_available(geometry, type, domain)) { - return geometry.get_component_for_read(type); - } - - /* If there is no component of the same type, choose the other component based on a consistent - * order, rather than some more complicated heuristic. This is the same order visible in the - * spreadsheet and used in the ray-cast node. */ - static const Array<GeometryComponentType> supported_types = { - GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}; + /* Choose the other component based on a consistent order, rather than some more complicated + * heuristic. This is the same order visible in the spreadsheet and used in the ray-cast node. */ + static const Array<GeometryComponentType> supported_types = {GEO_COMPONENT_TYPE_MESH, + GEO_COMPONENT_TYPE_POINT_CLOUD, + GEO_COMPONENT_TYPE_CURVE, + GEO_COMPONENT_TYPE_INSTANCES}; for (const GeometryComponentType src_type : supported_types) { if (component_is_available(geometry, src_type, domain)) { return geometry.get_component_for_read(src_type); @@ -611,76 +608,70 @@ static const GeometryComponent *find_best_match_component(const GeometrySet &geo } /** - * Use a #FieldInput because it's necessary to know the field context in order to choose the - * corresponding component type from the input geometry, and only a #FieldInput receives the - * evaluation context to provide its data. - * * The index-based transfer theoretically does not need realized data when there is only one * instance geometry set in the target. A future optimization could be removing that limitation * internally. */ -class IndexTransferFieldInput : public FieldInput { +class IndexTransferFunction : public fn::MultiFunction { GeometrySet src_geometry_; GField src_field_; - Field<int> index_field_; AttributeDomain domain_; + fn::MFSignature signature_; + + std::optional<GeometryComponentFieldContext> geometry_context_; + std::unique_ptr<FieldEvaluator> evaluator_; + const GVArray *src_data_ = nullptr; + public: - IndexTransferFieldInput(GeometrySet geometry, - GField src_field, - Field<int> index_field, - const AttributeDomain domain) - : FieldInput(src_field.cpp_type(), "Attribute Transfer node"), - src_geometry_(std::move(geometry)), - src_field_(std::move(src_field)), - index_field_(std::move(index_field)), - domain_(domain) + IndexTransferFunction(GeometrySet geometry, GField src_field, const AttributeDomain domain) + : src_geometry_(std::move(geometry)), src_field_(std::move(src_field)), domain_(domain) { src_geometry_.ensure_owns_direct_data(); - category_ = Category::Generated; + + signature_ = this->create_signature(); + this->set_signature(&signature_); + + this->evaluate_field(); } - const GVArray *get_varray_for_context(const FieldContext &context, - const IndexMask mask, - ResourceScope &scope) const final + fn::MFSignature create_signature() { - const GeometryComponentFieldContext *geometry_context = - dynamic_cast<const GeometryComponentFieldContext *>(&context); - if (geometry_context == nullptr) { - return nullptr; - } - - FieldEvaluator index_evaluator{*geometry_context, &mask}; - index_evaluator.add(index_field_); - index_evaluator.evaluate(); - const VArray<int> &index_varray = index_evaluator.get_evaluated<int>(0); - /* The index virtual array is expected to be a span, since transferring the same index for - * every element is not very useful. */ - VArray_Span<int> indices{index_varray}; + fn::MFSignatureBuilder signature{"Attribute Transfer Index"}; + signature.single_input<int>("Index"); + signature.single_output("Attribute", src_field_.cpp_type()); + return signature.build(); + } - const GeometryComponent *component = find_best_match_component( - src_geometry_, geometry_context->geometry_component().type(), domain_); + void evaluate_field() + { + const GeometryComponent *component = find_target_component(src_geometry_, domain_); if (component == nullptr) { - return nullptr; + return; } + const int domain_size = component->attribute_domain_size(domain_); + geometry_context_.emplace(GeometryComponentFieldContext(*component, domain_)); + evaluator_ = std::make_unique<FieldEvaluator>(*geometry_context_, domain_size); + evaluator_->add(src_field_); + evaluator_->evaluate(); + src_data_ = &evaluator_->get_evaluated(0); + } - GeometryComponentFieldContext target_context{*component, domain_}; - /* A potential improvement is to only copy the necessary values - * based on the indices retrieved from the index input field. */ - FieldEvaluator target_evaluator{target_context, component->attribute_domain_size(domain_)}; - target_evaluator.add(src_field_); - target_evaluator.evaluate(); - const GVArray &src_data = target_evaluator.get_evaluated(0); + void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override + { + const VArray<int> &indices = params.readonly_single_input<int>(0, "Index"); + GMutableSpan dst = params.uninitialized_single_output(1, "Attribute"); - GArray dst(src_field_.cpp_type(), mask.min_array_size()); + const CPPType &type = dst.type(); + if (src_data_ == nullptr) { + type.fill_construct_indices(type.default_value(), dst.data(), mask); + return; + } - attribute_math::convert_to_static_type(src_data.type(), [&](auto dummy) { + attribute_math::convert_to_static_type(type, [&](auto dummy) { using T = decltype(dummy); - GVArray_Typed<T> src{src_data}; - copy_with_indices_clamped(*src, mask, indices, dst.as_mutable_span().typed<T>()); + copy_with_indices_clamped(src_data_->typed<T>(), mask, indices, dst.typed<T>()); }); - - return &scope.construct<fn::GVArray_For_GArray>(std::move(dst)); } }; @@ -749,10 +740,6 @@ static void geo_node_transfer_attribute_exec(GeoNodeExecParams params) }); }; - /* Since the instances are not used, there is no point in keeping - * a reference to them while the field is passed around. */ - geometry.remove(GEO_COMPONENT_TYPE_INSTANCES); - GField output_field; switch (mapping) { case GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED: { @@ -781,6 +768,8 @@ static void geo_node_transfer_attribute_exec(GeoNodeExecParams params) } case GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST: { if (geometry.has_curve() && !geometry.has_mesh() && !geometry.has_pointcloud()) { + params.error_message_add(NodeWarningType::Error, + TIP_("The target geometry must contain a mesh or a point cloud")); return return_default(); } auto fn = std::make_unique<NearestTransferFunction>( @@ -792,9 +781,11 @@ static void geo_node_transfer_attribute_exec(GeoNodeExecParams params) } case GEO_NODE_ATTRIBUTE_TRANSFER_INDEX: { Field<int> indices = params.extract_input<Field<int>>("Index"); - std::shared_ptr<FieldInput> input = std::make_shared<IndexTransferFieldInput>( - std::move(geometry), std::move(field), std::move(indices), domain); - output_field = GField(std::move(input)); + auto fn = std::make_unique<IndexTransferFunction>( + std::move(geometry), std::move(field), domain); + auto op = std::make_shared<FieldOperation>( + FieldOperation(std::move(fn), {std::move(indices)})); + output_field = GField(std::move(op)); break; } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc index fa05d858a07..1a5a60fb1b0 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc @@ -31,7 +31,7 @@ static void geo_node_translate_instances_declare(NodeDeclarationBuilder &b) static void translate_instances(GeoNodeExecParams ¶ms, InstancesComponent &instances_component) { - GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_POINT}; + GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE}; fn::FieldEvaluator selection_evaluator{field_context, instances_component.instances_amount()}; selection_evaluator.add(params.extract_input<Field<bool>>("Selection")); diff --git a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc index 194d1a751ed..a46d7529124 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc @@ -63,7 +63,7 @@ static eNodeSocketDatatype custom_data_type_to_socket_type(const CustomDataType } } -static void geo_node_viewer_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_viewer_update(bNodeTree *ntree, bNode *node) { const NodeGeometryViewer &storage = *(const NodeGeometryViewer *)node->storage; const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); @@ -73,7 +73,7 @@ static void geo_node_viewer_update(bNodeTree *UNUSED(ntree), bNode *node) if (socket->type == SOCK_GEOMETRY) { continue; } - nodeSetSocketAvailability(socket, socket->type == socket_type); + nodeSetSocketAvailability(ntree, socket, socket->type == socket_type); } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc index 416d502dc59..99eeae370fe 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc @@ -62,15 +62,17 @@ static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node) node->storage = data; } -static void geo_node_volume_to_mesh_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_volume_to_mesh_update(bNodeTree *ntree, bNode *node) { NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)node->storage; bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size"); bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount"); - nodeSetSocketAvailability(voxel_amount_socket, + nodeSetSocketAvailability(ntree, + voxel_amount_socket, data->resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT); - nodeSetSocketAvailability(voxel_size_socket, + nodeSetSocketAvailability(ntree, + voxel_size_socket, data->resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE); } diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc index 14d6c77299b..8a9386c1137 100644 --- a/source/blender/nodes/intern/derived_node_tree.cc +++ b/source/blender/nodes/intern/derived_node_tree.cc @@ -167,7 +167,11 @@ DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const BLI_assert(socket_ref_->node().is_group_node()); const DTreeContext *child_context = context_->child_context(socket_ref_->node()); - BLI_assert(child_context != nullptr); + if (child_context == nullptr) { + /* Can happen when the group node references a non-existant group (e.g. when the group is + * linked but the original file is not found). */ + return {}; + } const NodeTreeRef &child_tree = child_context->tree(); Span<const NodeRef *> group_output_nodes = child_tree.nodes_by_type("NodeGroupOutput"); diff --git a/source/blender/nodes/intern/node_common.cc b/source/blender/nodes/intern/node_common.cc index e5ec50858d9..b80cedc9352 100644 --- a/source/blender/nodes/intern/node_common.cc +++ b/source/blender/nodes/intern/node_common.cc @@ -251,26 +251,6 @@ void register_node_type_frame(void) /** \name Node Re-Route * \{ */ -/* simple, only a single input and output here */ -static void node_reroute_update_internal_links(bNodeTree *ntree, bNode *node) -{ - bNodeLink *link; - - /* Security check! */ - if (!ntree) { - return; - } - - link = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "internal node link"); - link->fromnode = node; - link->fromsock = (bNodeSocket *)node->inputs.first; - link->tonode = node; - link->tosock = (bNodeSocket *)node->outputs.first; - /* internal link is always valid */ - link->flag |= NODE_LINK_VALID; - BLI_addtail(&node->internal_links, link); -} - static void node_reroute_init(bNodeTree *ntree, bNode *node) { /* NOTE: Cannot use socket templates for this, since it would reset the socket type @@ -288,7 +268,6 @@ void register_node_type_reroute(void) node_type_base(ntype, NODE_REROUTE, "Reroute", NODE_CLASS_LAYOUT, 0); node_type_init(ntype, node_reroute_init); - node_type_internal_links(ntype, node_reroute_update_internal_links); nodeRegisterType(ntype); } diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc index 27bc206187d..f54ef25d4d6 100644 --- a/source/blender/nodes/intern/node_geometry_exec.cc +++ b/source/blender/nodes/intern/node_geometry_exec.cc @@ -113,11 +113,11 @@ const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name return nullptr; } -GVArrayPtr GeoNodeExecParams::get_input_attribute(const StringRef name, - const GeometryComponent &component, - const AttributeDomain domain, - const CustomDataType type, - const void *default_value) const +GVArray GeoNodeExecParams::get_input_attribute(const StringRef name, + const GeometryComponent &component, + const AttributeDomain domain, + const CustomDataType type, + const void *default_value) const { const bNodeSocket *found_socket = this->find_available_socket(name); BLI_assert(found_socket != nullptr); /* There should always be available socket for the name. */ @@ -129,13 +129,13 @@ GVArrayPtr GeoNodeExecParams::get_input_attribute(const StringRef name, } if (found_socket == nullptr) { - return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, default_value); + return GVArray::ForSingle(*cpp_type, domain_size, default_value); } if (found_socket->type == SOCK_STRING) { const std::string name = this->get_input<std::string>(found_socket->identifier); /* Try getting the attribute without the default value. */ - GVArrayPtr attribute = component.attribute_try_get_for_read(name, domain, type); + GVArray attribute = component.attribute_try_get_for_read(name, domain, type); if (attribute) { return attribute; } @@ -147,36 +147,36 @@ GVArrayPtr GeoNodeExecParams::get_input_attribute(const StringRef name, this->error_message_add(NodeWarningType::Error, TIP_("No attribute with name \"") + name + "\""); } - return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, default_value); + return GVArray::ForSingle(*cpp_type, domain_size, default_value); } const DataTypeConversions &conversions = get_implicit_type_conversions(); if (found_socket->type == SOCK_FLOAT) { const float value = this->get_input<float>(found_socket->identifier); BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer); conversions.convert_to_uninitialized(CPPType::get<float>(), *cpp_type, &value, buffer); - return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer); + return GVArray::ForSingle(*cpp_type, domain_size, buffer); } if (found_socket->type == SOCK_INT) { const int value = this->get_input<int>(found_socket->identifier); BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer); conversions.convert_to_uninitialized(CPPType::get<int>(), *cpp_type, &value, buffer); - return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer); + return GVArray::ForSingle(*cpp_type, domain_size, buffer); } if (found_socket->type == SOCK_VECTOR) { const float3 value = this->get_input<float3>(found_socket->identifier); BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer); conversions.convert_to_uninitialized(CPPType::get<float3>(), *cpp_type, &value, buffer); - return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer); + return GVArray::ForSingle(*cpp_type, domain_size, buffer); } if (found_socket->type == SOCK_RGBA) { const ColorGeometry4f value = this->get_input<ColorGeometry4f>(found_socket->identifier); BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer); conversions.convert_to_uninitialized( CPPType::get<ColorGeometry4f>(), *cpp_type, &value, buffer); - return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer); + return GVArray::ForSingle(*cpp_type, domain_size, buffer); } BLI_assert(false); - return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, default_value); + return GVArray::ForSingle(*cpp_type, domain_size, default_value); } CustomDataType GeoNodeExecParams::get_input_attribute_data_type( @@ -288,7 +288,7 @@ void GeoNodeExecParams::check_input_access(StringRef identifier, BLI_assert_unreachable(); } else if (requested_type != nullptr) { - const CPPType &expected_type = *found_socket->typeinfo->get_geometry_nodes_cpp_type(); + const CPPType &expected_type = *found_socket->typeinfo->geometry_nodes_cpp_type; if (*requested_type != expected_type) { std::cout << "The requested type '" << requested_type->name() << "' is incorrect. Expected '" << expected_type.name() << "'.\n"; @@ -328,7 +328,7 @@ void GeoNodeExecParams::check_output_access(StringRef identifier, const CPPType BLI_assert_unreachable(); } else { - const CPPType &expected_type = *found_socket->typeinfo->get_geometry_nodes_cpp_type(); + const CPPType &expected_type = *found_socket->typeinfo->geometry_nodes_cpp_type; if (value_type != expected_type) { std::cout << "The value type '" << value_type.name() << "' is incorrect. Expected '" << expected_type.name() << "'.\n"; diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc index dce54d58dce..200e4120346 100644 --- a/source/blender/nodes/intern/node_socket.cc +++ b/source/blender/nodes/intern/node_socket.cc @@ -697,13 +697,11 @@ static bNodeSocketType *make_socket_type_virtual() static bNodeSocketType *make_socket_type_bool() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_BOOLEAN, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<bool>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<bool>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(bool *)r_value = ((bNodeSocketValueBoolean *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<bool>>(); - }; + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<blender::fn::Field<bool>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { bool value; socket.typeinfo->get_base_cpp_value(socket, &value); @@ -715,13 +713,11 @@ static bNodeSocketType *make_socket_type_bool() static bNodeSocketType *make_socket_type_float(PropertySubType subtype) { bNodeSocketType *socktype = make_standard_socket_type(SOCK_FLOAT, subtype); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<float>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<float>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(float *)r_value = ((bNodeSocketValueFloat *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<float>>(); - }; + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<blender::fn::Field<float>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { float value; socket.typeinfo->get_base_cpp_value(socket, &value); @@ -733,13 +729,11 @@ static bNodeSocketType *make_socket_type_float(PropertySubType subtype) static bNodeSocketType *make_socket_type_int(PropertySubType subtype) { bNodeSocketType *socktype = make_standard_socket_type(SOCK_INT, subtype); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<int>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<int>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(int *)r_value = ((bNodeSocketValueInt *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<int>>(); - }; + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<blender::fn::Field<int>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { int value; socket.typeinfo->get_base_cpp_value(socket, &value); @@ -751,13 +745,12 @@ static bNodeSocketType *make_socket_type_int(PropertySubType subtype) static bNodeSocketType *make_socket_type_vector(PropertySubType subtype) { bNodeSocketType *socktype = make_standard_socket_type(SOCK_VECTOR, subtype); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<blender::float3>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<blender::float3>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(blender::float3 *)r_value = ((bNodeSocketValueVector *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<blender::float3>>(); - }; + socktype->geometry_nodes_cpp_type = + &blender::fn::CPPType::get<blender::fn::Field<blender::float3>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { blender::float3 value; socket.typeinfo->get_base_cpp_value(socket, &value); @@ -769,15 +762,12 @@ static bNodeSocketType *make_socket_type_vector(PropertySubType subtype) static bNodeSocketType *make_socket_type_rgba() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_RGBA, PROP_NONE); - socktype->get_base_cpp_type = []() { - return &blender::fn::CPPType::get<blender::ColorGeometry4f>(); - }; + socktype->base_cpp_type = &blender::fn::CPPType::get<blender::ColorGeometry4f>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(blender::ColorGeometry4f *)r_value = ((bNodeSocketValueRGBA *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<blender::ColorGeometry4f>>(); - }; + socktype->geometry_nodes_cpp_type = + &blender::fn::CPPType::get<blender::fn::Field<blender::ColorGeometry4f>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { blender::ColorGeometry4f value; socket.typeinfo->get_base_cpp_value(socket, &value); @@ -790,13 +780,12 @@ static bNodeSocketType *make_socket_type_rgba() static bNodeSocketType *make_socket_type_string() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_STRING, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<std::string>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<std::string>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { new (r_value) std::string(((bNodeSocketValueString *)socket.default_value)->value); }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<std::string>>(); - }; + socktype->geometry_nodes_cpp_type = + &blender::fn::CPPType::get<blender::fn::Field<std::string>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { std::string value; value.~basic_string(); @@ -815,11 +804,11 @@ MAKE_CPP_TYPE(Material, Material *, CPPTypeFlags::BasicType) static bNodeSocketType *make_socket_type_object() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_OBJECT, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Object *>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<Object *>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Object **)r_value = ((bNodeSocketValueObject *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } @@ -827,11 +816,11 @@ static bNodeSocketType *make_socket_type_object() static bNodeSocketType *make_socket_type_geometry() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_GEOMETRY, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<GeometrySet>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<GeometrySet>(); socktype->get_base_cpp_value = [](const bNodeSocket &UNUSED(socket), void *r_value) { new (r_value) GeometrySet(); }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } @@ -839,11 +828,11 @@ static bNodeSocketType *make_socket_type_geometry() static bNodeSocketType *make_socket_type_collection() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_COLLECTION, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Collection *>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<Collection *>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Collection **)r_value = ((bNodeSocketValueCollection *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } @@ -851,11 +840,11 @@ static bNodeSocketType *make_socket_type_collection() static bNodeSocketType *make_socket_type_texture() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_TEXTURE, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Tex *>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<Tex *>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Tex **)r_value = ((bNodeSocketValueTexture *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } @@ -863,11 +852,11 @@ static bNodeSocketType *make_socket_type_texture() static bNodeSocketType *make_socket_type_image() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_IMAGE, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Image *>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<Image *>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Image **)r_value = ((bNodeSocketValueImage *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } @@ -875,11 +864,11 @@ static bNodeSocketType *make_socket_type_image() static bNodeSocketType *make_socket_type_material() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_MATERIAL, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Material *>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<Material *>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Material **)r_value = ((bNodeSocketValueMaterial *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c index ba0cfeacb83..231030030eb 100644 --- a/source/blender/nodes/intern/node_util.c +++ b/source/blender/nodes/intern/node_util.c @@ -41,6 +41,8 @@ #include "MEM_guardedalloc.h" +#include "NOD_common.h" + #include "node_util.h" /* -------------------------------------------------------------------- */ @@ -97,12 +99,13 @@ void node_sock_label_clear(bNodeSocket *sock) } } -void node_math_update(bNodeTree *UNUSED(ntree), bNode *node) +void node_math_update(bNodeTree *ntree, bNode *node) { bNodeSocket *sock1 = BLI_findlink(&node->inputs, 0); bNodeSocket *sock2 = BLI_findlink(&node->inputs, 1); bNodeSocket *sock3 = BLI_findlink(&node->inputs, 2); - nodeSetSocketAvailability(sock2, + nodeSetSocketAvailability(ntree, + sock2, !ELEM(node->custom1, NODE_MATH_SQRT, NODE_MATH_SIGN, @@ -126,7 +129,8 @@ void node_math_update(bNodeTree *UNUSED(ntree), bNode *node) NODE_MATH_COSH, NODE_MATH_SINH, NODE_MATH_TANH)); - nodeSetSocketAvailability(sock3, + nodeSetSocketAvailability(ntree, + sock3, ELEM(node->custom1, NODE_MATH_COMPARE, NODE_MATH_MULTIPLY_ADD, @@ -491,6 +495,10 @@ static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype /* select a suitable input socket for an output */ static bNodeSocket *select_internal_link_input(bNode *node, bNodeSocket *output) { + if (node->type == NODE_REROUTE) { + return node->inputs.first; + } + bNodeSocket *selected = NULL, *input; int i; int sel_priority = -1; @@ -524,7 +532,7 @@ static bNodeSocket *select_internal_link_input(bNode *node, bNodeSocket *output) return selected; } -void node_update_internal_links_default(bNodeTree *ntree, bNode *node) +void node_internal_links_create(bNodeTree *ntree, bNode *node) { bNodeLink *link; bNodeSocket *output, *input; diff --git a/source/blender/nodes/intern/node_util.h b/source/blender/nodes/intern/node_util.h index 9cbb21e02f7..c064ef4ab36 100644 --- a/source/blender/nodes/intern/node_util.h +++ b/source/blender/nodes/intern/node_util.h @@ -83,7 +83,6 @@ void node_filter_label(struct bNodeTree *ntree, struct bNode *node, char *label, /*** Link Handling */ void node_insert_link_default(struct bNodeTree *ntree, struct bNode *node, struct bNodeLink *link); -void node_update_internal_links_default(struct bNodeTree *ntree, struct bNode *node); float node_socket_get_float(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock); void node_socket_set_float(struct bNodeTree *ntree, diff --git a/source/blender/nodes/intern/type_conversions.cc b/source/blender/nodes/intern/type_conversions.cc index 1a71a3418a5..d4cd7dc6bfe 100644 --- a/source/blender/nodes/intern/type_conversions.cc +++ b/source/blender/nodes/intern/type_conversions.cc @@ -24,19 +24,16 @@ namespace blender::nodes { -using fn::GVArrayPtr; -using fn::GVMutableArray; -using fn::GVMutableArrayPtr; using fn::MFDataType; template<typename From, typename To, To (*ConversionF)(const From &)> static void add_implicit_conversion(DataTypeConversions &conversions) { - const CPPType &from_type = CPPType::get<From>(); - const CPPType &to_type = CPPType::get<To>(); - const std::string conversion_name = from_type.name() + " to " + to_type.name(); + static const CPPType &from_type = CPPType::get<From>(); + static const CPPType &to_type = CPPType::get<To>(); + static const std::string conversion_name = from_type.name() + " to " + to_type.name(); - static fn::CustomMF_SI_SO<From, To> multi_function{conversion_name, ConversionF}; + static fn::CustomMF_SI_SO<From, To> multi_function{conversion_name.c_str(), ConversionF}; static auto convert_single_to_initialized = [](const void *src, void *dst) { *(To *)dst = ConversionF(*(const From *)src); }; @@ -242,107 +239,108 @@ void DataTypeConversions::convert_to_uninitialized(const CPPType &from_type, functions->convert_single_to_uninitialized(from_value, to_value); } -class GVArray_For_ConvertedGVArray : public GVArray { +class GVArray_For_ConvertedGVArray : public fn::GVArrayImpl { private: - GVArrayPtr varray_; + fn::GVArray varray_; const CPPType &from_type_; ConversionFunctions old_to_new_conversions_; public: - GVArray_For_ConvertedGVArray(GVArrayPtr varray, + GVArray_For_ConvertedGVArray(fn::GVArray varray, const CPPType &to_type, const DataTypeConversions &conversions) - : GVArray(to_type, varray->size()), varray_(std::move(varray)), from_type_(varray_->type()) + : fn::GVArrayImpl(to_type, varray.size()), + varray_(std::move(varray)), + from_type_(varray_.type()) { old_to_new_conversions_ = *conversions.get_conversion_functions(from_type_, to_type); } private: - void get_impl(const int64_t index, void *r_value) const override + void get(const int64_t index, void *r_value) const override { BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); - varray_->get(index, buffer); + varray_.get(index, buffer); old_to_new_conversions_.convert_single_to_initialized(buffer, r_value); from_type_.destruct(buffer); } - void get_to_uninitialized_impl(const int64_t index, void *r_value) const override + void get_to_uninitialized(const int64_t index, void *r_value) const override { BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); - varray_->get(index, buffer); + varray_.get(index, buffer); old_to_new_conversions_.convert_single_to_uninitialized(buffer, r_value); from_type_.destruct(buffer); } }; -class GVMutableArray_For_ConvertedGVMutableArray : public GVMutableArray { +class GVMutableArray_For_ConvertedGVMutableArray : public fn::GVMutableArrayImpl { private: - GVMutableArrayPtr varray_; + fn::GVMutableArray varray_; const CPPType &from_type_; ConversionFunctions old_to_new_conversions_; ConversionFunctions new_to_old_conversions_; public: - GVMutableArray_For_ConvertedGVMutableArray(GVMutableArrayPtr varray, + GVMutableArray_For_ConvertedGVMutableArray(fn::GVMutableArray varray, const CPPType &to_type, const DataTypeConversions &conversions) - : GVMutableArray(to_type, varray->size()), + : fn::GVMutableArrayImpl(to_type, varray.size()), varray_(std::move(varray)), - from_type_(varray_->type()) + from_type_(varray_.type()) { old_to_new_conversions_ = *conversions.get_conversion_functions(from_type_, to_type); new_to_old_conversions_ = *conversions.get_conversion_functions(to_type, from_type_); } private: - void get_impl(const int64_t index, void *r_value) const override + void get(const int64_t index, void *r_value) const override { BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); - varray_->get(index, buffer); + varray_.get(index, buffer); old_to_new_conversions_.convert_single_to_initialized(buffer, r_value); from_type_.destruct(buffer); } - void get_to_uninitialized_impl(const int64_t index, void *r_value) const override + void get_to_uninitialized(const int64_t index, void *r_value) const override { BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); - varray_->get(index, buffer); + varray_.get(index, buffer); old_to_new_conversions_.convert_single_to_uninitialized(buffer, r_value); from_type_.destruct(buffer); } - void set_by_move_impl(const int64_t index, void *value) override + void set_by_move(const int64_t index, void *value) override { BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); new_to_old_conversions_.convert_single_to_uninitialized(value, buffer); - varray_->set_by_relocate(index, buffer); + varray_.set_by_relocate(index, buffer); } }; -fn::GVArrayPtr DataTypeConversions::try_convert(fn::GVArrayPtr varray, - const CPPType &to_type) const +fn::GVArray DataTypeConversions::try_convert(fn::GVArray varray, const CPPType &to_type) const { - const CPPType &from_type = varray->type(); + const CPPType &from_type = varray.type(); if (from_type == to_type) { return varray; } if (!this->is_convertible(from_type, to_type)) { return {}; } - return std::make_unique<GVArray_For_ConvertedGVArray>(std::move(varray), to_type, *this); + return fn::GVArray::For<GVArray_For_ConvertedGVArray>(std::move(varray), to_type, *this); } -fn::GVMutableArrayPtr DataTypeConversions::try_convert(fn::GVMutableArrayPtr varray, - const CPPType &to_type) const +fn::GVMutableArray DataTypeConversions::try_convert(fn::GVMutableArray varray, + const CPPType &to_type) const { - const CPPType &from_type = varray->type(); + const CPPType &from_type = varray.type(); if (from_type == to_type) { return varray; } if (!this->is_convertible(from_type, to_type)) { return {}; } - return std::make_unique<GVMutableArray_For_ConvertedGVMutableArray>( + return fn::GVMutableArray::For<GVMutableArray_For_ConvertedGVMutableArray>( std::move(varray), to_type, *this); } diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.c index 97041b3fdfd..e1f6c135568 100644 --- a/source/blender/nodes/shader/node_shader_util.c +++ b/source/blender/nodes/shader/node_shader_util.c @@ -54,7 +54,6 @@ void sh_node_type_base( ntype->poll = sh_node_poll_default; ntype->insert_link = node_insert_link_default; - ntype->update_internal_links = node_update_internal_links_default; } void sh_fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag) diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c index e29b2ee1c5c..d2b40a7ec39 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c @@ -59,59 +59,34 @@ static void node_shader_init_hair_principled(bNodeTree *UNUSED(ntree), bNode *no } /* Triggers (in)visibility of some sockets when changing Parametrization. */ -static void node_shader_update_hair_principled(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_hair_principled(bNodeTree *ntree, bNode *node) { bNodeSocket *sock; int parametrization = node->custom1; for (sock = node->inputs.first; sock; sock = sock->next) { if (STREQ(sock->name, "Color")) { - if (parametrization == SHD_PRINCIPLED_HAIR_REFLECTANCE) { - sock->flag &= ~SOCK_UNAVAIL; - } - else { - sock->flag |= SOCK_UNAVAIL; - } + nodeSetSocketAvailability(ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_REFLECTANCE); } else if (STREQ(sock->name, "Melanin")) { - if (parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION) { - sock->flag &= ~SOCK_UNAVAIL; - } - else { - sock->flag |= SOCK_UNAVAIL; - } + nodeSetSocketAvailability( + ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION); } else if (STREQ(sock->name, "Melanin Redness")) { - if (parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION) { - sock->flag &= ~SOCK_UNAVAIL; - } - else { - sock->flag |= SOCK_UNAVAIL; - } + nodeSetSocketAvailability( + ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION); } else if (STREQ(sock->name, "Tint")) { - if (parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION) { - sock->flag &= ~SOCK_UNAVAIL; - } - else { - sock->flag |= SOCK_UNAVAIL; - } + nodeSetSocketAvailability( + ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION); } else if (STREQ(sock->name, "Absorption Coefficient")) { - if (parametrization == SHD_PRINCIPLED_HAIR_DIRECT_ABSORPTION) { - sock->flag &= ~SOCK_UNAVAIL; - } - else { - sock->flag |= SOCK_UNAVAIL; - } + nodeSetSocketAvailability( + ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_DIRECT_ABSORPTION); } else if (STREQ(sock->name, "Random Color")) { - if (parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION) { - sock->flag &= ~SOCK_UNAVAIL; - } - else { - sock->flag |= SOCK_UNAVAIL; - } + nodeSetSocketAvailability( + ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION); } } } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c index cb4f0594310..89b7164693f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c @@ -167,7 +167,7 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, sss_scale); } -static void node_shader_update_principled(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_principled(bNodeTree *ntree, bNode *node) { bNodeSocket *sock; int distribution = node->custom1; @@ -175,21 +175,11 @@ static void node_shader_update_principled(bNodeTree *UNUSED(ntree), bNode *node) for (sock = node->inputs.first; sock; sock = sock->next) { if (STREQ(sock->name, "Transmission Roughness")) { - if (distribution == SHD_GLOSSY_GGX) { - sock->flag &= ~SOCK_UNAVAIL; - } - else { - sock->flag |= SOCK_UNAVAIL; - } + nodeSetSocketAvailability(ntree, sock, distribution == SHD_GLOSSY_GGX); } if (STR_ELEM(sock->name, "Subsurface IOR", "Subsurface Anisotropy")) { - if (sss_method == SHD_SUBSURFACE_BURLEY) { - sock->flag |= SOCK_UNAVAIL; - } - else { - sock->flag &= ~SOCK_UNAVAIL; - } + nodeSetSocketAvailability(ntree, sock, sss_method == SHD_SUBSURFACE_BURLEY); } } } diff --git a/source/blender/nodes/shader/nodes/node_shader_common.c b/source/blender/nodes/shader/nodes/node_shader_common.c index 4df5add7151..a1dac05434e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_common.c +++ b/source/blender/nodes/shader/nodes/node_shader_common.c @@ -237,7 +237,6 @@ void register_node_type_sh_group(void) ntype.poll = sh_node_poll_default; ntype.poll_instance = node_group_poll_instance; ntype.insert_link = node_insert_link_default; - ntype.update_internal_links = node_update_internal_links_default; ntype.rna_ext.srna = RNA_struct_find("ShaderNodeGroup"); BLI_assert(ntype.rna_ext.srna != NULL); RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype); @@ -261,9 +260,6 @@ void register_node_type_sh_custom_group(bNodeType *ntype) if (ntype->insert_link == NULL) { ntype->insert_link = node_insert_link_default; } - if (ntype->update_internal_links == NULL) { - ntype->update_internal_links = node_update_internal_links_default; - } node_type_exec(ntype, group_initexec, group_freeexec, group_execute); node_type_gpu(ntype, gpu_group_execute); diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.cc b/source/blender/nodes/shader/nodes/node_shader_map_range.cc index c866a154e8c..e55963eb500 100644 --- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc +++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc @@ -41,10 +41,10 @@ static void sh_node_map_range_declare(NodeDeclarationBuilder &b) } // namespace blender::nodes -static void node_shader_update_map_range(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_map_range(bNodeTree *ntree, bNode *node) { bNodeSocket *sockSteps = nodeFindSocket(node, SOCK_IN, "Steps"); - nodeSetSocketAvailability(sockSteps, node->custom2 == NODE_MAP_RANGE_STEPPED); + nodeSetSocketAvailability(ntree, sockSteps, node->custom2 == NODE_MAP_RANGE_STEPPED); } static void node_shader_init_map_range(bNodeTree *UNUSED(ntree), bNode *node) diff --git a/source/blender/nodes/shader/nodes/node_shader_mapping.c b/source/blender/nodes/shader/nodes/node_shader_mapping.c index 774e7fed029..cabfecdb6ee 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mapping.c +++ b/source/blender/nodes/shader/nodes/node_shader_mapping.c @@ -57,11 +57,11 @@ static int gpu_shader_mapping(GPUMaterial *mat, return 0; } -static void node_shader_update_mapping(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_mapping(bNodeTree *ntree, bNode *node) { bNodeSocket *sock = nodeFindSocket(node, SOCK_IN, "Location"); nodeSetSocketAvailability( - sock, ELEM(node->custom1, NODE_MAPPING_TYPE_POINT, NODE_MAPPING_TYPE_TEXTURE)); + ntree, sock, ELEM(node->custom1, NODE_MAPPING_TYPE_POINT, NODE_MAPPING_TYPE_TEXTURE)); } void register_node_type_sh_mapping(void) diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc index 284a5f1189f..1e94148c5c7 100644 --- a/source/blender/nodes/shader/nodes/node_shader_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_math.cc @@ -88,7 +88,8 @@ static const blender::fn::MultiFunction *get_base_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl_to_fl( mode, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SO<float, float> fn{info.title_case_name, function}; + static blender::fn::CustomMF_SI_SO<float, float> fn{info.title_case_name.c_str(), + function}; base_fn = &fn; }); if (base_fn != nullptr) { @@ -97,7 +98,7 @@ static const blender::fn::MultiFunction *get_base_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl_fl_to_fl( mode, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SI_SO<float, float, float> fn{info.title_case_name, + static blender::fn::CustomMF_SI_SI_SO<float, float, float> fn{info.title_case_name.c_str(), function}; base_fn = &fn; }); @@ -108,7 +109,7 @@ static const blender::fn::MultiFunction *get_base_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl_fl_fl_to_fl( mode, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { static blender::fn::CustomMF_SI_SI_SI_SO<float, float, float, float> fn{ - info.title_case_name, function}; + info.title_case_name.c_str(), function}; base_fn = &fn; }); if (base_fn != nullptr) { diff --git a/source/blender/nodes/shader/nodes/node_shader_output_aov.c b/source/blender/nodes/shader/nodes/node_shader_output_aov.c index 7e7e1b703f1..32765b459ca 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_aov.c +++ b/source/blender/nodes/shader/nodes/node_shader_output_aov.c @@ -64,8 +64,7 @@ void register_node_type_sh_output_aov(void) &ntype, "NodeShaderOutputAOV", node_free_standard_storage, node_copy_standard_storage); node_type_gpu(&ntype, node_shader_gpu_output_aov); - /* Do not allow muting output node. */ - node_type_internal_links(&ntype, NULL); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_output_light.c b/source/blender/nodes/shader/nodes/node_shader_output_light.c index 722202bafdc..6c4837f3c6f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_light.c +++ b/source/blender/nodes/shader/nodes/node_shader_output_light.c @@ -36,8 +36,7 @@ void register_node_type_sh_output_light(void) node_type_init(&ntype, NULL); node_type_storage(&ntype, "", NULL, NULL); - /* Do not allow muting output node. */ - node_type_internal_links(&ntype, NULL); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c b/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c index 5b4ebf21f5f..07e253383e2 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c +++ b/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c @@ -38,8 +38,7 @@ void register_node_type_sh_output_linestyle(void) node_type_socket_templates(&ntype, sh_node_output_linestyle_in, NULL); node_type_init(&ntype, NULL); - /* Do not allow muting output node. */ - node_type_internal_links(&ntype, NULL); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_output_material.c b/source/blender/nodes/shader/nodes/node_shader_output_material.c index fb0b6e7b263..41932cca6a3 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_material.c +++ b/source/blender/nodes/shader/nodes/node_shader_output_material.c @@ -84,8 +84,7 @@ void register_node_type_sh_output_material(void) node_type_storage(&ntype, "", NULL, NULL); node_type_gpu(&ntype, node_shader_gpu_output_material); - /* Do not allow muting output node. */ - node_type_internal_links(&ntype, NULL); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_output_world.c b/source/blender/nodes/shader/nodes/node_shader_output_world.c index 59c77e0b25c..09eca7f712e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_world.c +++ b/source/blender/nodes/shader/nodes/node_shader_output_world.c @@ -52,8 +52,7 @@ void register_node_type_sh_output_world(void) node_type_storage(&ntype, "", NULL, NULL); node_type_gpu(&ntype, node_shader_gpu_output_world); - /* Do not allow muting output node. */ - node_type_internal_links(&ntype, NULL); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc index 81f9cd735eb..e426d9cc49c 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc @@ -104,7 +104,7 @@ static int node_shader_gpu_tex_musgrave(GPUMaterial *mat, return GPU_stack_link(mat, node, name, in, out); } -static void node_shader_update_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_tex_musgrave(bNodeTree *ntree, bNode *node) { NodeTexMusgrave *tex = (NodeTexMusgrave *)node->storage; @@ -113,12 +113,14 @@ static void node_shader_update_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *nod bNodeSocket *inOffsetSock = nodeFindSocket(node, SOCK_IN, "Offset"); bNodeSocket *inGainSock = nodeFindSocket(node, SOCK_IN, "Gain"); - nodeSetSocketAvailability(inVectorSock, tex->dimensions != 1); - nodeSetSocketAvailability(inWSock, tex->dimensions == 1 || tex->dimensions == 4); - nodeSetSocketAvailability(inOffsetSock, + nodeSetSocketAvailability(ntree, inVectorSock, tex->dimensions != 1); + nodeSetSocketAvailability(ntree, inWSock, tex->dimensions == 1 || tex->dimensions == 4); + nodeSetSocketAvailability(ntree, + inOffsetSock, tex->musgrave_type != SHD_MUSGRAVE_MULTIFRACTAL && tex->musgrave_type != SHD_MUSGRAVE_FBM); - nodeSetSocketAvailability(inGainSock, + nodeSetSocketAvailability(ntree, + inGainSock, tex->musgrave_type == SHD_MUSGRAVE_HYBRID_MULTIFRACTAL || tex->musgrave_type == SHD_MUSGRAVE_RIDGED_MULTIFRACTAL); @@ -199,28 +201,28 @@ class MusgraveFunction : public fn::MultiFunction { void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override { - auto get_vector = [&](int param_index) -> const VArray<float3> & { + auto get_vector = [&](int param_index) -> VArray<float3> { return params.readonly_single_input<float3>(param_index, "Vector"); }; - auto get_w = [&](int param_index) -> const VArray<float> & { + auto get_w = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "W"); }; - auto get_scale = [&](int param_index) -> const VArray<float> & { + auto get_scale = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Scale"); }; - auto get_detail = [&](int param_index) -> const VArray<float> & { + auto get_detail = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Detail"); }; - auto get_dimension = [&](int param_index) -> const VArray<float> & { + auto get_dimension = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Dimension"); }; - auto get_lacunarity = [&](int param_index) -> const VArray<float> & { + auto get_lacunarity = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Lacunarity"); }; - auto get_offset = [&](int param_index) -> const VArray<float> & { + auto get_offset = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Offset"); }; - auto get_gain = [&](int param_index) -> const VArray<float> & { + auto get_gain = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Gain"); }; diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc index d28095edb96..7dd2695ecf7 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc @@ -76,14 +76,14 @@ static int node_shader_gpu_tex_noise(GPUMaterial *mat, return GPU_stack_link(mat, node, name, in, out); } -static void node_shader_update_tex_noise(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_tex_noise(bNodeTree *ntree, bNode *node) { bNodeSocket *sockVector = nodeFindSocket(node, SOCK_IN, "Vector"); bNodeSocket *sockW = nodeFindSocket(node, SOCK_IN, "W"); NodeTexNoise *tex = (NodeTexNoise *)node->storage; - nodeSetSocketAvailability(sockVector, tex->dimensions != 1); - nodeSetSocketAvailability(sockW, tex->dimensions == 1 || tex->dimensions == 4); + nodeSetSocketAvailability(ntree, sockVector, tex->dimensions != 1); + nodeSetSocketAvailability(ntree, sockW, tex->dimensions == 1 || tex->dimensions == 4); } namespace blender::nodes { diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_sky.c b/source/blender/nodes/shader/nodes/node_shader_tex_sky.c index 5dc11c4df00..5c581528c14 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_sky.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_sky.c @@ -195,12 +195,12 @@ static int node_shader_gpu_tex_sky(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_tex_sky_nishita", in, out); } -static void node_shader_update_sky(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_sky(bNodeTree *ntree, bNode *node) { bNodeSocket *sockVector = nodeFindSocket(node, SOCK_IN, "Vector"); NodeTexSky *tex = (NodeTexSky *)node->storage; - nodeSetSocketAvailability(sockVector, !(tex->sky_model == 2 && tex->sun_disc == 1)); + nodeSetSocketAvailability(ntree, sockVector, !(tex->sky_model == 2 && tex->sun_disc == 1)); } /* node type definition */ diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc index 422268b98c3..1bc3741d27c 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc @@ -123,7 +123,7 @@ static int node_shader_gpu_tex_voronoi(GPUMaterial *mat, return GPU_stack_link(mat, node, name, in, out, GPU_constant(&metric)); } -static void node_shader_update_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_tex_voronoi(bNodeTree *ntree, bNode *node) { bNodeSocket *inVectorSock = nodeFindSocket(node, SOCK_IN, "Vector"); bNodeSocket *inWSock = nodeFindSocket(node, SOCK_IN, "W"); @@ -138,27 +138,31 @@ static void node_shader_update_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage; - nodeSetSocketAvailability(inWSock, tex->dimensions == 1 || tex->dimensions == 4); - nodeSetSocketAvailability(inVectorSock, tex->dimensions != 1); + nodeSetSocketAvailability(ntree, inWSock, tex->dimensions == 1 || tex->dimensions == 4); + nodeSetSocketAvailability(ntree, inVectorSock, tex->dimensions != 1); nodeSetSocketAvailability( + ntree, inExponentSock, tex->distance == SHD_VORONOI_MINKOWSKI && tex->dimensions != 1 && !ELEM(tex->feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS)); - nodeSetSocketAvailability(inSmoothnessSock, tex->feature == SHD_VORONOI_SMOOTH_F1); + nodeSetSocketAvailability(ntree, inSmoothnessSock, tex->feature == SHD_VORONOI_SMOOTH_F1); - nodeSetSocketAvailability(outDistanceSock, tex->feature != SHD_VORONOI_N_SPHERE_RADIUS); - nodeSetSocketAvailability(outColorSock, + nodeSetSocketAvailability(ntree, outDistanceSock, tex->feature != SHD_VORONOI_N_SPHERE_RADIUS); + nodeSetSocketAvailability(ntree, + outColorSock, tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE && tex->feature != SHD_VORONOI_N_SPHERE_RADIUS); - nodeSetSocketAvailability(outPositionSock, + nodeSetSocketAvailability(ntree, + outPositionSock, tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE && tex->feature != SHD_VORONOI_N_SPHERE_RADIUS && tex->dimensions != 1); - nodeSetSocketAvailability(outWSock, + nodeSetSocketAvailability(ntree, + outWSock, tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE && tex->feature != SHD_VORONOI_N_SPHERE_RADIUS && (ELEM(tex->dimensions, 1, 4))); - nodeSetSocketAvailability(outRadiusSock, tex->feature == SHD_VORONOI_N_SPHERE_RADIUS); + nodeSetSocketAvailability(ntree, outRadiusSock, tex->feature == SHD_VORONOI_N_SPHERE_RADIUS); } namespace blender::nodes { @@ -220,22 +224,22 @@ class VoronoiMinowskiFunction : public fn::MultiFunction { void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override { - auto get_vector = [&](int param_index) -> const VArray<float3> & { + auto get_vector = [&](int param_index) -> VArray<float3> { return params.readonly_single_input<float3>(param_index, "Vector"); }; - auto get_w = [&](int param_index) -> const VArray<float> & { + auto get_w = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "W"); }; - auto get_scale = [&](int param_index) -> const VArray<float> & { + auto get_scale = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Scale"); }; - auto get_smoothness = [&](int param_index) -> const VArray<float> & { + auto get_smoothness = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Smoothness"); }; - auto get_exponent = [&](int param_index) -> const VArray<float> & { + auto get_exponent = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Exponent"); }; - auto get_randomness = [&](int param_index) -> const VArray<float> & { + auto get_randomness = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Randomness"); }; auto get_r_distance = [&](int param_index) -> MutableSpan<float> { @@ -651,19 +655,19 @@ class VoronoiMetricFunction : public fn::MultiFunction { void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override { - auto get_vector = [&](int param_index) -> const VArray<float3> & { + auto get_vector = [&](int param_index) -> VArray<float3> { return params.readonly_single_input<float3>(param_index, "Vector"); }; - auto get_w = [&](int param_index) -> const VArray<float> & { + auto get_w = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "W"); }; - auto get_scale = [&](int param_index) -> const VArray<float> & { + auto get_scale = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Scale"); }; - auto get_smoothness = [&](int param_index) -> const VArray<float> & { + auto get_smoothness = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Smoothness"); }; - auto get_randomness = [&](int param_index) -> const VArray<float> & { + auto get_randomness = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Randomness"); }; auto get_r_distance = [&](int param_index) -> MutableSpan<float> { @@ -1153,16 +1157,16 @@ class VoronoiEdgeFunction : public fn::MultiFunction { void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override { - auto get_vector = [&](int param_index) -> const VArray<float3> & { + auto get_vector = [&](int param_index) -> VArray<float3> { return params.readonly_single_input<float3>(param_index, "Vector"); }; - auto get_w = [&](int param_index) -> const VArray<float> & { + auto get_w = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "W"); }; - auto get_scale = [&](int param_index) -> const VArray<float> & { + auto get_scale = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Scale"); }; - auto get_randomness = [&](int param_index) -> const VArray<float> & { + auto get_randomness = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Randomness"); }; auto get_r_distance = [&](int param_index) -> MutableSpan<float> { diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc index 43ee9400551..7b4ff7fec5c 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc @@ -58,13 +58,13 @@ static int gpu_shader_tex_white_noise(GPUMaterial *mat, return GPU_stack_link(mat, node, name, in, out); } -static void node_shader_update_tex_white_noise(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_tex_white_noise(bNodeTree *ntree, bNode *node) { bNodeSocket *sockVector = nodeFindSocket(node, SOCK_IN, "Vector"); bNodeSocket *sockW = nodeFindSocket(node, SOCK_IN, "W"); - nodeSetSocketAvailability(sockVector, node->custom1 != 1); - nodeSetSocketAvailability(sockW, node->custom1 == 1 || node->custom1 == 4); + nodeSetSocketAvailability(ntree, sockVector, node->custom1 != 1); + nodeSetSocketAvailability(ntree, sockW, node->custom1 == 1 || node->custom1 == 4); } namespace blender::nodes { diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc index ca5aeea9a7d..9b1b2467230 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc @@ -119,7 +119,7 @@ static int gpu_shader_vector_math(GPUMaterial *mat, return 0; } -static void node_shader_update_vector_math(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_vector_math(bNodeTree *ntree, bNode *node) { bNodeSocket *sockB = (bNodeSocket *)BLI_findlink(&node->inputs, 1); bNodeSocket *sockC = (bNodeSocket *)BLI_findlink(&node->inputs, 2); @@ -128,7 +128,8 @@ static void node_shader_update_vector_math(bNodeTree *UNUSED(ntree), bNode *node bNodeSocket *sockVector = nodeFindSocket(node, SOCK_OUT, "Vector"); bNodeSocket *sockValue = nodeFindSocket(node, SOCK_OUT, "Value"); - nodeSetSocketAvailability(sockB, + nodeSetSocketAvailability(ntree, + sockB, !ELEM(node->custom1, NODE_VECTOR_MATH_SINE, NODE_VECTOR_MATH_COSINE, @@ -140,19 +141,22 @@ static void node_shader_update_vector_math(bNodeTree *UNUSED(ntree), bNode *node NODE_VECTOR_MATH_ABSOLUTE, NODE_VECTOR_MATH_FRACTION, NODE_VECTOR_MATH_NORMALIZE)); - nodeSetSocketAvailability(sockC, + nodeSetSocketAvailability(ntree, + sockC, ELEM(node->custom1, NODE_VECTOR_MATH_WRAP, NODE_VECTOR_MATH_FACEFORWARD, NODE_VECTOR_MATH_MULTIPLY_ADD)); - nodeSetSocketAvailability(sockScale, - ELEM(node->custom1, NODE_VECTOR_MATH_SCALE, NODE_VECTOR_MATH_REFRACT)); - nodeSetSocketAvailability(sockVector, + nodeSetSocketAvailability( + ntree, sockScale, ELEM(node->custom1, NODE_VECTOR_MATH_SCALE, NODE_VECTOR_MATH_REFRACT)); + nodeSetSocketAvailability(ntree, + sockVector, !ELEM(node->custom1, NODE_VECTOR_MATH_LENGTH, NODE_VECTOR_MATH_DISTANCE, NODE_VECTOR_MATH_DOT_PRODUCT)); - nodeSetSocketAvailability(sockValue, + nodeSetSocketAvailability(ntree, + sockValue, ELEM(node->custom1, NODE_VECTOR_MATH_LENGTH, NODE_VECTOR_MATH_DISTANCE, @@ -197,8 +201,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_fl3_to_fl3( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{info.title_case_name, - function}; + static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{ + info.title_case_name.c_str(), function}; multi_fn = &fn; }); if (multi_fn != nullptr) { @@ -208,7 +212,7 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_fl3_fl3_to_fl3( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{ - info.title_case_name, function}; + info.title_case_name.c_str(), function}; multi_fn = &fn; }); if (multi_fn != nullptr) { @@ -218,7 +222,7 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_fl3_fl_to_fl3( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{ - info.title_case_name, function}; + info.title_case_name.c_str(), function}; multi_fn = &fn; }); if (multi_fn != nullptr) { @@ -227,8 +231,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_fl3_to_fl( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SI_SO<float3, float3, float> fn{info.title_case_name, - function}; + static blender::fn::CustomMF_SI_SI_SO<float3, float3, float> fn{ + info.title_case_name.c_str(), function}; multi_fn = &fn; }); if (multi_fn != nullptr) { @@ -237,8 +241,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_fl_to_fl3( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SI_SO<float3, float, float3> fn{info.title_case_name, - function}; + static blender::fn::CustomMF_SI_SI_SO<float3, float, float3> fn{ + info.title_case_name.c_str(), function}; multi_fn = &fn; }); if (multi_fn != nullptr) { @@ -247,7 +251,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_to_fl3( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SO<float3, float3> fn{info.title_case_name, function}; + static blender::fn::CustomMF_SI_SO<float3, float3> fn{info.title_case_name.c_str(), + function}; multi_fn = &fn; }); if (multi_fn != nullptr) { @@ -256,7 +261,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_to_fl( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SO<float3, float> fn{info.title_case_name, function}; + static blender::fn::CustomMF_SI_SO<float3, float> fn{info.title_case_name.c_str(), + function}; multi_fn = &fn; }); if (multi_fn != nullptr) { diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc index 1ab643bc3fa..3c1f1ed8d39 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc @@ -193,14 +193,16 @@ static void sh_node_vector_rotate_build_multi_function( builder.set_matching_fn(fn); } -static void node_shader_update_vector_rotate(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_vector_rotate(bNodeTree *ntree, bNode *node) { bNodeSocket *sock_rotation = nodeFindSocket(node, SOCK_IN, "Rotation"); - nodeSetSocketAvailability(sock_rotation, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ)); + nodeSetSocketAvailability( + ntree, sock_rotation, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ)); bNodeSocket *sock_axis = nodeFindSocket(node, SOCK_IN, "Axis"); - nodeSetSocketAvailability(sock_axis, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_AXIS)); + nodeSetSocketAvailability(ntree, sock_axis, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_AXIS)); bNodeSocket *sock_angle = nodeFindSocket(node, SOCK_IN, "Angle"); - nodeSetSocketAvailability(sock_angle, !ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ)); + nodeSetSocketAvailability( + ntree, sock_angle, !ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ)); } void register_node_type_sh_vector_rotate(void) diff --git a/source/blender/nodes/texture/node_texture_util.c b/source/blender/nodes/texture/node_texture_util.c index 570b10d6e89..c968d0bae56 100644 --- a/source/blender/nodes/texture/node_texture_util.c +++ b/source/blender/nodes/texture/node_texture_util.c @@ -57,7 +57,6 @@ void tex_node_type_base( ntype->poll = tex_node_poll_default; ntype->insert_link = node_insert_link_default; - ntype->update_internal_links = node_update_internal_links_default; } static void tex_call_delegate(TexDelegate *dg, float *out, TexParams *params, short thread) diff --git a/source/blender/nodes/texture/nodes/node_texture_common.c b/source/blender/nodes/texture/nodes/node_texture_common.c index 2de64779ea6..868c97e5850 100644 --- a/source/blender/nodes/texture/nodes/node_texture_common.c +++ b/source/blender/nodes/texture/nodes/node_texture_common.c @@ -166,7 +166,6 @@ void register_node_type_tex_group(void) ntype.poll = tex_node_poll_default; ntype.poll_instance = node_group_poll_instance; ntype.insert_link = node_insert_link_default; - ntype.update_internal_links = node_update_internal_links_default; ntype.rna_ext.srna = RNA_struct_find("TextureNodeGroup"); BLI_assert(ntype.rna_ext.srna != NULL); RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype); diff --git a/source/blender/nodes/texture/nodes/node_texture_output.c b/source/blender/nodes/texture/nodes/node_texture_output.c index b24781e032b..9145df0038b 100644 --- a/source/blender/nodes/texture/nodes/node_texture_output.c +++ b/source/blender/nodes/texture/nodes/node_texture_output.c @@ -172,8 +172,7 @@ void register_node_type_tex_output(void) node_type_storage(&ntype, "TexNodeOutput", node_free_standard_storage, copy); node_type_exec(&ntype, NULL, NULL, exec); - /* Do not allow muting output. */ - node_type_internal_links(&ntype, NULL); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_viewer.c b/source/blender/nodes/texture/nodes/node_texture_viewer.c index c96ff2062cb..18b11b86d6f 100644 --- a/source/blender/nodes/texture/nodes/node_texture_viewer.c +++ b/source/blender/nodes/texture/nodes/node_texture_viewer.c @@ -60,8 +60,7 @@ void register_node_type_tex_viewer(void) node_type_socket_templates(&ntype, inputs, outputs); node_type_exec(&ntype, NULL, NULL, exec); - /* Do not allow muting viewer node. */ - node_type_internal_links(&ntype, NULL); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/python/generic/blf_py_api.c b/source/blender/python/generic/blf_py_api.c index 9e725730d40..a49c943df94 100644 --- a/source/blender/python/generic/blf_py_api.c +++ b/source/blender/python/generic/blf_py_api.c @@ -70,14 +70,15 @@ PyDoc_STRVAR(py_blf_size_doc, "font use 0.\n" " :type fontid: int\n" " :arg size: Point size of the font.\n" - " :type size: int\n" + " :type size: float\n" " :arg dpi: dots per inch value to use for drawing.\n" " :type dpi: int\n"); static PyObject *py_blf_size(PyObject *UNUSED(self), PyObject *args) { - int fontid, size, dpi; + int fontid, dpi; + float size; - if (!PyArg_ParseTuple(args, "iii:blf.size", &fontid, &size, &dpi)) { + if (!PyArg_ParseTuple(args, "ifi:blf.size", &fontid, &size, &dpi)) { return NULL; } diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index 7646109c1b0..3377b2c283e 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -22,9 +22,13 @@ * A script writer should never directly access this module. */ +/* Future-proof, See https://docs.python.org/3/c-api/arg.html#strings-and-buffers */ +#define PY_SSIZE_T_CLEAN + #include <Python.h> #include "BLI_string.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "BKE_appdir.h" @@ -149,6 +153,52 @@ static PyObject *bpy_blend_paths(PyObject *UNUSED(self), PyObject *args, PyObjec return list; } +PyDoc_STRVAR(bpy_flip_name_doc, + ".. function:: flip_name(name, strip_digits=False)\n" + "\n" + " Flip a name between left/right sides, useful for \n" + " mirroring bone names.\n" + "\n" + " :arg name: Bone name to flip.\n" + " :type name: string\n" + " :arg strip_digits: Whether to remove ``.###`` suffix.\n" + " :type strip_digits: bool\n" + " :return: The flipped name.\n" + " :rtype: string\n"); +static PyObject *bpy_flip_name(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +{ + const char *name_src = NULL; + Py_ssize_t name_src_len; + bool strip_digits = false; + + static const char *_keywords[] = {"", "strip_digits", NULL}; + static _PyArg_Parser _parser = { + "s#" /* `name` */ + "|$" /* Optional, keyword only arguments. */ + "O&" /* `strip_digits` */ + /* Name to show in the case of an error. */ + ":flip_name", + _keywords, + 0, + }; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, &name_src, &name_src_len, PyC_ParseBool, &strip_digits)) { + return NULL; + } + + /* Worst case we gain one extra byte (besides null-terminator) by changing + "Left" to "Right", because only the first appearance of "Left" gets replaced. */ + const size_t size = name_src_len + 2; + char *name_dst = PyMem_MALLOC(size); + const size_t name_dst_len = BLI_string_flip_side_name(name_dst, name_src, strip_digits, size); + + PyObject *result = PyUnicode_FromStringAndSize(name_dst, name_dst_len); + + PyMem_FREE(name_dst); + + return result; +} + // PyDoc_STRVAR(bpy_user_resource_doc[] = /* now in bpy/utils.py */ static PyObject *bpy_user_resource(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { @@ -338,6 +388,12 @@ static PyMethodDef meth_bpy_blend_paths = { METH_VARARGS | METH_KEYWORDS, bpy_blend_paths_doc, }; +static PyMethodDef meth_bpy_flip_name = { + "flip_name", + (PyCFunction)bpy_flip_name, + METH_VARARGS | METH_KEYWORDS, + bpy_flip_name_doc, +}; static PyMethodDef meth_bpy_user_resource = { "user_resource", (PyCFunction)bpy_user_resource, @@ -472,6 +528,8 @@ void BPy_init_modules(struct bContext *C) PyModule_AddObject(mod, meth_bpy_unescape_identifier.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_unescape_identifier, NULL)); + PyModule_AddObject( + mod, meth_bpy_flip_name.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_flip_name, NULL)); /* register funcs (bpy_rna.c) */ PyModule_AddObject(mod, diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c index d9a357c5e2e..059d692a9ba 100644 --- a/source/blender/python/intern/bpy_library_load.c +++ b/source/blender/python/intern/bpy_library_load.c @@ -67,7 +67,9 @@ typedef struct { char abspath[FILE_MAX]; /* absolute path */ BlendHandle *blo_handle; /* Referenced by `blo_handle`, so stored here to keep alive for long enough. */ + ReportList reports; BlendFileReadReport bf_reports; + int flag; PyObject *dict; /* Borrowed reference to the `bmain`, taken from the RNA instance of #RNA_BlendDataLibraries. @@ -256,16 +258,17 @@ static PyObject *bpy_lib_enter(BPy_Library *self) PyObject *ret; BPy_Library *self_from; PyObject *from_dict = _PyDict_NewPresized(INDEX_ID_MAX); - ReportList reports; + ReportList *reports = &self->reports; + BlendFileReadReport *bf_reports = &self->bf_reports; - BKE_reports_init(&reports, RPT_STORE); - BlendFileReadReport bf_reports = {.reports = &reports}; + BKE_reports_init(reports, RPT_STORE); + memset(bf_reports, 0, sizeof(*bf_reports)); + bf_reports->reports = reports; - self->bf_reports = bf_reports; - self->blo_handle = BLO_blendhandle_from_file(self->abspath, &self->bf_reports); + self->blo_handle = BLO_blendhandle_from_file(self->abspath, bf_reports); if (self->blo_handle == NULL) { - if (BPy_reports_to_error(&reports, PyExc_IOError, true) != -1) { + if (BPy_reports_to_error(reports, PyExc_IOError, true) != -1) { PyErr_Format(PyExc_IOError, "load: %s failed to open blend file", self->abspath); } return NULL; @@ -301,7 +304,7 @@ static PyObject *bpy_lib_enter(BPy_Library *self) PyTuple_SET_ITEMS(ret, (PyObject *)self_from, (PyObject *)self); Py_INCREF(self); - BKE_reports_clear(&reports); + BKE_reports_clear(reports); return ret; } diff --git a/source/blender/render/intern/engine.c b/source/blender/render/intern/engine.c index 5f8679b572d..cb92b15f873 100644 --- a/source/blender/render/intern/engine.c +++ b/source/blender/render/intern/engine.c @@ -206,8 +206,8 @@ static RenderResult *render_result_from_bake(RenderEngine *engine, int x, int y, BLI_addtail(&rr->layers, rl); /* Add render passes. */ - RenderPass *result_pass = render_layer_add_pass( - rr, rl, engine->bake.depth, RE_PASSNAME_COMBINED, "", "RGBA", true); + render_layer_add_pass(rr, rl, engine->bake.depth, RE_PASSNAME_COMBINED, "", "RGBA", true); + RenderPass *primitive_pass = render_layer_add_pass(rr, rl, 4, "BakePrimitive", "", "RGBA", true); RenderPass *differential_pass = render_layer_add_pass( rr, rl, 4, "BakeDifferential", "", "RGBA", true); @@ -244,15 +244,6 @@ static RenderResult *render_result_from_bake(RenderEngine *engine, int x, int y, } } - /* Initialize tile render result from full image bake result. */ - for (int ty = 0; ty < h; ty++) { - size_t offset = ty * w * engine->bake.depth; - size_t bake_offset = ((y + ty) * engine->bake.width + x) * engine->bake.depth; - size_t size = w * engine->bake.depth * sizeof(float); - - memcpy(result_pass->rect + offset, engine->bake.result + bake_offset, size); - } - return rr; } @@ -264,18 +255,31 @@ static void render_result_to_bake(RenderEngine *engine, RenderResult *rr) return; } - /* Copy from tile render result to full image bake result. */ - int x = rr->tilerect.xmin; - int y = rr->tilerect.ymin; - int w = rr->tilerect.xmax - rr->tilerect.xmin; - int h = rr->tilerect.ymax - rr->tilerect.ymin; + /* Copy from tile render result to full image bake result. Just the pixels for the + * object currently being baked, to preserve other objects when baking multiple. */ + const int x = rr->tilerect.xmin; + const int y = rr->tilerect.ymin; + const int w = rr->tilerect.xmax - rr->tilerect.xmin; + const int h = rr->tilerect.ymax - rr->tilerect.ymin; + const size_t pixel_depth = engine->bake.depth; + const size_t pixel_size = pixel_depth * sizeof(float); for (int ty = 0; ty < h; ty++) { - size_t offset = ty * w * engine->bake.depth; - size_t bake_offset = ((y + ty) * engine->bake.width + x) * engine->bake.depth; - size_t size = w * engine->bake.depth * sizeof(float); + const size_t offset = ty * w; + const size_t bake_offset = (y + ty) * engine->bake.width + x; - memcpy(engine->bake.result + bake_offset, rpass->rect + offset, size); + const float *pass_rect = rpass->rect + offset * pixel_depth; + const BakePixel *bake_pixel = engine->bake.pixels + bake_offset; + float *bake_result = engine->bake.result + bake_offset * pixel_depth; + + for (int tx = 0; tx < w; tx++) { + if (bake_pixel->object_id == engine->bake.object_id) { + memcpy(bake_result, pass_rect, pixel_size); + } + pass_rect += pixel_depth; + bake_result += pixel_depth; + bake_pixel++; + } } } diff --git a/source/blender/sequencer/SEQ_edit.h b/source/blender/sequencer/SEQ_edit.h index fbbf4bc53ea..f3a64c9cd62 100644 --- a/source/blender/sequencer/SEQ_edit.h +++ b/source/blender/sequencer/SEQ_edit.h @@ -33,10 +33,15 @@ struct Scene; struct Sequence; int SEQ_edit_sequence_swap(struct Sequence *seq_a, struct Sequence *seq_b, const char **error_str); +bool SEQ_edit_move_strip_to_seqbase(struct Scene *scene, + ListBase *seqbase, + struct Sequence *src_seq, + ListBase *dst_seqbase); bool SEQ_edit_move_strip_to_meta(struct Scene *scene, struct Sequence *src_seq, struct Sequence *dst_seqm, const char **error_str); +bool SEQ_meta_separate(struct Scene *scene, struct Sequence *src_meta, const char **error_str); void SEQ_edit_flag_for_removal(struct Scene *scene, struct ListBase *seqbase, struct Sequence *seq); diff --git a/source/blender/sequencer/SEQ_relations.h b/source/blender/sequencer/SEQ_relations.h index 54e53193b48..3b9d430a3c9 100644 --- a/source/blender/sequencer/SEQ_relations.h +++ b/source/blender/sequencer/SEQ_relations.h @@ -35,10 +35,6 @@ struct Scene; struct Sequence; void SEQ_relations_sequence_free_anim(struct Sequence *seq); -void SEQ_relations_update_changed_seq_and_deps(struct Scene *scene, - struct Sequence *changed_seq, - int len_change, - int ibuf_change); bool SEQ_relations_check_scene_recursion(struct Scene *scene, struct ReportList *reports); bool SEQ_relations_render_loop_check(struct Sequence *seq_main, struct Sequence *seq); void SEQ_relations_free_imbuf(struct Scene *scene, struct ListBase *seqbasep, bool for_render); diff --git a/source/blender/sequencer/SEQ_time.h b/source/blender/sequencer/SEQ_time.h index df3c9a40409..a0abaf8813a 100644 --- a/source/blender/sequencer/SEQ_time.h +++ b/source/blender/sequencer/SEQ_time.h @@ -45,6 +45,7 @@ int SEQ_time_find_next_prev_edit(struct Scene *scene, const bool do_center, const bool do_unselected); void SEQ_time_update_sequence(struct Scene *scene, struct ListBase *seqbase, struct Sequence *seq); +void SEQ_time_update_recursive(struct Scene *scene, struct Sequence *changed_seq); bool SEQ_time_strip_intersects_frame(const struct Sequence *seq, const int timeline_frame); void SEQ_time_update_meta_strip_range(struct Scene *scene, struct Sequence *seq_meta); diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c index b9ee23a9186..6a6889c3679 100644 --- a/source/blender/sequencer/intern/effects.c +++ b/source/blender/sequencer/intern/effects.c @@ -2942,6 +2942,9 @@ static ImBuf *do_solid_color(const SeqRenderData *context, } } } + + out->planes = R_IMF_PLANES_RGB; + return out; } @@ -3741,7 +3744,7 @@ static void init_text_effect(Sequence *seq) data = seq->effectdata = MEM_callocN(sizeof(TextVars), "textvars"); data->text_font = NULL; data->text_blf_id = -1; - data->text_size = 60; + data->text_size = 60.0f; copy_v4_fl(data->color, 1.0f); data->shadow_color[3] = 0.7f; @@ -3842,7 +3845,7 @@ static int num_inputs_text(void) static int early_out_text(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1)) { TextVars *data = seq->effectdata; - if (data->text[0] == 0 || data->text_size < 1 || + if (data->text[0] == 0 || data->text_size < 1.0f || ((data->color[3] == 0.0f) && (data->shadow_color[3] == 0.0f || (data->flag & SEQ_TEXT_SHADOW) == 0))) { return EARLY_USE_INPUT_1; @@ -4024,6 +4027,14 @@ static int early_out_mul_input2(Sequence *UNUSED(seq), float facf0, float facf1) return EARLY_DO_EFFECT; } +static int early_out_mul_input1(Sequence *UNUSED(seq), float facf0, float facf1) +{ + if (facf0 == 0.0f && facf1 == 0.0f) { + return EARLY_USE_INPUT_2; + } + return EARLY_DO_EFFECT; +} + static void get_default_fac_noop(Sequence *UNUSED(seq), float UNUSED(timeline_frame), float *facf0, @@ -4134,6 +4145,7 @@ static struct SeqEffectHandle get_sequence_effect_impl(int seq_type) rval.multithreaded = true; rval.init = init_alpha_over_or_under; rval.execute_slice = do_alphaover_effect; + rval.early_out = early_out_mul_input1; break; case SEQ_TYPE_OVERDROP: rval.multithreaded = true; diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c index 4405253586b..6030b49537c 100644 --- a/source/blender/sequencer/intern/render.c +++ b/source/blender/sequencer/intern/render.c @@ -466,6 +466,45 @@ static void sequencer_thumbnail_transform(ImBuf *in, ImBuf *out) IMB_transform(in, out, transform_matrix, &source_crop, IMB_FILTER_NEAREST); } +/* Check whether transform introduces transparent ares in the result (happens when the transformed + * image does not fully cover the render frame). + * + * The check is done by checking whether all corners of viewport fit inside of the transformed + * image. If they do not the image will have transparent areas. */ +static bool seq_image_transform_transparency_gained(const SeqRenderData *context, Sequence *seq) +{ + Scene *scene = context->scene; + const int x = context->rectx; + const int y = context->recty; + + float seq_image_quad[4][2]; + SEQ_image_transform_final_quad_get(scene, seq, seq_image_quad); + for (int i = 0; i < 4; i++) { + add_v2_v2(seq_image_quad[i], (float[]){x / 2, y / 2}); + } + + return !isect_point_quad_v2((float[]){x, y}, + seq_image_quad[0], + seq_image_quad[1], + seq_image_quad[2], + seq_image_quad[3]) || + !isect_point_quad_v2((float[]){0, y}, + seq_image_quad[0], + seq_image_quad[1], + seq_image_quad[2], + seq_image_quad[3]) || + !isect_point_quad_v2((float[]){x, 0}, + seq_image_quad[0], + seq_image_quad[1], + seq_image_quad[2], + seq_image_quad[3]) || + !isect_point_quad_v2((float[]){0, 0}, + seq_image_quad[0], + seq_image_quad[1], + seq_image_quad[2], + seq_image_quad[3]); +} + static void sequencer_preprocess_transform_crop( ImBuf *in, ImBuf *out, const SeqRenderData *context, Sequence *seq, const bool is_proxy_image) { @@ -490,6 +529,13 @@ static void sequencer_preprocess_transform_crop( const eIMBInterpolationFilterMode filter = context->for_render ? IMB_FILTER_BILINEAR : IMB_FILTER_NEAREST; IMB_transform(in, out, transform_matrix, &source_crop, filter); + + if (!seq_image_transform_transparency_gained(context, seq)) { + out->planes = in->planes; + } + else { + out->planes = R_IMF_PLANES_RGBA; + } } static void multibuf(ImBuf *ibuf, const float fmul) @@ -525,6 +571,10 @@ static void multibuf(ImBuf *ibuf, const float fmul) rt_float += 4; } } + + if (ELEM(ibuf->planes, R_IMF_PLANES_BW, R_IMF_PLANES_RGB) && fmul < 1.0f) { + ibuf->planes = R_IMF_PLANES_RGBA; + } } static ImBuf *input_preprocess(const SeqRenderData *context, @@ -1181,7 +1231,8 @@ static ImBuf *seq_render_movieclip_strip(const SeqRenderData *context, /* Try to get a proxy image. */ ibuf = seq_get_movieclip_ibuf(seq, user); - if (ibuf != NULL && psize != IMB_PROXY_NONE) { + /* If clip doesn't use proxies, it will fallback to full size render of original file. */ + if (ibuf != NULL && psize != IMB_PROXY_NONE && BKE_movieclip_proxy_enabled(seq->clip)) { *r_is_proxy_image = true; } @@ -1803,6 +1854,20 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, early_out = seq_get_early_out_for_blend_mode(seq); + /* Early out for alpha over. It requires image to be rendered, so it can't use + * `seq_get_early_out_for_blend_mode`. */ + if (out == NULL && seq->blend_mode == SEQ_TYPE_ALPHAOVER && seq->blend_opacity == 100.0f) { + ImBuf *test = seq_render_strip(context, state, seq, timeline_frame); + if (ELEM(test->planes, R_IMF_PLANES_BW, R_IMF_PLANES_RGB)) { + early_out = EARLY_USE_INPUT_2; + } + else { + early_out = EARLY_DO_EFFECT; + } + /* Free the image. It is stored in cache, so this doesn't affect performance. */ + IMB_freeImBuf(test); + } + switch (early_out) { case EARLY_NO_INPUT: case EARLY_USE_INPUT_2: @@ -1827,6 +1892,7 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, } break; } + if (out) { break; } @@ -2046,7 +2112,7 @@ int SEQ_render_thumbnails_guaranteed_set_frame_step_get(const Sequence *seq) /* Arbitrary, but due to performance reasons should be as low as possible. */ const int thumbnails_base_set_count = min_ii(content_len / 100, 30); if (thumbnails_base_set_count <= 0) { - return 0; + return content_len; } return content_len / thumbnails_base_set_count; } diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c index 6f635b5db5f..382fdd4953f 100644 --- a/source/blender/sequencer/intern/strip_add.c +++ b/source/blender/sequencer/intern/strip_add.c @@ -159,7 +159,7 @@ Sequence *SEQ_add_scene_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDat { Sequence *seq = SEQ_sequence_alloc( seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_SCENE); - seq->blend_mode = SEQ_TYPE_CROSS; + seq->blend_mode = SEQ_TYPE_ALPHAOVER; seq->scene = load_data->scene; seq->len = load_data->scene->r.efra - load_data->scene->r.sfra + 1; id_us_ensure_real((ID *)load_data->scene); @@ -180,7 +180,7 @@ Sequence *SEQ_add_movieclip_strip(Scene *scene, ListBase *seqbase, struct SeqLoa { Sequence *seq = SEQ_sequence_alloc( seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_MOVIECLIP); - seq->blend_mode = SEQ_TYPE_CROSS; + seq->blend_mode = SEQ_TYPE_ALPHAOVER; seq->clip = load_data->clip; seq->len = BKE_movieclip_get_duration(load_data->clip); id_us_ensure_real((ID *)load_data->clip); @@ -201,7 +201,7 @@ Sequence *SEQ_add_mask_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData { Sequence *seq = SEQ_sequence_alloc( seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_MASK); - seq->blend_mode = SEQ_TYPE_CROSS; + seq->blend_mode = SEQ_TYPE_ALPHAOVER; seq->mask = load_data->mask; seq->len = BKE_mask_get_duration(load_data->mask); id_us_ensure_real((ID *)load_data->mask); @@ -230,25 +230,18 @@ Sequence *SEQ_add_effect_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDa seq->seq2 = load_data->effect.seq2; seq->seq3 = load_data->effect.seq3; - if (seq->type == SEQ_TYPE_COLOR) { - seq->blend_mode = SEQ_TYPE_CROSS; - } - else if (seq->type == SEQ_TYPE_ADJUSTMENT) { - seq->blend_mode = SEQ_TYPE_CROSS; + if (SEQ_effect_get_num_inputs(seq->type) == 1) { + seq->blend_mode = seq->seq1->blend_mode; } - else if (seq->type == SEQ_TYPE_TEXT) { + else { seq->blend_mode = SEQ_TYPE_ALPHAOVER; } - else if (SEQ_effect_get_num_inputs(seq->type) == 1) { - seq->blend_mode = seq->seq1->blend_mode; - } if (!load_data->effect.seq1) { seq->len = 1; /* Effect is generator, set non zero length. */ SEQ_transform_set_right_handle_frame(seq, load_data->effect.end_frame); } - SEQ_relations_update_changed_seq_and_deps(scene, seq, 1, 1); /* Runs SEQ_time_update_sequence. */ seq_add_set_name(scene, seq, load_data); seq_add_generic_update(scene, seqbase, seq); @@ -327,7 +320,7 @@ Sequence *SEQ_add_image_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL { Sequence *seq = SEQ_sequence_alloc( seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_IMAGE); - seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */ + seq->blend_mode = SEQ_TYPE_ALPHAOVER; /* so alpha adjustment fade to the strip below */ seq->len = load_data->image.len; Strip *strip = seq->strip; strip->stripdata = MEM_callocN(load_data->image.len * sizeof(StripElem), "stripelem"); @@ -588,7 +581,7 @@ Sequence *SEQ_add_movie_strip( } } - seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */ + seq->blend_mode = SEQ_TYPE_ALPHAOVER; /* so alpha adjustment fade to the strip below */ if (anim_arr[0] != NULL) { seq->len = IMB_anim_get_duration(anim_arr[0], IMB_TC_RECORD_RUN); @@ -798,6 +791,7 @@ void SEQ_add_reload_new_file(Main *bmain, Scene *scene, Sequence *seq, const boo ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene)); SEQ_time_update_sequence(scene, seqbase, seq); + SEQ_relations_invalidate_cache_raw(scene, seq); } void SEQ_add_movie_reload_if_needed(struct Main *bmain, diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c index 747f0eb3deb..00b3da86306 100644 --- a/source/blender/sequencer/intern/strip_edit.c +++ b/source/blender/sequencer/intern/strip_edit.c @@ -221,6 +221,40 @@ static bool seq_exists_in_seqbase(Sequence *seq, ListBase *seqbase) return false; } +/** + * Move sequence to seqbase. + * + * \param scene: Scene containing the editing + * \param dst_seqbase: seqbase where `seq` is located + * \param seq: Sequence to move + * \param dst_seqbase: Target seqbase + */ +bool SEQ_edit_move_strip_to_seqbase(Scene *scene, + ListBase *seqbase, + Sequence *seq, + ListBase *dst_seqbase) +{ + /* Move to meta. */ + BLI_remlink(seqbase, seq); + BLI_addtail(dst_seqbase, seq); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); + + /* Update meta. */ + if (SEQ_transform_test_overlap(dst_seqbase, seq)) { + SEQ_transform_seqbase_shuffle(dst_seqbase, seq, scene); + } + + return true; +} + +/** + * Move sequence to meta sequence. + * + * \param scene: Scene containing the editing + * \param src_seq: Sequence to move + * \param dst_seqm: Target Meta sequence + * \param error_str: Error message + */ bool SEQ_edit_move_strip_to_meta(Scene *scene, Sequence *src_seq, Sequence *dst_seqm, @@ -262,17 +296,7 @@ bool SEQ_edit_move_strip_to_meta(Scene *scene, Sequence *seq; SEQ_ITERATOR_FOREACH (seq, collection) { /* Move to meta. */ - BLI_remlink(seqbase, seq); - BLI_addtail(&dst_seqm->seqbase, seq); - SEQ_relations_invalidate_cache_preprocessed(scene, seq); - - /* Update meta. */ - ListBase *meta_seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, dst_seqm); - SEQ_time_update_meta_strip_range(scene, dst_seqm); - SEQ_time_update_sequence(scene, meta_seqbase, dst_seqm); - if (SEQ_transform_test_overlap(&dst_seqm->seqbase, seq)) { - SEQ_transform_seqbase_shuffle(&dst_seqm->seqbase, seq, scene); - } + SEQ_edit_move_strip_to_seqbase(scene, seqbase, seq, &dst_seqm->seqbase); } SEQ_collection_free(collection); diff --git a/source/blender/sequencer/intern/strip_relations.c b/source/blender/sequencer/intern/strip_relations.c index d17a37cb9d8..e6d9cd330b3 100644 --- a/source/blender/sequencer/intern/strip_relations.c +++ b/source/blender/sequencer/intern/strip_relations.c @@ -281,80 +281,6 @@ void SEQ_relations_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render) } } -static bool update_changed_seq_recurs( - Scene *scene, Sequence *seq, Sequence *changed_seq, int len_change, int ibuf_change) -{ - Sequence *subseq; - bool free_imbuf = false; - - /* recurse downwards to see if this seq depends on the changed seq */ - - if (seq == NULL) { - return false; - } - - if (seq == changed_seq) { - free_imbuf = true; - } - - for (subseq = seq->seqbase.first; subseq; subseq = subseq->next) { - if (update_changed_seq_recurs(scene, subseq, changed_seq, len_change, ibuf_change)) { - free_imbuf = true; - } - } - - if (seq->seq1) { - if (update_changed_seq_recurs(scene, seq->seq1, changed_seq, len_change, ibuf_change)) { - free_imbuf = true; - } - } - if (seq->seq2 && (seq->seq2 != seq->seq1)) { - if (update_changed_seq_recurs(scene, seq->seq2, changed_seq, len_change, ibuf_change)) { - free_imbuf = true; - } - } - if (seq->seq3 && (seq->seq3 != seq->seq1) && (seq->seq3 != seq->seq2)) { - if (update_changed_seq_recurs(scene, seq->seq3, changed_seq, len_change, ibuf_change)) { - free_imbuf = true; - } - } - - if (free_imbuf) { - if (ibuf_change) { - if (seq->type == SEQ_TYPE_MOVIE) { - SEQ_relations_sequence_free_anim(seq); - } - else if (seq->type == SEQ_TYPE_SPEED) { - seq_effect_speed_rebuild_map(scene, seq); - } - } - - if (len_change) { - ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene)); - SEQ_time_update_sequence(scene, seqbase, seq); - } - } - - return free_imbuf; -} - -void SEQ_relations_update_changed_seq_and_deps(Scene *scene, - Sequence *changed_seq, - int len_change, - int ibuf_change) -{ - Editing *ed = SEQ_editing_get(scene); - Sequence *seq; - - if (ed == NULL) { - return; - } - - for (seq = ed->seqbase.first; seq; seq = seq->next) { - update_changed_seq_recurs(scene, seq, changed_seq, len_change, ibuf_change); - } -} - static void sequencer_all_free_anim_ibufs(ListBase *seqbase, int timeline_frame) { for (Sequence *seq = seqbase->first; seq != NULL; seq = seq->next) { diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c index 92ac580f3b1..a8e07f37a0b 100644 --- a/source/blender/sequencer/intern/strip_time.c +++ b/source/blender/sequencer/intern/strip_time.c @@ -267,6 +267,65 @@ void SEQ_time_update_sequence(Scene *scene, ListBase *seqbase, Sequence *seq) seq_time_update_sequence_bounds(scene, seq); } +static bool update_changed_seq_recurs(Scene *scene, Sequence *seq, Sequence *changed_seq) +{ + Sequence *subseq; + bool do_update = false; + + /* recurse downwards to see if this seq depends on the changed seq */ + + if (seq == NULL) { + return false; + } + + if (seq == changed_seq) { + do_update = true; + } + + for (subseq = seq->seqbase.first; subseq; subseq = subseq->next) { + if (update_changed_seq_recurs(scene, subseq, changed_seq)) { + do_update = true; + } + } + + if (seq->seq1) { + if (update_changed_seq_recurs(scene, seq->seq1, changed_seq)) { + do_update = true; + } + } + if (seq->seq2 && (seq->seq2 != seq->seq1)) { + if (update_changed_seq_recurs(scene, seq->seq2, changed_seq)) { + do_update = true; + } + } + if (seq->seq3 && (seq->seq3 != seq->seq1) && (seq->seq3 != seq->seq2)) { + if (update_changed_seq_recurs(scene, seq->seq3, changed_seq)) { + do_update = true; + } + } + + if (do_update) { + ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene)); + SEQ_time_update_sequence(scene, seqbase, seq); + } + + return do_update; +} + +void SEQ_time_update_recursive(Scene *scene, Sequence *changed_seq) +{ + Editing *ed = SEQ_editing_get(scene); + Sequence *seq; + + if (ed == NULL) { + return; + } + + for (seq = ed->seqbase.first; seq; seq = seq->next) { + update_changed_seq_recurs(scene, seq, changed_seq); + } +} + int SEQ_time_find_next_prev_edit(Scene *scene, int timeline_frame, const short side, diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c index becf44a7a8e..63ab4a30edc 100644 --- a/source/blender/sequencer/intern/strip_transform.c +++ b/source/blender/sequencer/intern/strip_transform.c @@ -520,10 +520,11 @@ static void seq_image_transform_quad_get_ex(const Scene *scene, } /** - * Get 4 corner points of strip image, optionally without rotation component applied + * Get 4 corner points of strip image, optionally without rotation component applied. + * Corner vectors are in viewport space. * * \param scene: Scene in which strips are located - * \param seq: Sequence to calculate image transform origin + * \param seq: Sequence to calculate transformed image quad * \param apply_rotation: Apply sequence rotation transform to the quad * \param r_quad: array of 4 2D vectors */ @@ -536,10 +537,10 @@ void SEQ_image_transform_quad_get(const Scene *scene, } /** - * Get 4 corner points of strip image. + * Get 4 corner points of strip image. Corner vectors are in viewport space. * * \param scene: Scene in which strips are located - * \param seq: Sequence to calculate image transform origin + * \param seq: Sequence to calculate transformed image quad * \param r_quad: array of 4 2D vectors */ void SEQ_image_transform_final_quad_get(const Scene *scene, diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 8d25ece3753..c41c328c006 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -470,6 +470,8 @@ int WM_operator_repeat(struct bContext *C, struct wmOperator *op); int WM_operator_repeat_last(struct bContext *C, struct wmOperator *op); bool WM_operator_repeat_check(const struct bContext *C, struct wmOperator *op); bool WM_operator_is_repeat(const struct bContext *C, const struct wmOperator *op); + +bool WM_operator_name_poll(struct bContext *C, const char *opstring); int WM_operator_name_call_ptr(struct bContext *C, struct wmOperatorType *ot, wmOperatorCallContext context, diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_types.h b/source/blender/windowmanager/gizmo/WM_gizmo_types.h index ceaec94e70b..8bf82a41c91 100644 --- a/source/blender/windowmanager/gizmo/WM_gizmo_types.h +++ b/source/blender/windowmanager/gizmo/WM_gizmo_types.h @@ -29,6 +29,7 @@ #pragma once #include "BLI_compiler_attrs.h" +#include "BLI_utildefines.h" struct wmGizmo; struct wmGizmoGroup; @@ -163,6 +164,8 @@ typedef enum eWM_GizmoFlagGroupTypeFlag { WM_GIZMOGROUPTYPE_VR_REDRAWS = (1 << 10), } eWM_GizmoFlagGroupTypeFlag; +ENUM_OPERATORS(eWM_GizmoFlagGroupTypeFlag, WM_GIZMOGROUPTYPE_VR_REDRAWS); + /** * #wmGizmoGroup.init_flag */ diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c index 29ba346c2f6..bc87347b2f3 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.c +++ b/source/blender/windowmanager/intern/wm_dragdrop.c @@ -736,10 +736,12 @@ static void wm_drop_operator_draw(const char *name, int x, int y) static void wm_drop_redalert_draw(const char *redalert_str, int x, int y) { const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; - const float col_bg[4] = {0.0f, 0.0f, 0.0f, 0.2f}; - float col_fg[4]; + const bTheme *btheme = UI_GetTheme(); + const uiWidgetColors *wcol = &btheme->tui.wcol_tooltip; + float col_fg[4], col_bg[4]; UI_GetThemeColor4fv(TH_REDALERT, col_fg); + rgba_uchar_to_float(col_bg, wcol->inner); UI_fontstyle_draw_simple_backdrop(fstyle, x, y, redalert_str, col_fg, col_bg); } @@ -776,6 +778,12 @@ static void wm_drag_draw_icon(bContext *UNUSED(C), const int xy[2]) { int x, y; + + /* This could also get the preview image of an ID when dragging one. But the big preview icon may + * actually not always be wanted, for example when dragging objects in the Outliner it gets in + * the way). So make the drag user set an image buffer explicitly (e.g. through + * #UI_but_drag_attach_image()). */ + if (drag->imb) { x = xy[0] - drag->sx / 2; y = xy[1] - drag->sy / 2; diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index f51c8c48c48..474d900a53d 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -1614,6 +1614,16 @@ int WM_operator_name_call(bContext *C, return 0; } +bool WM_operator_name_poll(bContext *C, const char *opstring) +{ + wmOperatorType *ot = WM_operatortype_find(opstring, 0); + if (!ot) { + return false; + } + + return WM_operator_poll(C, ot); +} + int WM_operator_name_call_with_properties(struct bContext *C, const char *opstring, wmOperatorCallContext context, diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 0074ecc392d..a301b17227d 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -887,11 +887,11 @@ static void file_read_reports_finalize(BlendFileReadReport *bf_reports) bf_reports->count.linked_proxies); } - if (bf_reports->count.vse_strips_skipped != 0) { + if (bf_reports->count.sequence_strips_skipped != 0) { BKE_reportf(bf_reports->reports, RPT_ERROR, "%d sequence strips were not read because they were in a channel larger than %d", - bf_reports->count.vse_strips_skipped, + bf_reports->count.sequence_strips_skipped, MAXSEQ); } @@ -1558,15 +1558,16 @@ static void wm_history_file_update(void) * Screen-shot the active window. * \{ */ -static ImBuf *blend_file_thumb_from_screenshot(bContext *C, BlendThumbnail **thumb_pt) +static ImBuf *blend_file_thumb_from_screenshot(bContext *C, BlendThumbnail **r_thumb) { - if (*thumb_pt) { - /* We are given a valid thumbnail data, so just generate image from it. */ - return BKE_main_thumbnail_to_imbuf(NULL, *thumb_pt); + *r_thumb = NULL; + + wmWindow *win = CTX_wm_window(C); + if (G.background || (win == NULL)) { + return NULL; } /* The window to capture should be a main window (without parent). */ - wmWindow *win = CTX_wm_window(C); while (win && win->parent) { win = win->parent; } @@ -1595,7 +1596,7 @@ static ImBuf *blend_file_thumb_from_screenshot(bContext *C, BlendThumbnail **thu BlendThumbnail *thumb = BKE_main_thumbnail_from_imbuf(NULL, thumb_ibuf); IMB_freeImBuf(thumb_ibuf); - *thumb_pt = thumb; + *r_thumb = thumb; } /* Must be freed by caller. */ @@ -1614,8 +1615,15 @@ static ImBuf *blend_file_thumb_from_screenshot(bContext *C, BlendThumbnail **thu static ImBuf *blend_file_thumb_from_camera(const bContext *C, Scene *scene, bScreen *screen, - BlendThumbnail **thumb_pt) + BlendThumbnail **r_thumb) { + *r_thumb = NULL; + + /* Scene can be NULL if running a script at startup and calling the save operator. */ + if (G.background || scene == NULL) { + return NULL; + } + /* will be scaled down, but gives some nice oversampling */ ImBuf *ibuf; BlendThumbnail *thumb; @@ -1629,17 +1637,6 @@ static ImBuf *blend_file_thumb_from_camera(const bContext *C, ARegion *region = NULL; View3D *v3d = NULL; - /* In case we are given a valid thumbnail data, just generate image from it. */ - if (*thumb_pt) { - thumb = *thumb_pt; - return BKE_main_thumbnail_to_imbuf(NULL, thumb); - } - - /* scene can be NULL if running a script at startup and calling the save operator */ - if (G.background || scene == NULL) { - return NULL; - } - if (screen != NULL) { area = BKE_screen_find_big_area(screen, SPACE_VIEW3D, 0); if (area) { @@ -1713,13 +1710,13 @@ static ImBuf *blend_file_thumb_from_camera(const bContext *C, IMB_scaleImBuf(ibuf, PREVIEW_RENDER_LARGE_HEIGHT, PREVIEW_RENDER_LARGE_HEIGHT); } else { - /* '*thumb_pt' needs to stay NULL to prevent a bad thumbnail from being handled */ + /* '*r_thumb' needs to stay NULL to prevent a bad thumbnail from being handled. */ CLOG_WARN(&LOG, "failed to create thumbnail: %s", err_out); thumb = NULL; } /* must be freed by caller */ - *thumb_pt = thumb; + *r_thumb = thumb; return ibuf; } @@ -1752,7 +1749,7 @@ static bool wm_file_write(bContext *C, Main *bmain = CTX_data_main(C); int len; int ok = false; - BlendThumbnail *thumb, *main_thumb; + BlendThumbnail *thumb = NULL, *main_thumb = NULL; ImBuf *ibuf_thumb = NULL; len = strlen(filepath); @@ -1802,33 +1799,42 @@ static bool wm_file_write(bContext *C, /* don't forget not to return without! */ WM_cursor_wait(true); - /* blend file thumbnail */ - /* Save before exit_editmode, otherwise derivedmeshes for shared data corrupt T27765. */ - /* Main now can store a '.blend' thumbnail, useful for background mode - * or thumbnail customization. */ - main_thumb = thumb = bmain->blen_thumb; - if (BLI_thread_is_main() && U.file_preview_type != USER_FILE_PREVIEW_NONE) { - - int file_preview_type = U.file_preview_type; - - if (file_preview_type == USER_FILE_PREVIEW_AUTO) { - Scene *scene = CTX_data_scene(C); - bool do_render = (scene != NULL && scene->camera != NULL && - (BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_VIEW3D, 0) != NULL)); - file_preview_type = do_render ? USER_FILE_PREVIEW_CAMERA : USER_FILE_PREVIEW_SCREENSHOT; - } - - switch (file_preview_type) { - case USER_FILE_PREVIEW_SCREENSHOT: { - ibuf_thumb = blend_file_thumb_from_screenshot(C, &thumb); - break; + if (U.file_preview_type != USER_FILE_PREVIEW_NONE) { + /* Blend file thumbnail. + * + * - Save before exiting edit-mode, otherwise evaluated-mesh for shared data gets corrupted. + * See T27765. + * - Main can store a '.blend' thumbnail, + * useful for background-mode or thumbnail customization. + */ + main_thumb = thumb = bmain->blen_thumb; + if (thumb != NULL) { + /* In case we are given a valid thumbnail data, just generate image from it. */ + ibuf_thumb = BKE_main_thumbnail_to_imbuf(NULL, thumb); + } + else if (BLI_thread_is_main()) { + int file_preview_type = U.file_preview_type; + + if (file_preview_type == USER_FILE_PREVIEW_AUTO) { + Scene *scene = CTX_data_scene(C); + bool do_render = (scene != NULL && scene->camera != NULL && + (BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_VIEW3D, 0) != NULL)); + file_preview_type = do_render ? USER_FILE_PREVIEW_CAMERA : USER_FILE_PREVIEW_SCREENSHOT; } - case USER_FILE_PREVIEW_CAMERA: { - ibuf_thumb = blend_file_thumb_from_camera(C, CTX_data_scene(C), CTX_wm_screen(C), &thumb); - break; + + switch (file_preview_type) { + case USER_FILE_PREVIEW_SCREENSHOT: { + ibuf_thumb = blend_file_thumb_from_screenshot(C, &thumb); + break; + } + case USER_FILE_PREVIEW_CAMERA: { + ibuf_thumb = blend_file_thumb_from_camera( + C, CTX_data_scene(C), CTX_wm_screen(C), &thumb); + break; + } + default: + BLI_assert_unreachable(); } - default: - BLI_assert_unreachable(); } } diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index d373ecdac77..00ac1c2ffe6 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -52,9 +52,8 @@ #include "BLO_readfile.h" -#include "BLT_translation.h" - #include "BKE_armature.h" +#include "BKE_blendfile_link_append.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_key.h" @@ -168,841 +167,6 @@ static int wm_link_append_flag(wmOperator *op) return flag; } -typedef struct WMLinkAppendDataItem { - char *name; - BLI_bitmap - *libraries; /* All libs (from WMLinkAppendData.libraries) to try to load this ID from. */ - short idcode; - - /** Type of action to do to append this item, and other append-specific information. */ - char append_action; - char append_tag; - - ID *new_id; - Library *source_library; - void *customdata; -} WMLinkAppendDataItem; - -typedef struct WMLinkAppendData { - LinkNodePair libraries; - LinkNodePair items; - int num_libraries; - int num_items; - /** - * Combines #eFileSel_Params_Flag from DNA_space_types.h & #eBLOLibLinkFlags from BLO_readfile.h - */ - int flag; - - /** Allows to easily find an existing items from an ID pointer. Used by append code. */ - 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; - - /* Internal 'private' data */ - MemArena *memarena; -} WMLinkAppendData; - -typedef struct WMLinkAppendDataCallBack { - WMLinkAppendData *lapp_data; - WMLinkAppendDataItem *item; - ReportList *reports; - -} WMLinkAppendDataCallBack; - -enum { - WM_APPEND_ACT_UNSET = 0, - WM_APPEND_ACT_KEEP_LINKED, - WM_APPEND_ACT_REUSE_LOCAL, - WM_APPEND_ACT_MAKE_LOCAL, - WM_APPEND_ACT_COPY_LOCAL, -}; - -enum { - WM_APPEND_TAG_INDIRECT = 1 << 0, -}; - -static WMLinkAppendData *wm_link_append_data_new(const int flag) -{ - MemArena *ma = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); - WMLinkAppendData *lapp_data = BLI_memarena_calloc(ma, sizeof(*lapp_data)); - - lapp_data->flag = flag; - lapp_data->memarena = ma; - - return lapp_data; -} - -static void wm_link_append_data_free(WMLinkAppendData *lapp_data) -{ - if (lapp_data->new_id_to_item != NULL) { - BLI_ghash_free(lapp_data->new_id_to_item, NULL, NULL); - } - - BLI_assert(lapp_data->library_weak_reference_mapping == NULL); - - BLI_memarena_free(lapp_data->memarena); -} - -/* WARNING! *Never* call wm_link_append_data_library_add() after having added some items! */ - -static void wm_link_append_data_library_add(WMLinkAppendData *lapp_data, const char *libname) -{ - size_t len = strlen(libname) + 1; - char *libpath = BLI_memarena_alloc(lapp_data->memarena, len); - - BLI_strncpy(libpath, libname, len); - BLI_linklist_append_arena(&lapp_data->libraries, libpath, lapp_data->memarena); - lapp_data->num_libraries++; -} - -static WMLinkAppendDataItem *wm_link_append_data_item_add(WMLinkAppendData *lapp_data, - const char *idname, - const short idcode, - void *customdata) -{ - WMLinkAppendDataItem *item = BLI_memarena_calloc(lapp_data->memarena, sizeof(*item)); - size_t len = strlen(idname) + 1; - - item->name = BLI_memarena_alloc(lapp_data->memarena, len); - BLI_strncpy(item->name, idname, len); - item->idcode = idcode; - item->libraries = BLI_BITMAP_NEW_MEMARENA(lapp_data->memarena, lapp_data->num_libraries); - - item->new_id = NULL; - item->append_action = WM_APPEND_ACT_UNSET; - item->customdata = customdata; - - BLI_linklist_append_arena(&lapp_data->items, item, lapp_data->memarena); - lapp_data->num_items++; - - return item; -} - -/* -------------------------------------------------------------------- */ -/** \name Library appending helper functions. - * - * FIXME: Deduplicate code with similar one in readfile.c - * \{ */ - -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 *wm_append_loose_data_instantiate_process_check(WMLinkAppendDataItem *item) -{ - /* 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->append_action, WM_APPEND_ACT_COPY_LOCAL, WM_APPEND_ACT_MAKE_LOCAL)) { - return NULL; - } - - ID *id = item->new_id; - if (id == NULL) { - return NULL; - } - - if (item->append_action == WM_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 wm_append_loose_data_instantiate_ensure_active_collection( - WMLinkAppendData *lapp_data, - Main *bmain, - Scene *scene, - ViewLayer *view_layer, - Collection **r_active_collection) -{ - /* Find or add collection as needed. */ - if (*r_active_collection == NULL) { - if (lapp_data->flag & FILE_ACTIVE_COLLECTION) { - LayerCollection *lc = BKE_layer_collection_get_active(view_layer); - *r_active_collection = lc->collection; - } - else { - *r_active_collection = BKE_collection_add( - bmain, scene->master_collection, DATA_("Appended Data")); - } - } -} - -/* TODO: De-duplicate this code with the one in readfile.c, think we need some utils code for that - * in BKE. */ -static void wm_append_loose_data_instantiate(WMLinkAppendData *lapp_data, - Main *bmain, - Scene *scene, - ViewLayer *view_layer, - const View3D *v3d) -{ - if (scene == NULL) { - /* In some cases, like the asset drag&drop e.g., the caller code manages instantiation itself. - */ - return; - } - - LinkNode *itemlink; - Collection *active_collection = NULL; - const bool do_obdata = (lapp_data->flag & BLO_LIBLINK_OBDATA_INSTANCE) != 0; - - /* 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; - - /* 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) { - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = wm_append_loose_data_instantiate_process_check(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_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *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; - } - } - } - - /* First do collections, then objects, then obdata. */ - - /* NOTE: For collections we only view_layer-instantiate duplicated collections that have - * non-instantiated objects in them. */ - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = wm_append_loose_data_instantiate_process_check(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->append_tag & WM_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) { - wm_append_loose_data_instantiate_ensure_active_collection( - lapp_data, bmain, scene, view_layer, &active_collection); - - /* In case user requested instantiation of collections as empties, we do so for the one they - * explicitly selected (originally directly linked IDs). */ - if ((lapp_data->flag & BLO_LIBLINK_COLLECTION_INSTANCE) != 0 && - (item->append_tag & WM_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_data->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; - BLO_object_instantiate_object_base_instance_init( - bmain, active_collection, ob, view_layer, v3d, lapp_data->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_data->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); - } - } - } - } - } - } - - /* NOTE: For objects we only view_layer-instantiate duplicated objects that are not yet used - * anywhere. */ - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = wm_append_loose_data_instantiate_process_check(item); - if (id == NULL || GS(id->name) != ID_OB) { - continue; - } - - Object *ob = (Object *)id; - - if (object_in_any_collection(bmain, ob)) { - continue; - } - - wm_append_loose_data_instantiate_ensure_active_collection( - lapp_data, bmain, scene, view_layer, &active_collection); - - CLAMP_MIN(ob->id.us, 0); - ob->mode = OB_MODE_OBJECT; - - BLO_object_instantiate_object_base_instance_init( - bmain, active_collection, ob, view_layer, v3d, lapp_data->flag, object_set_active); - } - - if (!do_obdata) { - return; - } - - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = wm_append_loose_data_instantiate_process_check(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; - } - - wm_append_loose_data_instantiate_ensure_active_collection( - lapp_data, bmain, scene, view_layer, &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); - - BLO_object_instantiate_object_base_instance_init( - bmain, active_collection, ob, view_layer, v3d, lapp_data->flag, object_set_active); - - copy_v3_v3(ob->loc, scene->cursor.location); - - id->tag &= ~LIB_TAG_DOIT; - } - - /* Finally, add rigid body objects and constraints to current RB world(s). */ - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = wm_append_loose_data_instantiate_process_check(item); - if (id == NULL || GS(id->name) != ID_OB) { - continue; - } - BKE_rigidbody_ensure_local_object(bmain, (Object *)id); - } -} - -/** \} */ - -static int foreach_libblock_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; - } - - WMLinkAppendDataCallBack *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_append_callback, data, IDWALK_NOP); - } - return IDWALK_RET_NOP; - } - - const bool do_recursive = (data->lapp_data->flag & BLO_LIBLINK_APPEND_RECURSIVE) != 0; - if (!do_recursive && cb_data->id_owner->lib != id->lib) { - /* When `do_recursive` is false, we only make local IDs from same library(-ies) as the - * initially directly linked ones. */ - return IDWALK_RET_NOP; - } - - WMLinkAppendDataItem *item = BLI_ghash_lookup(data->lapp_data->new_id_to_item, id); - if (item == NULL) { - item = wm_link_append_data_item_add(data->lapp_data, 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->append_tag |= WM_APPEND_TAG_INDIRECT; - BLI_ghash_insert(data->lapp_data->new_id_to_item, 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; -} - -/* 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(). */ -static void wm_append_do(WMLinkAppendData *lapp_data, - ReportList *reports, - Main *bmain, - Scene *scene, - ViewLayer *view_layer, - const View3D *v3d) -{ - BLI_assert((lapp_data->flag & FILE_LINK) == 0); - - const bool set_fakeuser = (lapp_data->flag & BLO_LIBLINK_APPEND_SET_FAKEUSER) != 0; - const bool do_reuse_local_id = (lapp_data->flag & BLO_LIBLINK_APPEND_LOCAL_ID_REUSE) != 0; - - const int make_local_common_flags = LIB_ID_MAKELOCAL_FULL_LIBRARY | - ((lapp_data->flag & BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR) != - 0 ? - LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR : - 0); - - LinkNode *itemlink; - - /* Generate a mapping between newly linked IDs and their items, and tag linked IDs used as - * liboverride references as already existing. */ - lapp_data->new_id_to_item = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = item->new_id; - if (id == NULL) { - continue; - } - BLI_ghash_insert(lapp_data->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; - } - } - - lapp_data->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_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = item->new_id; - if (id == NULL) { - continue; - } - BLI_assert(item->customdata == NULL); - - /* In Append case linked IDs should never be marked as needing post-processing (instantiation - * of loose objects etc.). */ - 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_data->library_weak_reference_mapping, - id->lib->filepath, - id->name) : - NULL; - - if (item->append_action != WM_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->append_action = WM_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->append_action = WM_APPEND_ACT_REUSE_LOCAL; - item->customdata = 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->append_action = WM_APPEND_ACT_COPY_LOCAL; - } - else { - CLOG_INFO(&LOG, 3, "Appended ID '%s' will be made local...", id->name); - item->append_action = WM_APPEND_ACT_MAKE_LOCAL; - } - - /* Only check dependencies if we are not keeping linked data, nor re-using existing local data. - */ - if (!ELEM(item->append_action, WM_APPEND_ACT_KEEP_LINKED, WM_APPEND_ACT_REUSE_LOCAL)) { - WMLinkAppendDataCallBack cb_data = { - .lapp_data = lapp_data, .item = item, .reports = reports}; - BKE_library_foreach_ID_link( - bmain, id, foreach_libblock_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->append_action, WM_APPEND_ACT_KEEP_LINKED, WM_APPEND_ACT_REUSE_LOCAL)) { - BKE_main_library_weak_reference_remove_item(lapp_data->library_weak_reference_mapping, - id->lib->filepath, - id->name, - existing_local_id); - } - } - - /* Effectively perform required operation on every linked ID. */ - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *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->append_action) { - case WM_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 WM_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 WM_APPEND_ACT_KEEP_LINKED: - /* Nothing to do here. */ - break; - case WM_APPEND_ACT_REUSE_LOCAL: - /* We only need to set `newid` to ID found in previous loop, for proper remapping. */ - ID_NEW_SET(id, item->customdata); - /* This is not a 'new' local appended id, do not set `local_appended_new_id` here. */ - break; - case WM_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_data->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_data->library_weak_reference_mapping); - lapp_data->library_weak_reference_mapping = NULL; - - /* Remap IDs as needed. */ - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - - if (item->append_action == WM_APPEND_ACT_KEEP_LINKED) { - continue; - } - - ID *id = item->new_id; - if (id == NULL) { - continue; - } - if (ELEM(item->append_action, WM_APPEND_ACT_COPY_LOCAL, WM_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_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - - if (item->append_action != WM_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. */ - wm_append_loose_data_instantiate(lapp_data, bmain, scene, view_layer, v3d); - - /* 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_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - - if (item->append_action != WM_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); -} - -static void wm_link_do(WMLinkAppendData *lapp_data, - ReportList *reports, - Main *bmain, - Scene *scene, - ViewLayer *view_layer, - const View3D *v3d) -{ - Main *mainl; - BlendHandle *bh; - Library *lib; - - const int flag = lapp_data->flag; - const int id_tag_extra = 0; - - LinkNode *liblink, *itemlink; - int lib_idx, item_idx; - - BLI_assert(lapp_data->num_items && lapp_data->num_libraries); - - for (lib_idx = 0, liblink = lapp_data->libraries.list; liblink; - lib_idx++, liblink = liblink->next) { - char *libname = liblink->link; - BlendFileReadReport bf_reports = {.reports = reports}; - - if (STREQ(libname, BLO_EMBEDDED_STARTUP_BLEND)) { - bh = BLO_blendhandle_from_memory( - datatoc_startup_blend, datatoc_startup_blend_size, &bf_reports); - } - else { - bh = BLO_blendhandle_from_file(libname, &bf_reports); - } - - if (bh == 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 */ - struct LibraryLink_Params liblink_params; - BLO_library_link_params_init_with_context( - &liblink_params, bmain, flag, id_tag_extra, scene, view_layer, v3d); - /* In case of append, do not handle instantiation in linking process, but during append phase - * (see #wm_append_loose_data_instantiate ). */ - if ((flag & FILE_LINK) == 0) { - liblink_params.flag &= ~BLO_LIBLINK_NEEDS_ID_TAG_DOIT; - } - - mainl = BLO_library_link_begin(&bh, libname, &liblink_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_data->items.list; itemlink; - item_idx++, itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *new_id; - - if (!BLI_BITMAP_TEST(item->libraries, lib_idx)) { - continue; - } - - new_id = BLO_library_link_named_part(mainl, &bh, item->idcode, item->name, &liblink_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_data->num_libraries); - item->new_id = new_id; - item->source_library = new_id->lib; - } - } - - BLO_library_link_end(mainl, &bh, &liblink_params); - BLO_blendhandle_close(bh); - } -} - /** * Check if an item defined by \a name and \a group can be appended/linked. * @@ -1053,7 +217,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); PropertyRNA *prop; - WMLinkAppendData *lapp_data; + BlendfileLinkAppendContext *lapp_context; char path[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX_LIBEXTRA], relname[FILE_MAX]; char *group, *name; int totfiles = 0; @@ -1120,7 +284,14 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) /* We define our working data... * Note that here, each item 'uses' one library, and only one. */ - lapp_data = wm_link_append_data_new(flag); + LibraryLink_Params lapp_params; + BLO_library_link_params_init_with_context( + &lapp_params, bmain, flag, 0, scene, view_layer, CTX_wm_view3d(C)); + + lapp_context = BKE_blendfile_link_append_context_new(&lapp_params); + BKE_blendfile_link_append_context_embedded_blendfile_set( + lapp_context, datatoc_startup_blend, datatoc_startup_blend_size); + if (totfiles != 0) { GHash *libraries = BLI_ghash_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__); int lib_idx = 0; @@ -1138,7 +309,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) if (!BLI_ghash_haskey(libraries, libname)) { BLI_ghash_insert(libraries, BLI_strdup(libname), POINTER_FROM_INT(lib_idx)); lib_idx++; - wm_link_append_data_library_add(lapp_data, libname); + BKE_blendfile_link_append_context_library_add(lapp_context, libname, NULL); } } } @@ -1150,7 +321,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) BLI_join_dirfile(path, sizeof(path), root, relname); if (BLO_library_path_explode(path, libname, &group, &name)) { - WMLinkAppendDataItem *item; + BlendfileLinkAppendContextItem *item; if (!wm_link_append_item_poll(op->reports, path, group, name, do_append)) { continue; @@ -1158,9 +329,9 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) lib_idx = POINTER_AS_INT(BLI_ghash_lookup(libraries, libname)); - item = wm_link_append_data_item_add( - lapp_data, name, BKE_idtype_idcode_from_name(group), NULL); - BLI_BITMAP_ENABLE(item->libraries, lib_idx); + item = BKE_blendfile_link_append_context_item_add( + lapp_context, name, BKE_idtype_idcode_from_name(group), NULL); + BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, lib_idx); } } RNA_END; @@ -1168,16 +339,17 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) BLI_ghash_free(libraries, MEM_freeN, NULL); } else { - WMLinkAppendDataItem *item; + BlendfileLinkAppendContextItem *item; - wm_link_append_data_library_add(lapp_data, libname); - item = wm_link_append_data_item_add(lapp_data, name, BKE_idtype_idcode_from_name(group), NULL); - BLI_BITMAP_ENABLE(item->libraries, 0); + BKE_blendfile_link_append_context_library_add(lapp_context, libname, NULL); + item = BKE_blendfile_link_append_context_item_add( + lapp_context, name, BKE_idtype_idcode_from_name(group), NULL); + BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, 0); } - if (lapp_data->num_items == 0) { + if (BKE_blendfile_link_append_context_is_empty(lapp_context)) { /* Early out in case there is nothing to link. */ - wm_link_append_data_free(lapp_data); + BKE_blendfile_link_append_context_free(lapp_context); /* Clear pre existing tag. */ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); return OPERATOR_CANCELLED; @@ -1186,7 +358,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) /* XXX We'd need re-entrant locking on Main for this to work... */ // BKE_main_lock(bmain); - wm_link_do(lapp_data, op->reports, bmain, scene, view_layer, CTX_wm_view3d(C)); + BKE_blendfile_link(lapp_context, op->reports); // BKE_main_unlock(bmain); @@ -1196,10 +368,10 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) /* append, rather than linking */ if (do_append) { - wm_append_do(lapp_data, op->reports, bmain, scene, view_layer, CTX_wm_view3d(C)); + BKE_blendfile_append(lapp_context, op->reports); } - wm_link_append_data_free(lapp_data); + BKE_blendfile_link_append_context_free(lapp_context); /* important we unset, otherwise these object won't * link into other scenes from this blend file */ @@ -1351,23 +523,29 @@ static ID *wm_file_link_append_datablock_ex(Main *bmain, BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true); /* Define working data, with just the one item we want to link. */ - WMLinkAppendData *lapp_data = wm_link_append_data_new(flag); + LibraryLink_Params lapp_params; + BLO_library_link_params_init_with_context(&lapp_params, bmain, flag, 0, scene, view_layer, v3d); + + BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(&lapp_params); + BKE_blendfile_link_append_context_embedded_blendfile_set( + lapp_context, datatoc_startup_blend, datatoc_startup_blend_size); - wm_link_append_data_library_add(lapp_data, filepath); - WMLinkAppendDataItem *item = wm_link_append_data_item_add(lapp_data, id_name, id_code, NULL); - BLI_BITMAP_ENABLE(item->libraries, 0); + BKE_blendfile_link_append_context_library_add(lapp_context, filepath, NULL); + BlendfileLinkAppendContextItem *item = BKE_blendfile_link_append_context_item_add( + lapp_context, id_name, id_code, NULL); + BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, 0); /* Link datablock. */ - wm_link_do(lapp_data, NULL, bmain, scene, view_layer, v3d); + BKE_blendfile_link(lapp_context, NULL); if (do_append) { - wm_append_do(lapp_data, NULL, bmain, scene, view_layer, v3d); + BKE_blendfile_append(lapp_context, NULL); } /* Get linked datablock and free working data. */ - ID *id = item->new_id; + ID *id = BKE_blendfile_link_append_context_item_newid_get(lapp_context, item); - wm_link_append_data_free(lapp_data); + BKE_blendfile_link_append_context_free(lapp_context); BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); @@ -1444,291 +622,6 @@ static int wm_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *UN return OPERATOR_CANCELLED; } -static void lib_relocate_do_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); - } -} - -static void lib_relocate_do(bContext *C, - Library *library, - WMLinkAppendData *lapp_data, - ReportList *reports, - const bool do_reload) -{ - ListBase *lbarray[INDEX_ID_MAX]; - int lba_idx; - - LinkNode *itemlink; - int item_idx; - - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - - /* 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) { - WMLinkAppendDataItem *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 = wm_link_append_data_item_add(lapp_data, id->name + 2, idcode, id); - BLI_bitmap_set_all(item->libraries, true, lapp_data->num_libraries); - - CLOG_INFO(&LOG, 4, "Datablock to seek for: %s", id->name); - } - } - } - - if (lapp_data->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! */ - wm_link_do(lapp_data, reports, bmain, NULL, NULL, NULL); - - 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_data->items.list; itemlink; - item_idx++, itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *old_id = item->customdata; - - 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_data->items.list; itemlink; - item_idx++, itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *old_id = item->customdata; - ID *new_id = item->new_id; - - lib_relocate_do_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); - lib_relocate_do_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_data->items.list; itemlink; - item_idx++, itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *old_id = item->customdata; - - 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, - scene, - 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); - - BKE_main_lib_objects_recalc_all(bmain); - IMB_colormanagement_check_file_config(bmain); - - /* important we unset, otherwise these object won't - * link into other scenes from this blend file */ - BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); - - /* recreate dependency graph to include new objects */ - DEG_relations_tag_update(bmain); -} - void WM_lib_reload(Library *lib, bContext *C, ReportList *reports) { if (!BLO_has_bfile_extension(lib->filepath_abs)) { @@ -1745,14 +638,34 @@ void WM_lib_reload(Library *lib, bContext *C, ReportList *reports) return; } - WMLinkAppendData *lapp_data = wm_link_append_data_new(BLO_LIBLINK_USE_PLACEHOLDERS | - BLO_LIBLINK_FORCE_INDIRECT); + Main *bmain = CTX_data_main(C); + LibraryLink_Params lapp_params; + BLO_library_link_params_init_with_context(&lapp_params, + bmain, + BLO_LIBLINK_USE_PLACEHOLDERS | + BLO_LIBLINK_FORCE_INDIRECT, + 0, + CTX_data_scene(C), + CTX_data_view_layer(C), + NULL); - wm_link_append_data_library_add(lapp_data, lib->filepath_abs); + BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(&lapp_params); + + BKE_blendfile_link_append_context_library_add(lapp_context, lib->filepath_abs, NULL); + + BKE_blendfile_library_relocate(lapp_context, reports, lib, true); + + BKE_blendfile_link_append_context_free(lapp_context); + + BKE_main_lib_objects_recalc_all(bmain); + IMB_colormanagement_check_file_config(bmain); - lib_relocate_do(C, lib, lapp_data, reports, true); + /* Important we unset, otherwise these object won't link into other scenes from this blend file. + */ + BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); - wm_link_append_data_free(lapp_data); + /* Recreate dependency graph to include new IDs. */ + DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_WINDOW, NULL); } @@ -1768,7 +681,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) if (lib) { Main *bmain = CTX_data_main(C); PropertyRNA *prop; - WMLinkAppendData *lapp_data; + BlendfileLinkAppendContext *lapp_context; char path[FILE_MAX], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX]; short flag = 0; @@ -1813,13 +726,17 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) return OPERATOR_CANCELLED; } + LibraryLink_Params lapp_params; + BLO_library_link_params_init_with_context( + &lapp_params, bmain, flag, 0, CTX_data_scene(C), CTX_data_view_layer(C), NULL); + if (BLI_path_cmp(lib->filepath_abs, path) == 0) { CLOG_INFO(&LOG, 4, "We are supposed to reload '%s' lib (%d)", lib->filepath, lib->id.us); do_reload = true; - lapp_data = wm_link_append_data_new(flag); - wm_link_append_data_library_add(lapp_data, path); + lapp_context = BKE_blendfile_link_append_context_new(&lapp_params); + BKE_blendfile_link_append_context_library_add(lapp_context, path, NULL); } else { int totfiles = 0; @@ -1839,7 +756,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) } } - lapp_data = wm_link_append_data_new(flag); + lapp_context = BKE_blendfile_link_append_context_new(&lapp_params); if (totfiles) { RNA_BEGIN (op->ptr, itemptr, "files") { @@ -1852,27 +769,39 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) } CLOG_INFO(&LOG, 4, "\tCandidate new lib to reload datablocks from: %s", path); - wm_link_append_data_library_add(lapp_data, path); + BKE_blendfile_link_append_context_library_add(lapp_context, path, NULL); } RNA_END; } else { CLOG_INFO(&LOG, 4, "\tCandidate new lib to reload datablocks from: %s", path); - wm_link_append_data_library_add(lapp_data, path); + BKE_blendfile_link_append_context_library_add(lapp_context, path, NULL); } } if (do_reload) { - lapp_data->flag |= BLO_LIBLINK_USE_PLACEHOLDERS | BLO_LIBLINK_FORCE_INDIRECT; + BKE_blendfile_link_append_context_flag_set( + lapp_context, BLO_LIBLINK_USE_PLACEHOLDERS | BLO_LIBLINK_FORCE_INDIRECT, true); } - lib_relocate_do(C, lib, lapp_data, op->reports, do_reload); + BKE_blendfile_library_relocate(lapp_context, op->reports, lib, do_reload); - wm_link_append_data_free(lapp_data); + BKE_blendfile_link_append_context_free(lapp_context); /* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */ BLI_strncpy(G.lib, root, FILE_MAX); + BKE_main_lib_objects_recalc_all(bmain); + IMB_colormanagement_check_file_config(bmain); + + /* Important we unset, otherwise these object won't link into other scenes from this blend + * file. + */ + BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); + + /* Recreate dependency graph to include new IDs. */ + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_WINDOW, NULL); return OPERATOR_FINISHED; diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c index 8a527bead77..905f9ff1353 100644 --- a/source/blender/windowmanager/intern/wm_playanim.c +++ b/source/blender/windowmanager/intern/wm_playanim.c @@ -1570,7 +1570,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv) /* initialize the font */ BLF_init(); ps.fontid = BLF_load_mono_default(false); - BLF_size(ps.fontid, 11, 72); + BLF_size(ps.fontid, 11.0f, 72); ps.ibufx = ibuf->x; ps.ibufy = ibuf->y; diff --git a/source/blender/windowmanager/xr/intern/wm_xr_operators.c b/source/blender/windowmanager/xr/intern/wm_xr_operators.c index 112312bab7b..f3470edf2f7 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_operators.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_operators.c @@ -432,10 +432,10 @@ static bool wm_xr_navigation_grab_can_do_bimanual(const wmXrActionData *actionda const XrGrabData *data) { /* Returns true if: 1) Bimanual interaction is currently occurring (i.e. inputs on both - controllers are pressed) and 2) bimanual interaction occurred on the last update. This second - part is needed to avoid "jumpy" navigation changes when transitioning from one-handed to - two-handed interaction (see #wm_xr_grab_compute/compute_bimanual() for how navigation deltas - are calculated). */ + * controllers are pressed) and 2) bimanual interaction occurred on the last update. This second + * part is needed to avoid "jumpy" navigation changes when transitioning from one-handed to + * two-handed interaction (see #wm_xr_grab_compute/compute_bimanual() for how navigation deltas + * are calculated). */ return (actiondata->bimanual && data->bimanual_prev); } @@ -545,7 +545,7 @@ static int wm_xr_navigation_grab_modal(bContext *C, wmOperator *op, const wmEven /* Check if navigation is locked. */ if (!wm_xr_navigation_grab_is_locked(data, do_bimanual)) { /* Prevent unwanted snapping (i.e. "jumpy" navigation changes when transitioning from - two-handed to one-handed interaction) at the end of a bimanual interaction. */ + * two-handed to one-handed interaction) at the end of a bimanual interaction. */ if (!wm_xr_navigation_grab_is_bimanual_ending(actiondata, data)) { wm_xr_navigation_grab_apply(xr, actiondata, data, do_bimanual); } @@ -554,9 +554,9 @@ static int wm_xr_navigation_grab_modal(bContext *C, wmOperator *op, const wmEven wm_xr_navigation_grab_bimanual_state_update(actiondata, data); /* Note: KM_PRESS and KM_RELEASE are the only two values supported by XR events during event - dispatching (see #wm_xr_session_action_states_interpret()). For modal XR operators, modal - handling starts when an input is "pressed" (action state exceeds the action threshold) and - ends when the input is "released" (state falls below the threshold). */ + * dispatching (see #wm_xr_session_action_states_interpret()). For modal XR operators, modal + * handling starts when an input is "pressed" (action state exceeds the action threshold) and + * ends when the input is "released" (state falls below the threshold). */ switch (event->val) { case KM_PRESS: return OPERATOR_RUNNING_MODAL; diff --git a/source/creator/creator.c b/source/creator/creator.c index 4171d60b5b6..6daaea38c34 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -551,7 +551,8 @@ int main(int argc, WM_exit(C); } else { - if (!G.file_loaded) { + /* When no file is loaded, show the splash screen. */ + if (!G.relbase_valid) { WM_init_splash(C); } WM_main(C); diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index 789c4ad8f03..d365a8b05b4 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -2044,8 +2044,6 @@ static int arg_handle_load_file(int UNUSED(argc), const char **argv, void *data) } } - G.file_loaded = 1; - return 0; } diff --git a/source/tools b/source/tools -Subproject 2e8c879248822c8e500ed49d79acc605e5aa75b +Subproject b22d19e47f4d0353082f3d9f30ee8d244c5266d |